Java SE:详解IO流(上)

简介: Java SE:详解IO流(上)

编译软件:IntelliJ IDEA 2019.2.4 x64

运行环境:win10 家庭中文版

jdk版本:1.8.0_361

前言

当我们浏览技术文章或查阅专业技术书籍时,经常可以看到“IO”这个词语,很多英语不好的朋友常常抓耳挠腮,不知其所云,在进行Java程序开发时痛苦不堪,常常需要查阅英语词典以究其意。莫急,今天本文让你彻底搞懂IO以及IO流


提示:以下是本篇文章正文内容,下面案例可供参考

一、什么是IO?

“IO”,“IO”,将这“I"与”O"两个字母分别拆开出来看,“I"就是英语单词”Input"的简写,意为输入,例如键盘输入,从文件中读取,从网络中接收等场景;“O”便是英语单词Output的简写,意为输出,又如Java程序的运行结果输出到控制台,写入文件,通过网络发送等场景。

代码如下(示例):

@Test
    public void test08(){
        Scanner input=new Scanner(System.in);//键盘输入
        System.out.print("输入一个数字:");
        int n=input.nextInt();
        System.out.println("输出数字:"+n);//输出到控制台
    }

而在上述案例场景中数据的传输,亦可看作是数据的流动,基于此,人们便形象的称其为IO流。在Java中,按照流动的方向,以内存为基准,分为输入input输出output ,即流向内存是输入流,流出内存的输出流。

Java中I/O操作主要是指使用java.io包下的内容,进行输入、输出操作。输入也叫做读取数据,输出也叫做作写出数据。


二、IO流的分类

2.1 按数据的流向划分

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

🔔以InputStream,Reader结尾

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

🔔 以OutputStream、Writer结尾

2.2 按数据的类型划分

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

🔔以InputStreamOutputStream结尾

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

🔔 以ReaderWriter结尾

2.3 按IO流的角色划分

  • 节点流:可以从 / 向一个特定的地方(节点)读 / 写数据。如FileReader.就是专门向文件读写数据。
  • 处理流/装饰流/包装流:它是在其他IO流基础上,增加功能用的。

🔔 举例:

BufferedInputStream、Buffered0utputStream、BufferedReader、BufferedWriter,给其他IO流增加缓冲功能

InputStreamReader、Outputstreamlriter,给其他IO流转换类型用的,或者给其他IO编码、解码用的

💡小tips:

区分上述三者的依据是看创建它们的对象的方式

如果是处理流,创建调用它们的构造器创建对象时,必须传入另一个IO流对象。

FileInputstream(String name) : 参数不是IO流类型BufferedInputStream(InputStream in): 参数是IO流类型

2.4 小结

可以说,所有的IO流类都有四个基类,四个超类、四个父类,其他的IO流都是从他们演变过来。

如下所示:

字节输入流: Inputstream
字节输出流: Outputstream
字符输入流: Reader
字符输出流: Writer

三、字节流

众所皆知,一切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,而这些二进制数字就是字节,那么传输时一样如此。所以,字节流可以传输任意文件数据。在操作流的时候,我们要时刻明确,无论使用什么样的流对象,底层传输的始终为二进制数据。

3.1 字节输出流【OutputStream】

java.io.OutputStream 抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到目的地。它定义了如下字节输出流的基本共性功能方法。

  • public void write(int b)将指定的字节输出流。虽然参数为int类型四个字节,但是只会保留一个字节的信息写出。
  • public void write(byte[] b)将 b.length字节从指定的字节数组写入此输出流
  • public void write(byte[] b, int off, int len)从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。

💡小tips:

偏移量就是指字节数组中的位序,比如偏移量off为2,就是从位序2开始。

  • public void flush() 刷新此输出流强制任何缓冲的输出字节被写出
  • public void close()关闭此输出流并释放与此流相关联的任何系统资源

💡小tips:当完成流的操作时,必须调用close方法,以释放系统资源。

3.2 FileOutputStream类

java.io.FileOutputStream 类是文件输出流,用于将数据写入文件中。

  • public FileOutputStream(File file):创建文件输出流以写入由指定的 File对象表示的文件。
  • public FileOutputStream(String name): 创建文件输出流以指定的名称写入文件。

