【文件IO】Java文件内容操作

【文件IO】Java文件内容操作

      • 一、文件流
        • [1.1 InputStream](#1.1 InputStream)
        • [1.2 OutputStream](#1.2 OutputStream)
        • [1.3 Reader、Writer](#1.3 Reader、Writer)
        • [1.4 用Scanner辅助](#1.4 用Scanner辅助)

一、文件流

主要分为字节流 (InputStream、OutputStream)和字符流 (Reader、Writer)。字节流每次读写的最小单位为1个字节,字符流每次读写的最小单位为1个字符(1个字符可能由多个字节构成)。

读写文件在各个编程语言中,都是固定套路。即打开文件、读写文件、关闭文件。关闭文件是十分重要的,在处理大量请求,大量的打开文件的时候,如果不及时关闭文件,可能会引起文件资源泄露

文件资源泄露:

每个计算机上都维护有一张文件描述符表(顺序表/数组),记录当前打开了哪些文件。数组中的每个元素都是一个结构体,这个结构体描述了打开的文件在文件系统上的一些属性。每次打开一个文件都要在文件描述符表中占据一个位置,如果不及时关闭,就会导致文件描述符表被耗尽。如果耗尽,后续再打开文件就会打开失败。

此处的文件描述符表不能扩容:

因为对于操作系统内核来说,性能要求是相当高的,如果扩容(短时间内大量的搬运操作)引起卡顿、不稳定是得不偿失的。

1.1 InputStream

方法

修饰符及返回值类型 ⽅法签名 说明
int read() 读取⼀个字节的数据,返回 -1 代表已经完全读完了
int read(byte[] b) 最多读取 b.length 字节的数据到 b 中,返回实际读到的数量;-1 代表读完了
int read(byte[] b, int off, int len) 从off开始,读取len个字节的数据到b中,返回实际读到的数量;-1 代表读完了
void close() 关闭字节流

构造方法
InputStream 只是⼀个抽象类,要使⽤还需要具体的实现类。关于 InputStream 的实现类有很多,基本可以认为不同的输⼊设备都可以对应⼀个 InputStream 类,我们现在只关⼼从⽂件中读取,所以使⽤ FileInputStream。

签名 说明
FileInputStream(File file) 利⽤ File 构造⽂件输⼊流
FileInputStream(String name) 利⽤⽂件路径构造⽂件输⼊流
  • 打开关闭文件
java 复制代码
//为了避免中间出现异常,close执行不到,将close写到finally中
InputStream inputStream=null;
try {
    inputStream = new FileInputStream("./test.txt");
}finally {
    inputStream.close();
}

//更方便的写法,try with resources
//实现了Closeable接口的类,才能放到try()里面
try(InputStream inputStream =new FileInputStream("./test.txt")){
    //写中间逻辑        
}
  • 读写文件
java 复制代码
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

public class IODemo3 {
    public static void main(String[] args) throws IOException {
        try(InputStream inputStream =new FileInputStream("./test.txt")){
            while(true){
                //每次读取一个字节
                //此处返回的是读取的内容
//                int b=inputStream.read();
//                if(b==-1){
//                    //文件读取结束
//                    break;
//                }
//                System.out.printf("%d ",b);
				//一次读多个字节,将内容读到buffer中
                byte[] buffer=new byte[1024];
                //此处返回的是读取的字节数
                int n=inputStream.read(buffer);
                if(n==-1){
                    //文件读取结束
                    break;
                }
                for(int i=0;i<n;i++){
                    System.out.printf("%d ",buffer[i]);
                }
            }
        }
    }
}

如果想要打印具体的内容而不是每个字节的十进制形式,可以构造字符串在打印。

java 复制代码
String s=new String(buffer,0,n);
System.out.println(s);
1.2 OutputStream

方法

修饰符及返回值类型 ⽅法签名 说明
void write(byte[] b) 将 b 这个字符数组中的数据全部写⼊ os 中
int write(byte[] b, int off, int len) 将 b 这个字符数组中从 off 开始的数据写⼊ os 中,⼀共写 len 个
void close() 关闭字节流
void flush() 重要:我们知道 I/O 的速度是很慢的,所以,⼤多的 OutputStream 为了减少设备操作的次数,在写数据的时候都会将数据先暂时写⼊内存的⼀个指定区域⾥,直到该区域满了或者其他指定条件时才真正将数据写⼊设备中,这个区域⼀般称为缓冲区。但造成⼀个结果,就是我们写的数据,很可能会遗留⼀部分在缓冲区中。需要在最后或者合适的位置,调⽤ flush(刷新)操作,将数据刷到设备中。

OutputStream 同样只是⼀个抽象类,要使⽤还需要具体的实现类。我们现在还是只关⼼写⼊⽂件中,所以使用FileOutputStream 。

java 复制代码
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class IODemo4 {
    public static void main(String[] args) throws IOException {
    	//true表示追加,不加true表示覆盖
        try(OutputStream outputStream=new FileOutputStream("./test.txt"),true){
            byte[] buffer=new byte[]{97,98,99,100};
            outputStream.write(buffer);
        }
    }
}
1.3 Reader、Writer

与上面的InputStream、OutputStream基本一致,但是操作单位为char(字符)。

我们来看几个例子:

java 复制代码
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

public class IODemo5 {
    public static void main(String[] args) throws IOException {
        try(Reader reader=new FileReader("./test.txt")){
            while(true){
                char[] buffer=new char[1024];
                int n=reader.read(buffer);
                if(n==-1){
                    break;
                }
//                String s=new String(buffer,0,n);
//                System.out.println(s);
                for(int i=0;i<n;i++){
                    System.out.print(buffer[i]+" ");

                }
            }
        }
    }
}

运行结果:

我们知道,一个汉字占3个字节,而一个char只占两个字节,为什么这里没出问题呢?

Java中将utf8先转化为unicode(2字节),再转化为utf8.

java 复制代码
try(Writer writer=new FileWriter("./test.txt",true)){
    String s="坤坤";
    writer.write(s);
}
1.4 用Scanner辅助

使用Scanner,我们就不需要构造空数组来接收输入,而是可以用Scanner.next()来完成这一过程。

java 复制代码
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;

public class IODemo6 {
    public static void main(String[] args) throws IOException {
        try(InputStream inputStream=new FileInputStream("./test.txt")){
            Scanner scanner=new Scanner(inputStream);
            while(scanner.hasNext()){
                String s=scanner.next();
                System.out.println(s);
            }
        }
    }
}

我们之前常写的System.inSystem.out其实就是输入输出流。

相关推荐
风清云淡_A1 分钟前
【java基础系列】实现数字的首位交换算法
java·算法
Gao_xu_sheng4 分钟前
Java程序打包成exe,无Java环境也能运行
java·开发语言
大卫小东(Sheldon)11 分钟前
Java的HTTP接口测试框架Gatling
java
谢家小布柔12 分钟前
java中的继承
java·开发语言
l1384942745118 分钟前
Java每日一题(2)
java·开发语言·游戏
苹果醋321 分钟前
SpringBoot快速入门
java·运维·spring boot·mysql·nginx
WANGWUSAN6632 分钟前
Python高频写法总结!
java·linux·开发语言·数据库·经验分享·python·编程
Yvemil732 分钟前
《开启微服务之旅:Spring Boot 从入门到实践》(一)
java
forNoWhat41 分钟前
java小知识点:比较器
java·开发语言
西洼工作室1 小时前
【java 正则表达式 笔记】
java·笔记·正则表达式