Java 基础(四)| IO 流之使用文件流的正确姿势

简介: 为跳槽面试做准备,今天开始进入 Java 基础的复习。希望基础不好的同学看完这篇文章,能掌握泛型,而基础好的同学权当复习,希望看完这篇文章能够起一点你的青涩记忆。

一、什么是 IO 流?


想象一个场景:我们在电脑上编辑文件,可以保存到硬盘上,也可以拷贝到 U 盘中。那这个看似简单的过程,背后其实是数据的传输。


数据的传输,也就是数据的流动。既然是流动也就会有方向,有入方向和出方向。举个上传文件的栗子,现在有三个对象,文件、应用程序、上传的目标地址(服务器)。简化的上传文件有两步:


  • 应用程序读文件(此为入方向,文件读入到应用程序)


  • 应用程序写文件(此为出方向,读完之后写到目标地址)


注意这个入和出是相对的,它相对于应用程序而言。如果相对于服务器而言,这个上传文件操作就是入方向,从应用程序读入。Java 中 I/O 操作主要是指使用 java.io 包下的内容,进行输入、输出操作。输入也叫做读取数据,输出也叫做作写出数据。


二、IO 流的分类


我不认同网络上很多 IO 流的图,他们只是简单的把 io 流分成字节流和字符流。这样的分类也不是说不好,只是太臃肿、难记。


先上一张我自己总结的 IO 留的思维导图,我先把它分成了节点流处理流节点流是直接接触数据源的,而处理流是出于各种目的在节点流的基础上再套一层的 IO 流。再按照操作类型,分成 8 个小类,然后才是字节、字符分类,最后才是输入、输出的分类。具体可以看以下思维导图 (可能不清晰,有需要的在后台回复 IO 流获取原思维导图)


根据数据的流向分为:输入流输出流


  • 输入流 :把数据从其他设备上读取到内存中的流。
  • 输出流 :把数据从内存 中写出到其他设备上的流。


根据数据的类型分为:字节流字符流


  • 字节流 :以字节为单位,读写数据的流。
  • 字符流 :以字符为单位,读写数据的流。


640.jpg


IO 流要说明白需要好几篇才行,今天我们先复习文件流。


2.1 一切皆字节


所有的文件(包括图片、音乐、视频),都是字节。所以字节流可以传输任意文件数据。在操作流的时时,无论使用什么样的流对象,底层传输的始终为二进制数据。


2.2 什么叫文件流?


文件流也就是直接操作文件的流,文件流又分为字节流 (FileInputStreamFileOutputStream)和字符流(FileReaderFileWriter)。其中字节流可用于操作一切文件,而字符流只能用于操作文本文件。


三、使用文件字节流


640.png


640.png


3.1 FileOutputStream


java.io.FileOutputStream 类继承于 OutputStream 是文件输出流,用于将数据写出到文件。


构造方法:可用文件路径构造,也可创建 File 对象之后构造。


写出数据示例:


/**
 * Project Name:review_java <br/>
 * Package Name:com.nasus.io.filestream <br/>
 * Date:2020/1/5 19:24 <br/>
 *
 * @author <a href="turodog@foxmail.com">chenzy</a><br/>
 */
publicclass FOSWriterStream {
    public static void main(String[] args) throws IOException {
        // 使用文件名称创建流对象,构造函数中的 true 表示在原有数据末尾追加续写
        FileOutputStream fos = new FileOutputStream("fos.txt", true);
        // 1、逐个字节写出
        fos.write(97); // 97 的 ascll 码是 a
        fos.write(98); // 98 的 ascll 码是 b
        fos.write(99); // 99 的 ascll 码是 c
        // 2、写出一个换行, 换行符号转成数组写出
        fos.write("\r\n".getBytes());
        // 字符串转换为字节数组
        byte[] b = "一个优秀的废人".getBytes();
        // 3、写出字节数组数据
        fos.write(b);
        // 4、写出指定长度字节数组数据(不可超过 b 的长度,否则数组越界)
        fos.write(b, 0, b.length);
        // 关闭资源
        fos.close();
    }
}


3.2 FileInputStream


java.io.FileInputStream 类继承于 InputStream 是文件输入流,用于将数据从文件读出。


构造方法:可用文件路径构造,也可创建 File 对象之后构造。


读取数据示例:


/**
 * Project Name:review_java <br/>
 * Package Name:com.nasus.io.filestream <br/>
 * Date:2020/1/5 19:31 <br/>
 *
 * @author <a href="turodog@foxmail.com">chenzy</a><br/>
 */
