【Java】文件I/O-文件内容操作-输入输出流-Reader/Writer/InputStream/OutputStream四种流

导读

在文件I/O这一节的知识里,对文件的操作主要分为两大类:

☑️针对文件系统进行的操作

☑️针对文件内容进行的操作

上文已经讲了针对文件系统即File类的操作,这篇文章里博主就来带了解针对文件内容的操作,即输入输出流(Reader,Writer,InputStream,OutputStream)四种流相关知识📖

前置知识

1、流的分类

文件I/O中的流分为字节流和字符流

字符流:以字符为单位 ,每次读写的最小单位是字符;对应文本文件。包括Reader,Writer两个类

字节流:以字节为单位 ,每次读写的最小单位是字节;对应二进制文件。包括InputStream,OutputStream两个类

流的关系分类如下图

注意,字符和字节的关系如下

一个字符可能是对应多个字节
GBK,一个中文字符 ->两个字节
UTF8,一个中文字符 ->三个字节

2、输入输出的定义

计算机中的输入输出发生在CPU和硬盘之间,而我们所说的输入输出是以CPU为视角,即

· 把数据从CPU保存到硬盘上,是输出/写(Input/Read)

· 把内容从硬盘取到CPU里,是输入/读(Output/Write)

下图可以形象地表示输入输出的定义

四种流的使用

1、Reader

(1)Reader类

先创建一个Reader

java 复制代码
Reader reader = new FileReader("/Users/liuwenwen/Desktop/test.txt");

(2)Reader类中的方法

Reader最常用的就是read方法,read方法分为下面几种

|-----------------------------------------|-----------------------------------------|
| 方法名 | 说明 |
| read(char[] cbuf) | 传入数组参数,读取数组长度的字符存放在数组中 |
| read () | 读一个字符 |
| read(CharBuffer target) | 传入CharBuffer对象 |
| read(char[] cbuf,int off, int length) | 传入数组参数,从字符串off位置开始读,读取length长度的字符存放在数组中 |

(3)代码实例

其中最常用的是read(char[] cbuf)方法,返回参数是读取字符的个数

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

public class demo {
    public static void main(String[] args){
        char[] buf = new char[12];
        try(Reader reader = new FileReader("/Users/liuwenwen/Desktop/test.txt")) {
            while (true){
                int n = reader.read(buf);
                if(n == -1){
                    break;
                }
                System.out.println("n="+n);
                for (int i = 0; i < n; i++) {
                    System.out.print(buf[i]);
                }
                System.out.println();
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }
}

注意:代码中将Reader reader = new FileReader("/Users/liuwenwen/Desktop/test.txt放在try()代码块中是隐藏了reader.close()操作,相当于

java 复制代码
try {
      Reader reader = new FileReader("/Users/liuwenwen/Desktop/test.txt")
      while (true){
                int n = reader.read(buf);
                if(n == -1){
                    break;
                }
                System.out.println("n="+n);
                for (int i = 0; i < n; i++) {
                    System.out.print(buf[i]);
                }
                System.out.println();
        }
} catch (FileNotFoundException e) {
            throw new RuntimeException(e);
} catch (IOException e) {
            throw new RuntimeException(e);
}finally{
       reader.close();
}

读取结果

2、Writer类

(1)Writer中的方法

Writer方法如下

|----------------------------------------|---------------------------------------|
| 方法名 | 说明 |
| write(String str) | 一次写一个字符串 |
| write(char[] cbuf) | 一次写多个字符(字符数组) |
| write(int c) | 一次写一个字符 |
| write(String str, int off, int len) | 带有 offset 和lenoffset指的是从字符串中的第几个字符开始写 |
| write(char[] cbuf, int off, int len) | 带有 offset 和lenoffset 指的是从数组中的第几个字符开始写 |

(2)代码实例

我们最常用的是第一个即write(String str)方法

java 复制代码
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;

public class demo3 {
    public static void main(String[] args) {
        try(Writer writer = new FileWriter("/Users/liuwenwen/Desktop/test.txt")) {
            writer.write("驻跸怀千古,开襟望九州。太平词藻盛,长愿纪鸿休。");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

运行程序后,文本内容被修改了😦

可见我们原来的内容同时也被覆盖。如果不想覆盖原本的内容,怎么办呢?🤔

在创建Writer类时,加一个参数true,表示追加

java 复制代码
try(Writer writer = new FileWriter("/Users/liuwenwen/Desktop/test.txt",true)) 

为了防止由于程序运行太快,内容在缓冲区中没有来得及写到硬盘里,我们加一个flush()方法

java 复制代码
writer.flush();

现在整体代码就变成

java 复制代码
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;

public class demo3 {
    public static void main(String[] args) {
        try(Writer writer = new FileWriter("/Users/liuwenwen/Desktop/test.txt",true)) {
            writer.write("驻跸怀千古,开襟望九州。太平词藻盛,长愿纪鸿休。");
            writer.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

用原来的文本再次运行程序

​​​​​​​

可以看到,这次是追加,不再是覆盖

3、InputStream类

(1)方法

InputStream类和Reader类里的方法类似,不过将char[]数组变为了byte[]数组,返回值是读取字节的个数

(2)代码实例

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

public class demo5 {
    public static void main(String[] args) {
        try (InputStream inputStream = new FileInputStream("/Users/liuwenwen/Desktop/test.txt")){
            byte[] buf = new byte[1024];
            int n = inputStream.read(buf);
            for (int i = 0; i < n; i++) {
                System.out.printf("%x ",buf[i]);
                //采用十六进制打印,更加直观
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

读取结果

4、OutputStream类

(1)方法

OutputStream类和Writer类里的方法类似,不过将char[]数组变为了byte[]数组

(2)代码实例

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

public class demo6 {
    public static void main(String[] args) {
        try(OutputStream outputStream = new FileOutputStream("/Users/liuwenwen/Desktop/test.txt",true)){
            String s = "驻跸怀千古,开襟望九州。太平词藻盛,长愿纪鸿休。";
            outputStream.write(s.getBytes());
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

由于OutputStream类write方法要传入的是byte[]参数,我们直接调用字符串的getBytes()方法,方便书写

最终追加结果

相关推荐
月明长歌18 分钟前
【码道初阶】【Leetcode606】二叉树转字符串:前序遍历 + 括号精简规则,一次递归搞定
java·数据结构·算法·leetcode·二叉树
原来是好奇心19 分钟前
深入Spring Boot源码(八):高级特性与扩展点深度解析
java·源码·springboot
oioihoii22 分钟前
C++共享内存小白入门指南
java·c++·算法
布茹 ei ai24 分钟前
QtWeatherApp - 简单天气预报软件(C++ Qt6)(附源码)
开发语言·c++·qt·开源·开源项目·天气预报
Wpa.wk25 分钟前
自动化测试 - 文件上传 和 弹窗处理
开发语言·javascript·自动化测试·经验分享·爬虫·python·selenium
LinHenrY122727 分钟前
初识C语言(编译和链接)
c语言·开发语言·蓝桥杯
_OP_CHEN27 分钟前
【Python基础】(二)从 0 到 1 入门 Python 语法基础:从表达式到运算符的全面指南
开发语言·python
l1t28 分钟前
利用小米mimo为精确覆盖矩形问题C程序添加打乱函数求出更大的解
c语言·开发语言·javascript·人工智能·算法
@淡 定28 分钟前
线程安全的日期格式化:避免 SimpleDateFormat 并发问题
java
qq_124987075330 分钟前
基于springboot框架的小型饮料销售管理系统的设计与实现(源码+论文+部署+安装)
java·spring boot·后端·spring·毕业设计