文章目录
- 文件内容操作
- 读文件(字节流)
- read介绍
- read() 使用
- read(byte[] b) 使用
 
- read(byte[] b, int off, int len) 使用
 
- 写文件(字节流)
- write介绍
- write(int b) 使用
- write(byte[] b) 使用
- write(byte[] b, int off, int len) 使用
 
 
- 读文件(字符流)
- read() 使用
- read(char[] cbuf) 使用
 
- 写文件(字符流)
- 利用Scanner进行字符读取
 
文件内容操作
书接上文,我们已经在当前目录中创建了一个test.txt文件,文件内容为"hello".
 我们的代码:
package javaEE.fileIO;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
public class J {
    public static void main(String[] args) throws FileNotFoundException {
        // 使用这种写法,我们不变写finally也不必写close了~
        try (InputStream inputStream = new FileInputStream("./test.txt")) {
        }catch (IOException e) {
            e.printStackTrace();
        }
    }
}
接下来正式介绍如何读写文件~
读文件(字节流)
read介绍
我们所谓的读文件,其实就是把文件的内容从硬盘存到内存中.
 read()方法可以实现读文件这样的操作.
inputStream.read();

 read的官方文档说明:
 
 解释一下:read操作可以返回当前的一个字节,它会按照int的类型来返回,但是呢,这个int的范围只能是0~255.如果没有字节可以去读,也就是文件读取完毕的时候,就会返回-1.
之所以不使用byte,是因为当前这里的返回值要能够表示-1这种"特殊情况"(byte没法表示).
read() 使用
使用read()读取文件内容.
package javaEE.fileIO;
import java.io.*;
public class J {
    public static void main(String[] args) throws FileNotFoundException {
        try (InputStream inputStream = new FileInputStream("./test.txt")) {
            while (true) {
                int b = inputStream.read();
                if(b == -1) {
                    //读取完毕了
                    break;
                }
                // 表示字节,更习惯使用十六进制去打印.
                System.out.printf("0x%x\n",b);
            }
        }catch (IOException e) {
            e.printStackTrace();
        }
    }
}
运行结果如下.
 
 与文件内容一致~
 
上述代码的写法一次只读一个字节,效率很低,并不推荐使用,
 一次读一个字节,这意味着会频繁读取多次硬盘,而硬盘IO的耗时是比较大的.所以我们希望减少IO的次数来提高效率.
read(byte[] b) 使用
我们可以使用read(byte[] b),来一次读取多个字节.
 这个操作就会把硬盘中读到的对应的数据,尽可能地填充到byte内存的字节数组中.填充的过程会在一次IO中完成,这就减少了硬盘IO的次数,提供了效率.
 read(byte[] b)会返回一个int类型的数,表示实际读取到了多少个字节.当读到流的末尾,read就会返回-1.