publicclass FISReadStream {
    public static void main(String[] args) throws IOException {
        // 1、逐个读取字节
        int b;
        FileInputStream fis1 = new FileInputStream("fis.txt");
        // 循环读取
        while ((b = fis1.read())!=-1) {
            System.out.println((char)b);
        }
        // 关闭资源
        fis1.close();
        System.out.println("----华丽丽的分割线----");
        // 2、定义字节数组读取
        int length;
        FileInputStream fis2 = new FileInputStream("fis.txt");
        // 定义字节数组,作为装字节数据的容器
        byte[] bytes = newbyte[1024];
        // 循环读取
        while ((length = fis2.read(bytes))!=-1) {
            // 每次读取后,把数组变成字符串打印
            System.out.println(new String(bytes, 0, length));
        }
        // 关闭资源
        fis2.close();
    }
}


复制文件示例:


/**
 * Project Name:review_java <br/>
 * Package Name:com.nasus.io.filestream <br/>
 * Date:2020/1/5 19:43 <br/>
 *
 * @author <a href="turodog@foxmail.com">chenzy</a><br/>
 */
publicclass FileCopyStream {
    public static void main(String[] args) throws IOException {
        // 指定数据源
        FileInputStream fis = new FileInputStream("Java IO 流.png");
        // 指定目的地
        FileOutputStream fos = new FileOutputStream("流.png");
        // 定义数组
        byte[] b = newbyte[1024];
        // 定义长度
        int len;
        // 循环读取
        while ((len = fis.read(b))!=-1) {
            // 写出数据
            fos.write(b, 0 , len);
        }
        // 关闭资源,后开先关,后开先关
        fos.close();
        fis.close();
    }
}


3.3 为什么字节流处理中文字符时会出现乱码?