代码如下(示例):

@Test
public void test05() throws IOException{
    FileOutputStream fos=new FileOutputStream("1.txt");
    fos.write("生当作人杰".getBytes());
    fos.close();
}

经过以上的演示,每次程序运行,创建输出流对象,都会清空目标文件中的数据。

但是这样有一个问题,我如果还想在1.txt中续写内容,而不是重新创建文件

来写内容。该怎么办?

其实为了应对以上的场景需求,Java撰写了上面构造方法的重载形式。

请看JDK API 文档是这样描述的,如下:

  • public FileOutputStream(File file, boolean append): 创建文件输出流以写入由指定的 File对象表示的文件。
  • public FileOutputStream(String name, boolean append): 创建文件输出流以指定的名称写入文件。

这两个构造方法,参数中都需要传入一个boolean类型的值,true 表示追加数据false 表示清空原有数据。这样创建的输出流对象,就可以指定是否追加续写了。

代码使用演示:

@Test
public void test06() throws IOException{
    //追加
    FileOutputStream fos=new FileOutputStream("1.txt",true);
    fos.write("死亦为鬼雄".getBytes());
    fos.close();
}

🔔 注意:

当你创建一个流对象时,必须传入一个文件路径。如果该文件不存在,会创建该文件。如果有这个文件,会清空这个文件的数据。如果传入的是一个目录,则会报IOException异常。

3.3 字节输入流【InputStream】

java.io.InputStream 抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中。

  • public int read() : 从输入流读取一个字节返回读取的字节值。虽然读取了一个字节,但是会自动提升为int类型。如果已经到达流末尾,没有数据可读,则返回-1。
  • public int read(byte[] b)从输入流中读取一些字节数,并将它们存储到字节数组 b中 。每次最多读取b.length个字节。返回实际读取的字节个数。如果已经到达流末尾,没有数据可读,则返回-1。
  • public int read(byte[] b,int off,int len):从输入流中读取一些字节数,并将它们存储到字节数组 b中,从b[off]开始存储,每次最多读取len个字节 。返回实际读取的字节个数。如果已经到达流末尾,没有数据可读,则返回-1。
  • public void close()关闭此输入流释放与此流相关联的任何系统资源。

💡小tips:当完成流的操作时,必须调用close方法,以释放系统资源。

3.4 FileInputStream类

java.io.FileInputStream 类是文件输入流,从文件中读取字节。

  • FileInputStream(File file): 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的 File对象 file命名。
  • FileInputStream(String name): 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名 name命名。
    代码如下(示例):
@Test
    public void test09()throws IOException{
        // 使用文件名称创建流对象
        FileInputStream fis = new FileInputStream("1.txt");
        // 定义变量,保存数据
        int b;
        // 循环读取
        while ((b = fis.read())!=-1) {
            System.out.println((char)b);
        }
        // 关闭资源
        fis.close();
    }

3.5 复制文件

🌟原理: 从已有的文件读取字节数据,然后写入【字节数据】到另一个文件中

如图所示:

案例:使用一个文件字节流来复制一个视频文件

代码使用演示:

@Test
    public void test07() throws IOException{
        //案例需求:使用一个文件字节流来复制一个视频文件
        //源文件
        FileInputStream fis=new FileInputStream("D:\\BaiduNetdiskDownload\\尚硅谷2022Java\\01-Java基础【完结】\\day0217_JavaSE_第22天资料\\day0217_22video\\day0217_09IO流扩展练习3:复制文件.avi");
        //目标文件
        FileOutputStream fos=new FileOutputStream("day0217_09IO流扩展练习3:复制文件.avi");
        byte[] data=new byte[1024]; //一次读取1KB
        while (true){
            int len=fis.read(data); //从源文件中一次性读取len个字节的数据
            if (len==-1){
                break;
            }
            fos.write(data,0,len);//把本次读到的len个字节写入目标文件中
        }
        fis.close();
        fos.close();
    }


四、字符流

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

💡小tips:

字符流,只能操作文本文件,不能操作图片,视频等非文本文件。