package javaEE.fileIO;
import java.io.*;
public class J {
    public static void main(String[] args) throws FileNotFoundException {
        try (InputStream inputStream = new FileInputStream("./test.txt")) {
            while (true) {
                byte[] buffer = new byte[1024];
                // 这个操作就会把硬盘中读到的对应的数据,尽可能地填充到buffer内存的字节数组中.
                // 填充的过程会在一次IO中完成.
                // 返回值n表示read操作,实际读取到多少个字节.
                int n = inputStream.read(buffer);
                // 当读到流的末尾,read就会返回-1
                if (n == -1) {
                    break;
                }
                for (int i = 0; i < n; i++) {
                    System.out.printf("0x%x\n", buffer[i]);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
read(byte[] b, int off, int len) 使用
这个版本类似于上面的版本,它也是把数据往字节数组b里填充.但与上个版本不同的是,它不是使用整个数组,而是使用数组中[off,off + len) 范围的空间.
这里的off是offset的意思,是"偏移量",不是"关闭".
由于使用与上面的版本差不多,这里就不再演示了~
写文件(字节流)
write介绍
写文件,和读文件非常相似. 
write(int b) 使用
package javaEE.fileIO;
import java.io.*;
public class K {
    public static void main(String[] args) throws FileNotFoundException {
        try (OutputStream outputStream = new FileOutputStream("./test.txt")) {
            outputStream.write(97); // 向文件中写入内容
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
运行后test.txt的内容.
 
需要注意的是,此处的写操作,会把之前的内容清空,再进行写操作.只要使用OutputStream打开文件,文件中的内容就没了~
OutputStream 默认是在写入之前就会清空原来的内容.
 如果不想清空,OutputStream还有一个操作,"追加写"保持原有内容不变,在末尾继续写入新内容.
package javaEE.fileIO;
import java.io.*;
public class K {
    public static void main(String[] args) throws FileNotFoundException {
        try (OutputStream outputStream = new FileOutputStream("./test.txt",true)) {
            outputStream.write(97); // 向文件中写入内容
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
多次运行之后,test.txt中的内容.
 
 以上都是一次向文件中写入一个字节.
 我们也可以一次写入多个字节.
write(byte[] b) 使用
package javaEE.fileIO;
import java.io.*;
public class K {
    public static void main(String[] args) throws FileNotFoundException {
        // true表示"追加写".
        try (OutputStream outputStream = new FileOutputStream("./test.txt", true)) {
            byte[] buffer = new byte[]{0x68, 0x65, 0x6c, 0x6c, 0x6f};
            outputStream.write(buffer);// 把整个字节数组写入到文件中
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

write(byte[] b, int off, int len) 使用
这个版本类似于上面的版本,它也是把字节数组b中的数据写入到文件中.但与上个版本不同的是,它不是使用整个数组,而是使用数组中[off,off + len) 范围的空间.
再次强调: 这里的off是offset的意思,是"偏移量",不是"关闭".
这个版本的用法与上一个差不多,这里就不再赘述了.
InputStream / OutputStream 读写数据就是按照字节来操作的,如果要读写字符(中文等)的话,就需要靠程序员手动的来区分出哪几个字节是一个字符,再确保把这几个字节作为整体来写入.
为了更方便处理字符,我们就引入了字符流~
读文件(字符流)

read() 使用

read()虽然返回的是一个字符,但是为了能够表示-1这个情况,它并没有使用char这样的类型,而是使用int类型.
package javaEE.fileIO;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public class L {
    public static void main(String[] args) {
        try (Reader reader = new FileReader("./test.txt")) {
            while (true) {
                int c = reader.read();
                if (c == -1) {
                    return;
                }
                char ch = (char) c;
                System.out.print(ch);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
文件内容(utf8编码).
 
运行结果.
 
 在uft8中每个汉字是3个字节,但是Java中的char可是2个字节啊,这怎么能表示呢?
 其实,在我们使用字符流读取数据的过程中,Java标准库内部就自动针对数据的编码进行转码了.当使用char表示这里的汉字的时候,就不再使用utf8编码了,而是使用Unicode.在unicode中,一个汉字就是2字节~
read(char[] cbuf) 使用
package javaEE.fileIO;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public class L {
    public static void main(String[] args) {
        try (Reader reader = new FileReader("./test.txt")) {
            char[] buffer = new char[1024];
            int n = reader.read(buffer);
            System.out.println(n);
            for (int i = 0; i < n; i++) {
                System.out.print(buffer[i]);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

 与之类似,read(char[] cbuf, int off, int len) 就不再演示了~
写文件(字符流)

 使用方法都类似,这里就不写了,只演示一下第二个的用法.
package javaEE.fileIO;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class M {
    public static void main(String[] args) {
        // "./test.txt"后面可以写 ,true 表示"追加写",在前面也演示过~
        try (Writer writer = new FileWriter("./test.txt")) {
            writer.write("你好世界");
        } catch(IOException e) {
            e.printStackTrace();
        }
    }
}

利用Scanner进行字符读取

我们之前使用Scanner的时候都是这么用的:
Scanner scanner = new Scanner(System.in);
有没有好奇过,这里的System.in是啥?
 其实,System.in就是一个InputStream.
 
 因此,Scanner里面也可以填写其他文件的InputStream.
package javaEE.fileIO;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;
public class N {
    public static void main(String[] args) {
        try (InputStream inputStream = new FileInputStream("./test.txt")) {
            // 这样一写之后,相当于我们把针对流对象操作的权限就转交给Scanner了
            // Scanner就可以按照它自己提供的方法,来去读取并且解析文件的内容.
            Scanner scanner = new Scanner(inputStream);
            while (scanner.hasNextInt()) {
                System.out.println(scanner.nextInt());
            }
        } catch (IOException e){
            e.printStackTrace();
        }
    }
}
test.txt中的文件内容.
 
 代码运行结果:
 
 本文到这里就结束啦~
![[产品管理-6]:NPDP新产品开发 - 4 - 战略 - 创新支持战略,支持组织的总体创新战略(平台战略、技术战略、营销战略、知识产权战略、能力建设战略)](https://i-blog.csdnimg.cn/direct/14ebaf9b56dc4659b1d9e41a59a3bd5c.png)


















