IO流
综述
javaIO是指java的输入和输出流,用于处理文件网络等设备之间的数据传输。
Java提供了InputStream和OutputStream两个抽象类作为所有输入输出流类的基类,以及Reader和Writer两个抽象类作为所有字符输入输出流类的基类。同时,Java还提供了许多具体的输入输出流类和字符输入输出流类,如FileInputStream、FileOutputStream、BufferedInputStream、BufferedOutputStream、InputStreamReader、OutputStreamWriter等。这些类可用于读取文件、写入数据到文件、从网络中读取数据、向网络中写入数据等常见操作。
输出流:程序 -> 文件
输入流:文件 -> 程序
作用
Java IO流主要用于处理与文件、网络等设备之间的数据传输。其具体作用包括:
从文件中读取数据或将数据写入到文件中
从网络中读取数据或将数据写入到网络中
处理字节数据或字符数据
支持字符串、基本类型、对象等不同类型数据的读取和写入
支持对数据进行缓存,以提高读写性能
实现对文件、目录操作,如创建、删除等
实现序列化和反序列化,使得对象可以在不同系统之间传输和存储
支持压缩和解压缩文件,减小文件大小。
Java IO流为Java程序处理输入输出提供了丰富而灵活的方式,适用于各种场景和应用。
分类
Java IO流可以分为四种类型:字节输入输出流、字符输入输出流、字节缓冲输入输出流和字符缓冲输入输出流。
1、字节输入输出流(InputStream和OutputStream):用于处理读写字节数据,如二进制文件、图片、音频等。
2、字符输入输出流(Reader和Writer):用于处理读写字符数据,如文本文件、网页等。
3、字节缓冲输入输出流(BufferedInputStream和BufferedOutputStream):通过缓存方式提高了字节输入输出流的性能,适用于处理大量的字节数据。
4、字符缓冲输入输出流(BufferedReader和BufferedWriter):通过缓存方式提高了字符输入输出流的性能,适用于处理大量的字符数据。
此外,Java IO流还可以根据不同的来源和目的地进行分类,如:
文件输入输出流(FileInputStream和FileOutputStream):用于读写文件。
管道输入输出流(PipedInputStream和PipedOutputStream):用于线程间的数据传输。
套接字输入输出流(SocketInputStream和SocketOutputStream):用于与其他计算机上的程序进行通信。
标准输入输出流(System.in和System.out):用于控制台输入输出。
IO流的体系
字节流
字节输入流(InputStream)
FileInputStream
使用字节输入流可以读取本地文件中的数据并加载到程序中进行操作。
方法 | 说明 |
public int read() | 一次读一个字节数据 |
public int read(byte[] buffer) | 一次读一个字节数组数据 |
创建字节输入流细节:
如果文件不存在,使用字节输入流会抛出异常并报错。
读取数据细节:
使用字节输入流每次可以读取一个字节,并将该字节转换为其对应的ASCII码值。
当使用字节输入流读取文件时,当读取到文件末尾时,read()方法将返回-1。
释放资源细节:
为了避免持续占用资源,每次使用输入流或输出流后都应该释放其对应的资源。
字节输出流(OutputStream)
FileOutputStream
使用字节输出流可以将程序中的数据写入到本地文件中。
创建字节输出流对象细节:
参数是字符串表示的路径或者是File对象。
如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的。
如果文件已经存在,则会清空文件。
写入数据细节:
字节输出流中的write()方法参数为整数,但实际上在文件中写入的是该整数所对应的ASCII字符。
释放资源细节:
为了避免持续占用资源,每次使用输入流或输出流后都应该释放其对应的资源。
换行细节:
在Windows操作系统中,Java对回车换行进行了优化。尽管完整的换行符为\r\n,但只需使用其中一个\r或\n也可以实现换行,因为Java会在底层自动补全缺少的字符。
文件拷贝功能
为了避免覆盖先前读取操作的内容,重要的是指定从输入流中读取的字节数长度。如果未指定长度,则可能在字节数组中存在来自上一次读取操作的残留内容,如果字节数组没有被最近的读取操作完全填满,则在下一个写入操作期间会导致意外数据被写入。
该代码通过创建一个字节数组作为缓冲区来提高读写效率,先通过FileInputStream对象读取input.txt文件内容到缓冲区中,再通过FileOutputStream对象将缓冲区中的数据写入到output.txt文件中。最后关闭输入输出流并输出复制成功消息。
字符流
字符输入流(Reader)
字符输入流(Reader)是Java IO流体系中的一个抽象类,用于读取字符数据。它是所有字符输入流类的基类,提供了一些常用的读取字符的方法,如read()和readLine()等。
与字节输入流不同,字符输入流处理的是字符数据,以字符形式进行读写操作。InputStream对象每次读取一个字节,而Reader对象则每次读取一个字符,因此如果需要处理文本文件或其他字符数据,应该使用字符输入流来读取数据。
Java IO流中还提供了许多具体的字符输入流类,如FileReader、InputStreamReader、BufferedReader等,这些类可以根据不同的需求和场景提供更加丰富和灵活的字符输入流读取方式。
FileReader
方法 | 说明 |
public int read() | 读取数据,读到末尾返回-1 |
public int read(char[] cbuf) | 读取多个数据,读到末尾返回-1 |
read()细节:
字符流的底层也是字节流,默认是一个字节一个字节的读取,当字符流遇到中文字符时,会读取多个字节。这是因为中文字符在计算机内部以多个字节的形式表示。
在读取之后,方法底层还是会进行解码并转成十进制。
read(char[] cbuf)细节:
此方法是将数据读取、解码和强转三个步骤合并,并在完成强转后才将字符放入数组中。
原理解析
1、创建字符输入流对象
底层会关联文件,并创建缓冲区(长度8192的字节数组)
2、读取数据
底层会优先检查缓冲区是否有可读数据,若没有,则会从文件中读取数据并填充到缓冲区中,每次尽可能填满缓冲区。如果文件中也没有数据可读,则返回-1。如果缓冲区内有数据可读,则直接从缓冲区读取,而不需要再去文件中获取数据。
字符输出流(Writer)
字符输出流(Writer)是Java IO流体系中的一个抽象类,用于写入字符数据。它是所有字符输出流类的基类,提供了一些常用的写入字符的方法,如write()和flush()等。
与字节输出流不同,字符输出流处理的是字符数据,以字符形式进行读写操作。OutputStream对象每次写入一个字节,而Writer对象则每次写入一个字符,因此如果需要处理文本文件或其他字符数据,应该使用字符输出流来写入数据。
Java IO流中还提供了许多具体的字符输出流类,如FileWriter、OutputStreamWriter、BufferedWriter等,这些类可以根据不同的需求和场景提供更加丰富和灵活的字符输出流写入方式。
FileWiter
方法 | 说明 |
void write(int c) | 写出一个字符 |
void write(String str) | 写出一个字符串 |
void write(String str, int off, int len) | 写出一个字符串一部分 |
void write(char[] cbuf) | 写出一个字符数组 |
void write(char[] cbuf, int off, int len) | 写出字符数组一部分 |
public void flush() | 将缓冲区的数据,刷新到本地文件中 |
public void close() | 释放资源/关流 |
原理解析
1、创建字符输出流对象:首先需要创建一个字符输出流对象,该对象通常与一个底层的输出设备或文件相关联。
2、写入数据到缓冲区:当开始使用字符输出流写入数据时,数据通常被先写入到一个内部的缓冲区中。这样做可以提高写入性能,因为每次写操作都会导致底层设备或文件的IO操作。
3、刷新缓冲区:当缓冲区满了或者需要强制将缓冲区的所有内容写入到底层设备或文件时,需要调用flush()方法刷新缓冲区。此时,内存缓冲区中的所有数据都将被写入到目标设备或文件中。
4、关闭流:最后,当不再需要写入数据时,需要关闭字符输出流。这个操作将清空缓冲区并释放任何系统资源。
总之,字符输出流工作原理的核心是采用缓冲区技术来提高写入性能,并允许操作者控制何时将数据写入物理设备。
编码与解码
编码的方法
方法 | 说明 |
public byte[] getBytes() | 使用默认方式进行编码 |
public byte[] getBytes(String charsetName) | 使用指定方式进行编码 |
![](https://img-blog.csdnimg.cn/direct/22ce6f927a334c33b9d73a66d26e5390.png)
解码的方法
方法 | 说明 |
String(byte[] bytes) | 使用默认方式进行解码 |
String(byte[] bytes, String charsetName) | 使用指定方式进行解码 |
![](https://img-blog.csdnimg.cn/direct/ec12aa62a59e42baa022db0b7faca133.png)
案例
拷贝文件夹
文件加密
缓冲流
字节缓冲流
字节缓冲流是Java中用于处理字节数据的一种输入输出流,它可以提供高效的读写操作。字节缓冲流内部维护了一个缓冲区,读写时先将数据存入缓冲区中,当缓冲区满时再将数据一次性写入或者读取出来,这样可以减少实际的I/O操作次数,提高读写操作的效率。Java中的字节缓冲流有两种类型:BufferedInputStream和BufferedOutputStream。
其中BufferedInputStream可以从另一个输入流中读取数据,并将其存储在内部缓冲区中,而BufferedOutputStream则可以将数据写入另一个输出流中,并将其存储在内部缓冲区中,直到缓冲区被填满或者调用了flush()方法才会将数据真正写入输出流中。
底层自带了长度为8192的字节数组缓冲区提高性能
BufferedInputStream
方法 | 说明 |
public BufferedInputStream (InputStream is) | 把基本流包装成高级流,提高读取数据的性 |
BufferedOutputStream
方法 | 说明 |
public BufferedInputStream (OutputStream os) | 把基本流包装成高级流,提高写出数据的性能 |
利用字节缓冲流拷贝文件
字符缓冲流
字符缓冲流是Java I/O中的一种流,用于处理字符数据。它继承自Reader和Writer类,可以以缓冲方式读写字符数据,提高输入输出的效率。
与普通的Reader和Writer相比,字符缓冲流具有以下特点:
使用内部缓冲区,可以减少IO操作的次数,提高输入输出效率。
可以指定缓冲区大小,以适应不同的应用场景。
读取和写入的字符数据是以行为单位进行的,方便对文本文件进行处理。
支持mark和reset操作,方便在读取和写入过程中回到之前的位置。
可以与其他字符流和字节流组合使用,方便进行转换和处理。
常用的字符缓冲流有BufferedReader和BufferedWriter。其中,BufferedReader主要用于从字符输入流中读取文本数据,而BufferedWriter则用于向字符输出流中写入文本数据。
底层自带了长度为8192的字符数组缓冲区提高性能,一个字符为2个字节
BufferedReader
方法 | 说明 |
public BufferedReader (Reader r) | 把基本流包装成高级流 |
public String readLine() | 读取一行数据,如果没有数据可读了,会返回null |
![](https://img-blog.csdnimg.cn/direct/1343ec83f884472ea840971ef3052b7d.png)
BufferedWriter
方法 | 说明 |
public BufferedWriter (Reader r) | 把基本流包装成高级流 |
public String newLine() | 跨平台的换行 |
转换流
Java转换流是Java I/O库中的一种流,在字节流和字符流之间进行转换。它主要用于处理字符数据与字节数据之间的转换,是Reader和Writer类的一种包装。转换流可以将字节流转换为字符流,也可以将字符流转换为字节流。
转换流有两种类型:InputStreamReader和OutputStreamWriter。其中,InputStreamReader用于将字节输入流转换为字符输入流,而OutputStreamWriter则用于将字符输出流转换为字节输出流。转换时,需要指定字符编码,例如UTF-8或GBK等。
使用转换流的主要优点是可以同时处理字节流和字符流,并且可以在不同编码方式之间转换数据,方便进行跨平台开发和国际化处理。常见的应用场景包括读取和写入文本文件、处理网络数据和操作数据库等。
读取数据
FileReader为JDK11后的InputStreamReader替代方案
写入数据
FileWriter fw = new FileWriter("文件所在路径", Charset.forName("GBK"));
案例
序列化流
Java序列化流是Java I/O库中的一种流,用于将对象转换为字节流以便进行存储或传输。序列化流可以将一个包含数据的对象转换为二进制格式的字节数组,方便在网络上进行传输或者在文件中进行存储。
使用序列化流的主要优点是方便实现对象的持久化,即在程序结束后仍然能够保留对象状态和数据。同时,序列化流还可以用于实现远程方法调用(RMI)和分布式应用程序等。
Java提供了两个主要的序列化流:ObjectInputStream和ObjectOutputStream。其中,ObjectOutputStream用于将对象写入输出流中,而ObjectInputStream则用于从输入流中读取对象。在使用这些流时,需要注意对象必须实现Serializable接口,否则会抛出NotSerializableException异常。
![](https://img-blog.csdnimg.cn/direct/32041c1a4e9c4872b55a274d150aa9ed.png)
细节
使用序列化流将对象写到文件时,需要让Javabean类实现Serializable接口。否则,会出现NotSerializableException异常。
序列化流写到文件中的数据是不能修改的,一旦修改就无法再次读回来了。
序列化对象后,修改了Javabean类,再次反序列化,会抛出InvalidClassException异常。解决方案:给JavaBean类添加serialVersionUID(序列号、版本号)。
一个对象中的某个成员变量的值不想被序列化。解决方案:给该成员变量加transient关键字修饰,该关键字标记的成员变量不参与序列化过程。
读写多个对象
![](https://img-blog.csdnimg.cn/direct/b027a7ff9b7f472ca1081c9dbe4cd15f.png)
打印流
字节打印流
Java字节打印流是Java I/O库中的一种流,它可以将数据转换为字节,并输出到指定输出流中。字节打印流主要用于向文件或网络等数据通道写入文本或二进制数据。
Java提供了两种主要的字节打印流:PrintStream和PrintWriter。其中,PrintStream是处理字节流的打印流,而PrintWriter则是处理字符流的打印流。
使用字节打印流的主要优点是简化了输出操作,可以直接输出各种类型的数据,包括字符串、整数、浮点数等,同时可以自动进行格式化。另外,字节打印流还提供了一些特殊功能,例如自动刷新、自定义分隔符等。
需要注意的是,在使用字节打印流时,必须显式指定输出流对象,否则会抛出NullPointerException异常。同时,在使用完毕后,需要关闭打印流。
字节流底层没有缓冲区,开不开自动刷新都一样
![](https://img-blog.csdnimg.cn/direct/503de1e72e7c4fbba34672cd9ff60021.png)
字符打印流
Java字符打印流是Java I/O库中的一种流,它可以将数据转换为字符,并输出到指定输出流中。字符打印流主要用于向文件或网络等数据通道写入文本或字符数据。
Java提供了两种主要的字符打印流:PrintWriter和PrintStream。其中,PrintWriter是处理字符流的打印流,而PrintStream则是处理字节流的打印流。
使用字符打印流的主要优点是简化了输出操作,可以直接输出各种类型的数据,包括字符串、整数、浮点数等,同时可以自动进行格式化。另外,字符打印流还提供了一些特殊功能,例如自动刷新、自定义分隔符等。
需要注意的是,在使用字符打印流时,必须显式指定输出流对象,否则会抛出NullPointerException异常。同时,在使用完毕后,需要关闭打印流。
字符流底层有缓冲区,想要自动刷新需要开启
![](https://img-blog.csdnimg.cn/direct/150c25074d954198a6f12d63047fb83c.png)
压缩流
解压缩流
Java解压缩流是Java I/O库中的一种流,用于解压已经压缩过的数据。可以使用解压缩流来读取压缩文件,并将其中的数据解压缩后输出到目标数据通道中。
Java提供了两种主要的解压缩流:InflaterInputStream和GZIPInputStream。其中,InflaterInputStream是通用的解压缩流,可以处理各种常见的压缩格式,例如Zip、Gzip、Deflate等;而GZIPInputStream则专门用于处理Gzip压缩格式。
使用解压缩流的主要优点是简化了解压缩操作,可以直接从压缩文件中读取数据,同时可以自动进行解压缩。另外,解压缩流还提供了一些特殊功能,例如自动跳过头部信息、自定义缓冲区大小等。
需要注意的是,在使用解压缩流时,必须显式指定输入流对象,否则会抛出NullPointerException异常。同时,在使用完毕后,需要关闭流。
压缩流
Java压缩流是Java I/O库中的一种流,用于将数据压缩为指定格式并输出到目标数据通道中。可以使用压缩流来创建压缩文件,并将其中的数据压缩后输出到目标数据通道中。
Java提供了两种主要的压缩流:DeflaterOutputStream和GZIPOutputStream。其中,DeflaterOutputStream是通用的压缩流,可以处理各种常见的压缩格式,例如Zip、Gzip、Deflate等;而GZIPOutputStream则专门用于处理Gzip压缩格式。
使用压缩流的主要优点是简化了压缩操作,可以直接将数据写入压缩文件中,同时可以自动进行压缩。另外,压缩流还提供了一些特殊功能,例如自定义缓冲区大小、设置压缩级别等。
需要注意的是,在使用压缩流时,必须显式指定输出流对象,否则会抛出NullPointerException异常。同时,在使用完毕后,需要关闭流。
工具包
Commons-io
Commons-io是一个开源的Java库,提供了一系列实用类和方法,用于处理常见的输入输出(I/O)操作。这个库可以大大简化I/O编程任务,例如读写文件、拷贝文件、处理字节和字符流等。Commons-io还提供了许多方便的工具方法,例如比较文件内容、查找文件、解析URL等。它是Apache Commons项目的一部分,可以被广泛应用于Java开发中。
Commons-io提供了众多实用方法,下面列举其中一些常用的方法:
FileUtils类:提供了许多操作文件的方法,如读写文件、拷贝文件、删除文件等。
IOUtils类:提供了处理输入输出流的方法,如复制输入流到输出流、关闭流等。
FilenameUtils类:提供了处理文件名和路径的方法,如获取文件扩展名、合并路径、规范化路径等。
FileSystemUtils类:提供了操作文件系统的方法,如获取磁盘空间大小、检查是否支持符号链接等。
DigestUtils类:提供了生成消息摘要的方法,如MD5、SHA等。
这些方法都提供了高度的可定制性和灵活性,可以满足不同场景的需求。
Hutool
Hutool是一个开源的Java工具库,提供了丰富的工具类和方法,包括字符串处理、日期时间处理、文件操作、加密解密、网络请求、XML/JSON解析等常见功能。Hutool致力于简化Java开发过程中的常用操作,提高开发效率。它的设计理念是易用、可靠、高效,并且提供了简洁易懂的API文档和示例代码,方便开发者上手使用。Hutool也是国内比较受欢迎的Java工具库之一。
Hutool提供了众多实用方法,下面列举其中一些常用的方法:
StrUtil类:提供了许多字符串处理方法,如判空、拼接、格式化等。
DateUtil类:提供了日期时间处理方法,如格式化、计算、转换等。
FileUtil类:提供了文件操作方法,如读写文件、复制文件、删除文件等。
EncryptUtil类:提供了加密解密方法,如MD5、SHA、AES等。
HttpUtil类:提供了网络请求方法,如Get、Post、上传下载文件等。
JSONUtil类:提供了JSON解析方法,如对象序列化、JSON字符串转对象等。
这些方法都提供了高度的可定制性和灵活性,可以满足不同场景的需求。Hutool还提供了其他许多实用的工具类和方法,包括集合操作、XML解析、正则表达式等,可以大大简化Java开发过程中的编码工作。