java I/O流学习

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 = 97 out = 32 out = 97 out = 32 out = 97 out = 13 out = 10 out = 98 out = 13 out = 10 out = 99

1.txt长这样:

说明

  1. read()方法读出的是byte类型的ASSCII码,并且是一个一个子节读的字节流,所以使用while循环输出。

    • 如果想输出字符,可以强制类型转换为char(因为是同级的),即(char)out,输出就和文件一样了。

    • 自动类型转换:byte,short,char—> int —> long—> float —> double

  2. 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 a b c

注:

  1. 使用read(byte[])方法把文件信息读到byte[]数组里,返回值就变成了读入的子节长度

  2. String(byte[] bytes, int offset, int length)

    bytes-要解码为字符的字节 offset-要解码的第一个字节的索引 length-要解码的字节数

  3. 一个逻辑的火花:读和写确实是相对于程序来说的,但是程序也很好的安排了读和写的位置,比如,FileInputStream(程序从哪个文件读数据),.read(程序把读入的数据放到哪),FileOutputStream(程序向哪个文件写数据),.wirte(程序从哪个地方把要写出的数据拿出来),这么看来,我所说的“程序”就像是中间的管道。

3、FileOutputStream

1  FileOutputStream outs = new FileOutputStream("file/2.txt");
2          byte[] bytes = "zhangYaoYuan,你好啊!".getBytes();
3          for (byte aByte : bytes) {
4              outs.write(aByte);
5          }
6          // outs.write(bytes);不用for循环,这一步就可以了
7          outs.close();

 

结果:

如果是操作大的文件,难道是new一个非常大的byte数组吗?

实际上并不是这么处理的,而是使用循环分N次搬运

即buffer缓冲的思想

复制一张图片:

 1      public void copyFile() throws IOException {
 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() throws IOException{
 2          BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("file/minions.jpg"));
 3          BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("file/target.jpg"));
 4          int lens;
 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() throws IOException {
2          FileReader fileReader = new FileReader("file/1.txt");
3          int lens;
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() throws IOException {
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() throws IOException {
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() throws IOException {
 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!(但不是说基础的就不用学了,知道原理更重要!)

官方文档先放这,关于练习和例子之后补充。

 

posted @ 2021-02-09 22:34  yyComeOn  阅读(85)  评论(0)    收藏  举报