1. 缓冲流
概念: 缓冲流自带一个缓冲区,可以让传输过程更加高效和流畅,且缓冲流附带一些其他功能方法。
1.1 BufferedInputStream
概念: 缓冲字节输入流BufferedInputStream是InputStream的一个子类。
- 构造器:
BufferedInputStream(InputStream in)BufferedInputStream(InputStream in, int size)size是缓冲区默认大小,默认为8192b,即8K。
- 常用API方法:
int read():从此输入流中读取一个字节的数据,如果文件已经读完,返回-1。void mark(int readlimit):标记的位置,只取决于该方法被调用时,bis指针的位置,跟参数无关。- p1:一个以字节为单位的标记有效期。
void reset():回到上一个标记的位置,如果当前mark()过期,则报错。
mark()的有效期不仅仅取决于它的参数,还取决于BufferedInputStream()的缓存,这两个值,谁大谁生效,如mark()有效期为4个字节,BufferedInputStream()的缓存是8192个字节,所以最终只要读的字节数量没超过8192,都可以成功reset()。
源码: /javase-advanced/
- src:
c.y.io.BufferedSeriesTest.bufferedInputStream()
/**
* @author yap
*/
public class BufferedSeriesTest {
private String filePath = "D:" + File.separator + "java-io" + File.separator + "HelloWorld.java";
/**
* 对 `HelloWorld.java` 文件进行中间部分内容读取12-3456-3456
*/
@Test
public void bufferedInputStream() {
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath), 5)) {
System.out.println("pos-01:" + (char) bis.read());
System.out.println("pos-02:" + (char) bis.read());
bis.mark(4);
System.out.println("pos-03:" + (char) bis.read());
System.out.println("pos-04:" + (char) bis.read());
System.out.println("pos-05:" + (char) bis.read());
System.out.println("pos-06:" + (char) bis.read());
System.out.println("pos-06:" + (char) bis.read());
bis.reset();
System.out.println("pos-03:" + (char) bis.read());
System.out.println("pos-04:" + (char) bis.read());
System.out.println("pos-05:" + (char) bis.read());
System.out.println("pos-06:" + (char) bis.read());
} catch (IOException e) {
e.printStackTrace();
}
}
}
多个IO流嵌套的时候,程序最后只需要关闭最外层的IO流即可。
2.2 BufferedOutputStream
概念: 缓冲字节输出流BufferedOutputStream是OutputStream的一个子类。
- 构造器:
BufferedOutputStream(OutputStream out):BufferedOutputStream(OutputStream out, int size)size是缓冲区默认大小,默认为8192b,即8K。
- 常用API方法:
void write(int b):将指定的字节b写入此文件输出流。void flush():刷新此输出流并强制任何缓冲的输出字节被写出来。
源码: /javase-advanced/
- src:
c.y.io.BufferedSeriesTest.bufferedOutputStream()
/**
* @author yap
*/
public class BufferedSeriesTest {
private String filePath = "D:" + File.separator + "java-io" + File.separator + "HelloWorld.java";
/**
* 对一个文件写入10个A
*/
@Test
public void bufferedOutputStream() {
String destPath = "D:" + File.separator + "java-io" + File.separator + "io.txt";
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destPath))) {
int times = 10;
for (int i = 0; i < times; i++) {
bos.write('B');
}
System.out.println("write over...");
bos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.3 BufferedReader
概念: 缓冲字符输入流BufferedReader是Reader的一个子类。
- 构造器:
BufferedReader(Reader in)BufferedReader(Reader in, int size)size是缓冲区默认大小,默认为8192b,即8K。
- 常用API方法:
int read():从此输入流中读取一个字节的数据,如果文件已经读完,返回-1。String readLine():从此输入流中读取一行数据,如果文件已经读完,返回null。skip(),mark(),reset()都支持。
源码: /javase-advanced/
- src:
c.y.io.BufferedSeriesTest.bufferedReader()
/**
* @author yap
*/
public class BufferedSeriesTest {
private String filePath = "D:" + File.separator + "java-io" + File.separator + "HelloWorld.java";
/**
* 一行一行地读取 `HelloWorld.java` 文件,并打印在控制台上
*/
@Test
public void bufferedReader() {
try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
String str;
while ((str = br.readLine()) != null) {
System.out.println(str);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.4 BufferedWriter
概念: 缓冲字符输出流BufferedWriter是Writer的一个子类。
- 构造器:
BufferedWriter(Writer out):BufferedWriter(Writer out, int size)size是缓冲区默认大小,默认为8192b,即8K。
- 常用API方法:
void write(String b):将指定的字符串写入此文件输出流。void newLine():插入一个换行符。void flush():刷新此输出流并强制任何缓冲的输出字节被写出来。
源码: /javase-advanced/
- src:
c.y.io.BufferedSeriesTest.bufferedWriter()
/**
* @author yap
*/
public class BufferedSeriesTest {
private String filePath = "D:" + File.separator + "java-io" + File.separator + "HelloWorld.java";
/**
* 向指定文件写入100个随机数,每个随机数占据一行
*/
@Test
public void bufferedWriter() {
String filePath = "D:" + File.separator + "java-io" + File.separator + "random.txt";
try (BufferedWriter bw = new BufferedWriter(new FileWriter(filePath))) {
Random random = new Random();
for (int i = 0, j = 100; i < j; i++) {
bw.write("随机数:" + (random.nextInt(100)));
bw.newLine();
}
System.out.println("write over...");
bw.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2. 转换流
概念: 我们可以利用处理转换流将字节流转换成对应的字符流。
2.1 InputStreamReader
概念: 字节输入转换流InputStreamReader是Reader的一个子类。
- 构造器:
InputStreamReader(InputStream in)InputStreamReader(InputStream in, String charset)InputStreamReader(InputStream in, Charset cs)charset是字符编码字符串,默认UTF8,建议使用StandardCharsets.UTF_8。
- 常用API方法:
int read():从此输入流中读取一个字节的数据,如果文件已经读完,返回-1。String getEncoding():获取当前流中的字符集。
源码: /javase-advanced/
- src:
c.y.io.TransformSeriesTest.inputStreamReader()
/**
* @author yap
*/
public class TransformSeriesTest {
private static void inputStreamReader() {
// System.in is typeof InputStream
try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
String str;
while ((str = br.readLine()) != null) {
if ("exit".equals(str)) {
break;
}
System.out.println(">> " + str);
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 设计模拟Scanner读取控制台信息的方法,要求输入 `exit` 时可以退出。
* IDEA中的Junit和System.in或者Scanner有冲突,需要换成main方法测试
*/
public static void main(String[] args) {
inputStreamReader();
}
}
3.2 OutputStreamWriter
概念: 字节输出转换流OutputStreamWriter是Writer的一个子类。
- 构造器:
OutputStreamWriter(OutputStream out)OutputStreamReader(OutputStream out, String charset)OutputStreamReader(OutputStream out, Charset charset)charset是字符编码字符串,默认UTF8,建议使用StandardCharsets.UTF_8。
- 常用API方法:
void write(String str):将指定的字符串写入此文件输出流。void flush():刷新此输出流并强制任何缓冲的输出字节被写出来。
源码: /javase-advanced/
- src:
c.y.io.TransformSeriesTest.outputStreamWriter()
/**
* @author yap
*/
public class TransformSeriesTest {
/**
* 向文件中写入一个UTF8的 "你好" 和一个 GBK的 "世界"
*/
@Test
public void outputStreamWriter() {
String destPath = "D:" + File.separator + "java-io" + File.separator + "hello.txt";
OutputStreamWriter osw = null;
try {
FileOutputStream fos = new FileOutputStream(destPath);
osw = new OutputStreamWriter(fos, "UTF-8");
osw.write("你好");
System.out.println(osw.getEncoding());
osw.flush();
osw = new OutputStreamWriter(fos, "GBK");
osw.write("世界");
System.out.println(osw.getEncoding());
osw.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (osw != null) {
try {
osw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
4. 打印流
概念: 打印流是输出语句的底层结构,无需抛出IO异常,且自带flush效果。
4.1 PrintStream
概念: 打印字节流PrintStream是OutputStream的一个子类。
- 构造器:
PrintStream(OutputStream out)PrintStream(OutputStream out, boolean autoFlush)PrintStream(OutputStream out, boolean autoFlush, String charset)PrintStream(String fileName)PrintStream(String fileName, String charset)PrintStream(File file)PrintStream(File file, String charset)charset是字符编码字符串,默认UTF8。autoFlush是PrintWriter的刷新属性:- 为true时,每次写入,打印,或读到换行符等操作的时候都会flush。
- 为false时,只flush一次(默认)。
- 常用API方法
void print(String str):不换行打印,底层封装的write()。void println():换行打印,底层封装的write()。void printf():格式化打印,底层封装的write()。
- System类的一个API方法:
void setOut(PrintStream out):重新定义输出语句中的out的位置(默认指向控制台)。void setErr(PrintStream err):重新定义输出语句中的err的位置(默认指向控制台)。
源码: /javase-advanced/
- src:
c.y.io.PrintSeriesTest.printStream()
/**
* @author yap
*/
public class PrintSeriesTest {
/**
* 重新定义打印语句的目标位置为硬盘文件,并打印Unicode前128个字符,并还原
*/
@Test
public void printStream() {
String destPath = "D:" + File.separator + "java-io" + File.separator + "ps.dat";
try (PrintStream ps = new PrintStream(new FileOutputStream(destPath), true)) {
PrintStream defaultOut = System.out;
System.setOut(ps);
int max = 128;
for (int i = 0; i < max; i++) {
System.out.print((char) i + " ");
}
System.setOut(defaultOut);
System.out.println("print over...");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
如果修改out指定之后,需要恢复原来的指向(控制台),则需要在setOut()之前,对System.out进行备份,然后在后面的某个位置调用setOut()来还原备份。
4.2 PrintWriter
概念: 打印字符流PrintWriter是Writer的一个子类。
- 构造器:
PrintWriter(OutputStream out)PrintWriter(OutputStream out, boolean autoFlush)PrintWriter(Writer out):PrintWriter(Writer out, boolean autoFlush)PrintWriter(String fileName)PrintWriter(String fileName, String charset)PrintWriter(File file)PrintWriter(File file, String charset)charset是字符编码字符串,默认UTF8。autoFlush是PrintWriter的刷新属性:- 为true时,每次写入,打印,或读到换行符等操作的时候都会flush。
- 为false时,只flush一次(默认)。
- 常用API方法:
void print(String str):不换行打印,底层封装的write()。void println():换行打印,底层封装的write()。void printf():格式化打印,底层封装的write()。
- System类的一个API方法:
void setOut(PrintStream out):重新定义输出语句中的out的位置(默认指向控制台)。void setErr(PrintStream err):重新定义输出语句中的err的位置(默认指向控制台)。
源码: /javase-advanced/
- src:
c.y.io.PrintSeriesTest.printWriter()
/**
* @author yap
*/
public class PrintSeriesTest {
/**
* 设计一个模拟Log4j(java的日志文件)工作的方法
*/
@Test
public void printWriter() {
String destPath = "D:" + File.separator + "java-io" + File.separator + "my-log.log";
try (PrintWriter pw = new PrintWriter(new FileWriter(destPath, true), true)) {
String msg01 = "添加了一个用户";
String msg02 = "修改了一个用户";
String msg03 = "删除了一个用户";
pw.println(msg01);
pw.println(msg02);
pw.println(msg02);
pw.println("LOGGING AT " + new Date());
} catch (IOException e) {
e.printStackTrace();
}
}
}