IO流
关键词:字节、字符、包装、流
整个Java IO体系都是基于字符流(InputStream/OutputStream) 和 字节流(Reader/Writer)作为基类,根据不同的数据载体或功能派生出来的。
- 文件流:FileInputStream/FileOutputStream, FileReader/FileWriter
前者对应着字节流(byte),后者对应着字符流(char),读写都是无缓存的。
1 public class HelloWorld { 2 3 public static void main(String[] args) { 4 5 try { 6 FileInputStream fin = new FileInputStream("C:\\Users\\Administrator\\workspace\\test1\\src\\2.txt"); 7 FileOutputStream fout = new FileOutputStream("C:\\Users\\Administrator\\workspace\\test1\\src\\1.txt"); 8 byte[] buf = new byte[1024]; //分块 9 int len = 0; 10 while((len=fin.read(buf))>0) 11 { 12 fout.write(buf,0,len); 13 14 } 15 16 fout.close(); 17 } catch (IOException e) { 18 // TODO Auto-generated catch block 19 e.printStackTrace(); 20 } 21 22 23 } 24 25 }
- 包装流:PrintStream/PrintWriter/Scanner
PrintStream可以封装(包装)直接与文件交互的节点流对象OutputStream, 使得编程人员可以忽略设备底层的差异,进行一致的IO操作。因此这种流也称为处理流或者包装流。
PrintWriter除了可以包装字节流OutputStream之外,还能包装字符流Writer
Scanner可以包装键盘输入,方便地将键盘输入的内容转换成我们想要的数据类型。
ps:包装的意思是添加了很多的功能,使对原来流的操作更加方便
FileOutputStream fos = new FileOutputStream("tmp.txt"); PrintStream ps = new PrintStream(fos)) { ps.println("普通字符串\n");
通过传参,ps将fos包装,使用println函数就可以直接打印数据到fos对应的流里面。
- 字符串流:StringReader/StringWriter
这两个操作的是专门操作String字符串的流,其中StringReader能从String中方便地读取数据并保存到char数组,而StringWriter则将字符串类型的数据写入到StringBuffer中(因为String不可写)。
ps:StringReader其实就是把字符串当作了输入流
1 public class HelloWorld { 2 3 public static void main(String[] args) { 4 5 6 String s = "qegjkljg"; 7 StringReader sr = new StringReader(s); 8 char[] buf = new char[2]; 9 int len=0; 10 try { 11 while((len=sr.read(buf))>0) 12 { 13 System.out.println(new String(buf,0,len)); 14 } 15 } catch (IOException e) { 16 // TODO Auto-generated catch block 17 e.printStackTrace(); 18 } 19 } 20 21 }
- 转换流:InputStreamReader/OutputStreamReader
这两个类可以将字节流转换成字符流,被称为字节流与字符流之间的桥梁。我们经常在读取键盘输入(System.in)或网络通信的时候,需要使用这两个类
ps:这两个类需要对InputStream/OutputStream封装,而不能直接对文件进行封装
- 缓冲流:BufferedReader/BufferedWriter , BufferedInputStream/BufferedOutputStream
-
没有经过Buffered处理的IO, 意味着每一次读和写的请求都会由OS底层直接处理,这会导致非常低效的问题。
经过Buffered处理过的输入流将会从一个buffer内存区域读取数据,本地API只会在buffer空了之后才会被调用(可能一次调用会填充很多数据进buffer)。
经过Buffered处理过的输出流将会把数据写入到buffer中,本地API只会在buffer满了之后才会被调用
BufferedReader/BufferedWriter可以将字符流(Reader)包装成缓冲流,这是最常见用的做法。
另外,BufferedReader提供一个readLine()可以方便地读取一行,而FileInputStream和FileReader只能读取一个字节或者一个字符。
总结:
1 public class HelloWorld { 2 3 public static void main(String[] args) throws IOException { 4 5 6 try { 7 /*将文件流包装成文件输入字节流*/ 8 FileInputStream fi = new FileInputStream("C:\\Users\\Administrator\\workspace\\test1\\src\\1.txt"); 9 /*将输入字节流转成输入字符流*/ 10 InputStreamReader Reader = new InputStreamReader(fi); 11 /*将输入字符流包装成输入缓冲字符流*/ 12 BufferedReader br = new BufferedReader(Reader); 13 14 System.out.println(br.readLine()); 15 16 } catch (FileNotFoundException e) { 17 // TODO Auto-generated catch block 18 e.printStackTrace(); 19 } 20 } 21 22 }
当然,字节流也有对应的BufferedInputStream,不需要这么麻烦,这里只是为了体会包装的思想