首先明确一点:一个英文字母占一个字节,一个汉字占两个字节,所以当字节流读取字符流就会出现乱码或者显示不全。所以用字节流操作含有中文字符的文件时,要转换成字符流并指定编码格式才能防止乱码。(这点,后面转换流会复习到


四、使用文件字符流


当使用字节流读取文本文件时,可能会有一个小问题。就是遇到中文字符时,可能不会显示完整的字符,那是因为一个中文字符可能占用多个字节存储。所以 Java 提供一些字符流类,以字符为单位读写数据,专门用于处理文本文件。

640.png

640.png

4.1 FileReader


java.io.FileReader 类继承于 Reader 类,是读取字符文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。


构造方法:可用文件路径构造,也可创建 File 对象之后构造。


  • 字符编码:字节与字符的对应规则。Windows 系统的中文编码默认是 GBK 编码表
  • 字节缓冲区:一个字节数组,用来临时存储字节数据。


PS:有时候出现乱码,多考虑下是不是编码的原因:字节与字符的规则对不上。


读取数据示例:


/**
 * Project Name:review_java <br/>
 * Package Name:com.nasus.io.filereadwrite <br/>
 * Date:2020/1/5 20:19 <br/>
 *
 * @author <a href="turodog@foxmail.com">chenzy</a><br/>
 */
publicclass FileRead {
    public static void main(String[] args) throws IOException {
        // 1、逐个字符读取
        int b = 0;
        FileReader fileReader1 = new FileReader("read.txt");
        // 循环读取
        while ((b = fileReader1.read())!=-1) {
            // 自动提升类型提升为 int 类型,所以用 char 强转
            System.out.println((char)b);
        }
        // 关闭流
        fileReader1.close();
        System.out.println("----华丽丽的分割线----");
        // 2、利用字符数组,每次读取两个字符
        int length = 0;
        FileReader fileReader2 = new FileReader("read.txt");
        char[] charArray = newchar[2];
        // 读取数据
        while ((length = fileReader2.read(charArray)) != -1) {
            System.out.println(new String(charArray, 0, length));
        }
        // 关闭流
        fileReader2.close();
    }
}


4.2 FileWriter


java.io.FileWriter 类是写出字符到文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。


构造方法:可用文件路径构造,也可创建 File 对象之后构造。


写出数据示例:


public static void main(String[] args) throws IOException {
        // 使用文件名称创建流对象,true 表示在原有数据末尾追加续写
        FileWriter fileWriter = new FileWriter("fw.txt", true);
        // 1、逐个写出字符
        fileWriter.write(97);
        fileWriter.write('C');
        fileWriter.write('Z');
        fileWriter.write('Y');
        // 中文编码表中30000对应一个汉字。
        fileWriter.write(30000);
        // 2、写出字符串
        fileWriter.write("是一个");
        // 3、写出 Windows 换行
        fileWriter.write("\r\n");
        // 4、写出字符串数组
        // 字符串转换为字节数组
        char[] chars = "优秀的废人".toCharArray();
        fileWriter.write(chars, 0, chars.length);
        // 关闭资源,close方法调用之前,数据只是保存到了缓冲区,并未写出到文件中。
        fileWriter.close();
    }


刷新与关闭:


因为内置缓冲区的原因,如果不关闭输出流,无法写出字符到文件中。但是关闭的流对象,是无法继续写出数据的。如果我们既想写出数据,又想继续使用流,就需要 flush 方法了。


  • flush :刷新缓冲区,流对象可以继续使用。
  • close: 先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。


/**
 * Project Name:review_java <br/>
 * Package Name:com.nasus.io.filereadwrite <br/>
 * Date:2020/1/5 22:25 <br/>
 *
 * @author <a href="turodog@foxmail.com">chenzy</a><br/>
 */
publicclass FileFlushClose {
    public static void main(String[] args) throws IOException {
        // 使用文件名称创建流对象
        FileWriter fw = new FileWriter("fw.txt");
        // 1、通过 flush 写出数据
        // 写出第 1 个字符
        fw.write('刷');
        fw.flush();
        // 继续写出第 2 个字符,写出成功
        fw.write('新');
        fw.flush();
        // 2、通过 close 写出数据,流关闭后不可用
        // 写出第 1 个字符
        fw.write('关');
        fw.close();
        // 继续写出第 2 个字符,【报错】java.io.IOException: Stream closed
        fw.write('闭');
        fw.close();
    }
}


五、源码地址


目录
打赏
0
0
0
0
3
分享
相关文章
Java网络编程,多线程,IO流综合小项目一一ChatBoxes
**项目介绍**:本项目实现了一个基于TCP协议的C/S架构控制台聊天室,支持局域网内多客户端同时聊天。用户需注册并登录,用户名唯一,密码格式为字母开头加纯数字。登录后可实时聊天,服务端负责验证用户信息并转发消息。 **项目亮点**: - **C/S架构**:客户端与服务端通过TCP连接通信。 - **多线程**:采用多线程处理多个客户端的并发请求,确保实时交互。 - **IO流**:使用BufferedReader和BufferedWriter进行数据传输,确保高效稳定的通信。 - **线程安全**:通过同步代码块和锁机制保证共享数据的安全性。
58 23
JAVA网络IO之NIO/BIO
本文介绍了Java网络编程的基础与历史演进,重点阐述了IO和Socket的概念。Java的IO分为设备和接口两部分,通过流、字节、字符等方式实现与外部的交互。
|
4月前
|
java 中 IO 流
Java中的IO流是用于处理输入输出操作的机制,主要包括字节流和字符流两大类。字节流以8位字节为单位处理数据,如FileInputStream和FileOutputStream;字符流以16位Unicode字符为单位,如FileReader和FileWriter。这些流提供了读写文件、网络传输等基本功能。
77 10
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
这篇文章详细介绍了Java中的IO流,包括字符与字节的概念、编码格式、File类的使用、IO流的分类和原理,以及通过代码示例展示了各种流的应用,如节点流、处理流、缓存流、转换流、对象流和随机访问文件流。同时,还探讨了IDEA中设置项目编码格式的方法,以及如何处理序列化和反序列化问题。
154 1
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
|
5月前
|
使用 Java 文件流读取二进制文件
【10月更文挑战第5天】通过以上步骤,我们能够有效地使用 Java 的文件流来读取二进制文件,获取其中的信息。你在实际操作中是否遇到过一些问题或有什么特殊的技巧可以分享呢?我们可以一起交流,共同提高对文件流操作的理解和应用能力。
揭秘Java IO流:字节流与字符流的神秘面纱!
揭秘Java IO流:字节流与字符流的神秘面纱!
74 1
Java IO流全解析:字节流和字符流的区别与联系!
Java IO流全解析:字节流和字符流的区别与联系!
181 1
Java 流(Stream)、文件(File)和IO的区别
Java中的流(Stream)、文件(File)和输入/输出(I/O)是处理数据的关键概念。`File`类用于基本文件操作,如创建、删除和检查文件;流则提供了数据读写的抽象机制,适用于文件、内存和网络等多种数据源;I/O涵盖更广泛的输入输出操作,包括文件I/O、网络通信等,并支持异常处理和缓冲等功能。实际开发中,这三者常结合使用,以实现高效的数据处理。例如,`File`用于管理文件路径,`Stream`用于读写数据,I/O则处理复杂的输入输出需求。
363 12
|
5月前
|
Java 中 IO 流的分类详解
【10月更文挑战第10天】不同类型的 IO 流具有不同的特点和适用场景,我们可以根据具体的需求选择合适的流来进行数据的输入和输出操作。在实际应用中,还可以通过组合使用多种流来实现更复杂的功能。
103 0
【Java】文件IO
【Java】文件IO
63 0

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等