I/O Stream
1、对I/O流的理解
要想“流”,要保证有三个东西:
源头
管道
目标
对于源头来说,他是主动的,是流出
对于目标来说,他是被动的,是被流入
将这个思想放到程序中:因为程序员操作的是程序,所以读和写都是相对于程序来说的!
程序要想获取数据源(另一个程序、数据库、文件、云空间)的数据,是被动的接受,被流入,也叫读,如同下图所示:
程序向数据源传输数据,则程序变成主动的,主动输出,也叫写,如图所示:
2、FileInputStream
1 FileInputStream ins = new FileInputStream("file/1.txt");2 int out = 0;3 while ((out = ins.read())!=-1){4 System.out.println("out = " +out);5 }6 //带通道的流一定记得close掉,不然进程一直存在,占用非常大的内存!!!
7 ins.close();
结果:
out = 97out = 32out = 97out = 32out = 97out = 13out = 10out = 98out = 13out = 10out = 99
1.txt长这样:
说明
read()方法读出的是byte类型的ASSCII码,并且是一个一个子节读的字节流,所以使用while循环输出。
如果想输出字符,可以强制类型转换为char(因为是同级的),即(char)out,输出就和文件一样了。
自动类型转换:byte,short,char—> int —> long—> float —> double
enter键其实是两个控制符,回车(光标回到本行行首 13)->换行(光标回到对应的下一行 10)。
1 FileInputStream ins = new FileInputStream("file/1.txt");2 byte[] bytes = new byte[1024];3 int len =ins.read(bytes);4 ins.close();5 System.out.println(new String(bytes,0,len));
结果:
a a abc
注:
使用read(byte[])方法把文件信息读到byte[]数组里,返回值就变成了读入的子节长度
(byte[] bytes, int offset, int length)
bytes-要解码为字符的字节offset-要解码的第一个字节的索引length-要解码的字节数
一个逻辑的火花:读和写确实是相对于程序来说的,但是程序也很好的安排了读和写的位置,比如,FileInputStream(程序从哪个文件读数据),.read(程序把读入的数据放到哪),FileOutputStream(程序向哪个文件写数据),.wirte(程序从哪个地方把要写出的数据拿出来),这么看来,我所说的“程序”就像是中间的管道。
3、FileOutputStream
1 FileOutputStream outs = new FileOutputStream("file/2.txt");2 byte[] bytes = "zhangYaoYuan,你好啊!".getBytes();3 for (byteaByte : bytes) {4 outs.write(aByte);5 }6 //outs.write(bytes);不用for循环,这一步就可以了
7 outs.close();
结果:
如果是操作大的文件,难道是new一个非常大的byte数组吗?
实际上并不是这么处理的,而是使用循环分N次搬运
即buffer缓冲的思想
复制一张图片:
1 public void copyFile() throwsIOException {2 FileInputStream ins = new FileInputStream("file/minions.jpg");3 FileOutputStream outs = new FileOutputStream("file/target.jpg");4 5 byte[] bytes = new byte[1024];6 int lens;//当一次读入的数据大小少于1024b时,这个就有用了,少操作了很多空格
7 while ((lens = ins.read(bytes))!=-1){8 outs.write(bytes,0,lens);9 }10 ins.close();11 outs.close();12 }
4、BufferedInputStream/BufferedOutputStream
有了buffer缓冲的思想,Java写好了一个类,就不需要再自定义byte数组了
1 public void bufferedStream() throwsIOException{2 BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("file/minions.jpg"));3 BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("file/target.jpg"));4 intlens;5 while ((lens = bufferedInputStream.read())!=-1){6 bufferedOutputStream.write(lens);7 }8 bufferedInputStream.close();9 bufferedOutputStream.close();10 }
注意:
使用方法和自定义byte数组一样,但是注意这个类的构造参数是FileInputStream即另外一个类,这就如同是在花钱买了一个VIP服务,套在之前的套餐上!这也是一种设计模式,叫装饰设计模式!
5、FileReader/FileWriter
注:
xxInputStream、xxOutputStream都代表字节流,一次读取一个字节,所以使用byte[]数组接收或者缓冲;
xxReader、xxWriter都代表字符流,一次读取两个字节(Unicode编码),所以使用char[]数组进行接收或者缓冲,注意在Java中char类型占用两个字节。
二者的用途:
字节流通常用于处理二进制数据,实际上它可以处理任意类型的数据,但它不支持直接写入或读取Unicode码元;字符流通常处理文本数据,它支持写入及读取Unicode码元。
所以说,xxReader、xxWriter专门用来处理文本的(其实就是Unicode编码的中文文本)。
类的使用基本和字节流一致
1 public void fileReader() throwsIOException {2 FileReader fileReader = new FileReader("file/1.txt");3 intlens;4 char[] chars = new char[1024];5 while ((lens = fileReader.read(chars)) != -1) {6 System.out.println(new String(chars, 0, lens));7 }8 fileReader.close();9 }
想要输出读入的内容,就要new一个char数组进行接收。
1 public void fileWriter() throwsIOException {2 FileWriter fileWriter = new FileWriter("file/3.txt");3 String str = "张耀元哈哈哈哈哈哈哈!";4 fileWriter.write(str);5 fileWriter.close();6 }
既然是专门处理文本的,写文本可以直接用String做参数。
6、BufferedReader/BufferedWriter
BufferedReader/BufferedWriter同字节流的设计一样,使用了装饰的设计模式,并且增加了readLine()和nextLine()方法,处理文本更加方便。
1 public void bufferedReader() throwsIOException {2 BufferedReader bufferedReader = new BufferedReader(new FileReader("file/3.txt"));3 String str = null;4 //直接返回读到的内容,比较牛,如果使用read方法,还要申请一个char数组接住内容
5 while ((str = bufferedReader.readLine())!= null){6 System.out.println(str);7 }8 bufferedReader.close();9 }
1 public void bufferedWriter() throwsIOException {2 //append 追加
3 BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("file/4.txt",true));4 //“\n”换行的方式换个系统可能就不行了,所以专门有一个方法nextLine()实现换行5 //String string = "你\n" + "你\n" + "你好厉害啊!";
6 String str1 = "你好棒啊!";7 String str2 = "你好帅啊!";8 bufferedWriter.newLine();9 bufferedWriter.write(str1);10 bufferedWriter.newLine();11 bufferedWriter.write(str2);12 bufferedWriter.close();13 }
7、apache commons io
一些基础的东西学习了之后,实际开发中,不需要这么麻烦的操作流(苦笑.jpg,感觉都白学了),apache就写了一个非常方便、非常牛逼、非常好用的工具类FileUtils,操作文件就变得非常easy!(但不是说基础的就不用学了,知道原理更重要!)
官方文档先放这,关于练习和例子之后补充。