当我们单纯读或者写文本文件时 ,使用字符流; 其他情况使用字节流。

4.1 字符输入流【Reader】

java.io.Reader抽象类是表示用于读取字符流的所有类的超类,可以读取字符信息到内存中。它定义了字符输入流的基本共性功能方法。

  • public int read()从输入流读取一个字符。 虽然读取了一个字符,但是会自动提升为int类型。返回该字符的Unicode编码值。如果已经到达流末尾了,则返回-1。
  • public int read(char[] cbuf)从输入流中读取一些字符,并将它们存储到字符数组 cbuf中 。每次最多读取cbuf.length个字符。返回实际读取的字符个数。如果已经到达流末尾,没有数据可读,则返回-1。
  • public int read(char[] cbuf,int off,int len)从输入流中读取一些字符,并将它们存储到字符数组 cbuf中,从cbuf[off]开始的位置存储。每次最多读取len个字符。返回实际读取的字符个数。如果已经到达流末尾,没有数据可读,则返回-1。
  • public void close()关闭该流释放与此流相关联的任何系统资源

💡小tips:当完成流的操作时,必须调用close方法,以释放系统资源。

4.2 FileReader类

java.io.FileReader 类实现java.io.Reader抽象类,是用来读取字符文件。构造时默认使用系统默认的字符编码和默认字节缓冲区,若另外指定字符编码规则,则另说。

  • FileReader(File file): 创建一个新的 FileReader ,给定要读取的File对象。
  • FileReader(String fileName): 创建一个新的 FileReader ,给定要读取的文件的名称。

💡小tips:

当你创建一个流对象时,必须传入一个文件路径。类似于FileInputStream 。如果该文件不存在,则报FileNotFoundException。如果传入的是一个目录,则会报IOException异常。

代码使用演示:

@Test
public void test01() throws IOException {
    FileReader fr=new FileReader("2.txt");
    char[] data=new char[12];
    int len;
    while ((len=fr.read(data))!=-1){
        System.out.println(new String(data,0,len));
    }
}

4.3 字符输出流【Writer】

java.io.Writer 抽象类是超类,它是所有表示用于写出字符流的类的超类,将指定的字符信息写入到目的文件中。它定义了字节输出流的基本共性功能方法。

  • public void write(int c)写入单个字符
  • public void write(char[] cbuf) 写入字符数组
  • public void write(char[] cbuf, int off, int len) 写入字符数组的某一部分,off数组的开始索引,len写的字符个数。
  • public void write(String str) 写入字符串
  • public void write(String str, int off, int len)写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
  • public void flush() 刷新该流的缓冲
  • public void close()关闭此流,但要先刷新它

4.4 FileWriter类

java.io.FileWriter 类实现了java.io.Writer 抽象类,它是用来写入字符到文件中。构造时使用系统默认的字符编码和默认字节缓冲区。

  • FileWriter(File file): 创建一个新的 FileWriter,给定要读取的File对象。
  • FileWriter(String fileName): 创建一个新的 FileWriter,给定要读取的文件的名称。

💡小tips:

当你创建一个流对象时,必须传入一个文件路径。类似于FileInputStream 。如果该文件不存在,则报FileNotFoundException。如果传入的是一个目录,则会报IOException异常。

代码使用演示:

@Test
public void test02() throws IOException{
    FileWriter fw=new FileWriter("2.txt",true);
    fw.write("。大善");
    fw.close();
}

🔔注意:

FileWriter类也可以像FileOutputStream类一样,在文中续写追加内容,而不用再创建文件写入。

用法和FileOutputStream类一样,这里不做赘述。

4.5 换行问题

代码使用演示:

@Test
    public void test10() throws IOException {
        // 使用文件名称创建流对象,可以续写数据
        FileWriter fw = new FileWriter("f5.txt");
        // 写出字符串
        fw.write("你");
        // 写出换行
        fw.write("\r\n");
        // 写出字符串
        fw.write("好");
        // 关闭资源
        fw.close();
    }

相关文章
|
6月前
|
Java Unix Go
【Java】(8)Stream流、文件File相关操作,IO的含义与运用
Java 为 I/O 提供了强大的而灵活的支持,使其更广泛地应用到文件传输和网络编程中。!但本节讲述最基本的和流与 I/O 相关的功能。我们将通过一个个例子来学习这些功能。
267 2
|
7月前
|
安全 Java API
Java SE 与 Java EE 区别解析及应用场景对比
在Java编程世界中,Java SE(Java Standard Edition)和Java EE(Java Enterprise Edition)是两个重要的平台版本,它们各自有着独特的定位和应用场景。理解它们之间的差异,对于开发者选择合适的技术栈进行项目开发至关重要。
1189 1
|
8月前
|
Java 测试技术 API
Java IO流(二):文件操作与NIO入门
本文详解Java NIO与传统IO的区别与优势,涵盖Path、Files类、Channel、Buffer、Selector等核心概念,深入讲解文件操作、目录遍历、NIO实战及性能优化技巧,适合处理大文件与高并发场景,助力高效IO编程与面试准备。
|
8月前
|
SQL Java 数据库连接
Java IO流(一):字节流与字符流基础
本文全面解析Java IO流,涵盖字节流、字符流及其使用场景,帮助开发者理解IO流分类与用途,掌握文件读写、编码转换、异常处理等核心技术,通过实战案例提升IO编程能力。
|
9月前
|
存储 Java Linux
操作系统层面视角下 Java IO 的演进路径及核心技术变革解析
本文从操作系统层面深入解析Java IO的演进历程,涵盖BIO、NIO、多路复用器及Netty等核心技术。分析各阶段IO模型的原理、优缺点及系统调用机制,探讨Java如何通过底层优化提升并发性能与数据处理效率,全面呈现IO技术的变革路径与发展趋势。
192 2
|
9月前
|
监控 Java API
现代 Java IO 高性能实践从原理到落地的高效实现路径与实战指南
本文深入解析现代Java高性能IO实践,涵盖异步非阻塞IO、操作系统优化、大文件处理、响应式网络编程与数据库访问,结合Netty、Reactor等技术落地高并发应用,助力构建高效可扩展的IO系统。
256 0
|
10月前
|
设计模式 算法 Java
Java SE 与 Java EE 组件封装使用方法及实践指南
本指南详细介绍了Java SE与Java EE的核心技术使用方法及组件封装策略。涵盖集合框架、文件操作、Servlet、JPA、EJB和RESTful API的使用示例,提供通用工具类与基础组件封装建议,如集合工具类、文件工具类、基础Servlet、实体基类和服务基类等。同时,通过分层架构集成示例展示Servlet、EJB和JPA的协同工作,并总结组件封装的最佳实践,包括单一职责原则、接口抽象、依赖注入、事务管理和异常处理等。适合希望提升代码可维护性和扩展性的开发者参考。
320 0
|
存储 网络协议 安全
Java网络编程,多线程,IO流综合小项目一一ChatBoxes
**项目介绍**:本项目实现了一个基于TCP协议的C/S架构控制台聊天室,支持局域网内多客户端同时聊天。用户需注册并登录,用户名唯一,密码格式为字母开头加纯数字。登录后可实时聊天,服务端负责验证用户信息并转发消息。 **项目亮点**: - **C/S架构**:客户端与服务端通过TCP连接通信。 - **多线程**:采用多线程处理多个客户端的并发请求,确保实时交互。 - **IO流**:使用BufferedReader和BufferedWriter进行数据传输,确保高效稳定的通信。 - **线程安全**:通过同步代码块和锁机制保证共享数据的安全性。
568 23
|
缓存 网络协议 Java
JAVA网络IO之NIO/BIO
本文介绍了Java网络编程的基础与历史演进,重点阐述了IO和Socket的概念。Java的IO分为设备和接口两部分,通过流、字节、字符等方式实现与外部的交互。
464 0
|
Java
java 中 IO 流
Java中的IO流是用于处理输入输出操作的机制,主要包括字节流和字符流两大类。字节流以8位字节为单位处理数据,如FileInputStream和FileOutputStream;字符流以16位Unicode字符为单位,如FileReader和FileWriter。这些流提供了读写文件、网络传输等基本功能。
284 10