java IO流

什么是IO流

  • I/O 即输入Input/ 输出Output的缩写,其实就是计算机调度把各个存储中(包括内存和外部存储)的数据写入写出的过程:标准输入输出,文件的操作,网络上的数据传输流,字符串流,对象流等等等。
  • java中用“流(stream)”来抽象表示这么一个写入写出的功能,封装成一个“类”,都放在java.io这个包里面。

IO流的分类

流的方向:

  • 输入流:数据源到程序(InputStream、Reader读进来)
  • 输出流:程序到目的地(OutPutStream、Writer写出去)

处理数据单元:

  • 字节流:按照字节读取数据(InputStream、OutputStream)
  • 字符流:按照字符读取数据(Reader、Writer)

功能不同:

  • 节点流:可以直接从数据源或目的地读写数据。
  • 处理流:不直接连接到数据源或目的地,是处理流的流。通过对其他流的处理提高程序的性能。

流的三要素

数据源

data source. 提供原始数据的原始媒介。常见的:数据库、文件、其他程序、内存、网络连接、IO设备。

目的地

数据的存放位置的原始媒介,常见的:数据库、文件、其他程序、内存、网络连接、IO设备。

交通工具

无论是输入流还是输出流,都必须选择一种流来处理数据,不同的流具备不同的效率,不同的特点,我们可以根据不同的需求选择不同的流工具,Java针对流提供了一套IO流框架。

字节输出流

OutputStream

此抽象类是表示输出字节流的所有类的超类。输出流接受输出字节并将这些字节发送到某个接收器。

方法

void close() 关闭此输出流并释放与此流有关的所有系统资源。

void flush() 刷新此输出流并强制写出所有缓冲的输出字节。

void write(byte[] b) 将 b.length 个字节从指定的 byte 数组写入此输出流。

void write(byte[] b, int off, int len) 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。

abstract void write(int b) 将指定的字节写入此输出流。

注意事项

追加写入利用FileOutputStream的带boolean append参数的构造器

notepad不能够识别/n这个换行符但是一般的编辑器可以,原因是notepad是Windows自带

Windows \r\n

Linux \n

Mac \r

字节流处理换行符字符不方便,后期会有字符流

IO编程需要加入异常处理,并且需要在finally中释放资源

字节输入流

InputStream

此抽象类是表示字节输入流的所有类的超类。InputSteam是一个抽象类,它不可以实例化。数据的读取需要由它的子类来实现。根据节点的不同,它派生了不同的节点流子类。

继承自InputSteam的流都是用于向程序中输入数据,且数据的单位为字节(8 bit);下图中深色为节点流,浅色为处理流。

相关方法

  • int available() 返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。

available作用

available() 方法在某些情况下很有用,尤其是当你需要知道输入流中有多少字节可供读取时。虽然它的返回值只是一个估计值,但在某些情况下它仍然很有用,比如:

  1. 了解数据量: 在处理输入流之前,你可能想知道有多少数据可用。例如,在网络编程中,你可能想了解网络套接字中的数据量,以便适当地处理它们。
  2. 调整缓冲区大小: 如果你知道了输入流中可用的字节数,就可以更好地确定适当的缓冲区大小。这对于高效地读取和处理数据是很重要的。如果你的缓冲区太小,可能需要多次读取来完全处理可用的数据,而如果它太大,可能会浪费内存。
  3. 避免阻塞: 在一些情况下,你可能希望检查输入流中是否有足够的数据可用,以避免在调用读取方法时发生阻塞。通过先调用available()方法,你可以在没有足够数据时选择等待,或者做一些其他的处理。

需要注意的是,available() 方法返回的是一个估计值,并不总是准确的。因此,在使用它时,你应该小心处理,并且不要完全依赖它的返回值。

  • void close() 关闭此输入流并释放与该流关联的所有系统资源。
  • void mark(int readlimit) 在此输入流中标记当前的位置。
  • boolean markSupported() 测试此输入流是否支持 mark 和 reset 方法。
  • void reset() 将此流重新定位到最后一次对此输入流调用 mark 方法时的位置。
  • long skip(long n) 跳过和丢弃此输入流中数据的 n 个字节。
  • abstract int read() 从输入流中读取数据的下一个字节。
  • int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
  • int read(byte[] b, int off, int len) 将输入流中最多 len 个数据字节读入 byte 数组。

注意事项

如果输入流文件不存在,会抛出异常

read()方法的特点

a. 文件每次读取一个字节,读取一个字节之后会自动将文件指针向后移动一个字节单位

b. 文件读取后返回的实际读取的字节内容

c. 读取到文件末尾返回-1

异常处理

InputStream和OutputStream都继承自Closeable > AutoCloseable(拥有close方法)

所以使用可变参数实现一个方法

private static void closeAll(AutoCloseable... resources) {
        try {
            if (Objects.nonNull(resources)) {
                for (AutoCloseable resource : resources) {
                    if (Objects.nonNull(resource)) {
                        resource.close();
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

jdk1.7后可以使用新语法

try(resources) {
    // ...
}

会自动关闭资源

FileOutputStream和FileInputStream

补充

new FileOutputStream(File file,Boolean append)

append表示是否开启追加,默认是覆盖

BufferedOutputStream和BufferedInputStream

功能:提高读写效率

实现:缓冲区8192

BufferedOut/InputStream 具有缓冲功能,它会将数据先写入到内存缓冲区中,并在缓冲区满或调用 flush() 方法时将数据批量地写入到底层的输出流中。这样可以减少实际的 I/O 操作次数,提高写入数据的效率。

字符输入流

Writer

写入字符流的抽象类。子类必须实现的方法仅有write(char[], int, int)、flush() 和 close()。但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能。

常用方法

Writer append(char c) 将指定字符添加到此 writer。

Writer append(CharSequence csq) 将指定字符序列添加到此 writer。

Writer append(CharSequence csq, int start, int end) 将指定字符序列的子序列添加到此 writer.Appendable。

abstract void close() 关闭此流,但要先刷新它。

abstract void flush() 刷新该流的缓冲。

void write(char[] cbuf) 写入字符数组。

abstract void write(char[] cbuf, int off, int len) 写入字符数组的某一部分。

void write(int c) 写入单个字符。

void write(String str) 写入字符串。

void write(String str, int off, int len) 写入字符串的某一部分。

字符输出流

Reader

用于读取字符流的抽象类。子类必须实现的方法只有read(char[], int, int) 和 close()。但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能。

常用方法

abstract void close() 关闭该流并释放与之关联的所有资源。

void mark(int readAheadLimit) 标记流中的当前位置。

boolean markSupported() 判断此流是否支持 mark() 操作。

int read() 读取单个字符。

int read(char[] cbuf) 将字符读入数组。

abstract int read(char[] cbuf, int off, int len) 将字符读入数组的某一部分。

int read(CharBuffer target) 试图将字符读入指定的字符缓冲区。

boolean ready() 判断是否准备读取此流。

void reset() 重置该流。

long skip(long n) 跳过字符。

转换流InputStreamReader和OutputStreamWriter

例如:网络中传输的只能是字节流,但是程序处理需要使用字符流时

文件字符流FileReader和FileWrter

和文件字节字节流类似

高效字符流BufferedReader和BufferedWriter

和BufferedOutputStream类似

IO流核心框架总结

字节流: 万能流,既能够处理二进制文件也能够处理文本文件,但是处理文本文件不是很方便,可以通过转换流转换成字符流

InputStream 抽象类

读一个字节

读一个字节数组

读一个字节数组的一部分

FileInputStream

1.能够读文件

FiterInputStream

1.没有扩展的功能

2.但是是一个普通类,可以直接使用,但是需要通过构造方法传入一个字节流

BufferedInputStream

1.提高了字节输入流的效率

BufferedInputStream(InputStream in)

BufferedInputStream(InputStream in, int size)

OutputStream 抽象类

写一个字节

写一个字节数组

写一个字节数组的一部分

FileOutputStream

1.能够写文件

2.能够追加写入

FiterOutputStream

1.没有扩展的功能

2.但是是一个普通类,可以直接使用,但是需要通过构造方法传入一个字节流

BufferedOutputStream

1.提高了字节输出流的效率

BufferedOutputStream(OutputStream out)

BufferedOutputStream(OutputStream out, int size)

字符流

Reader 【抽象类】

读一个字字符

读一个字符数组

读一个字符数组的一部分

InputStreamReader

1.能够将字节流转换成字符流

InputStreamReader(InputStream in)

2.处理编码问题

InputStreamReader(InputStream in, String charsetName)

3.能够具备字符流的功能

FileReader

1.能够读文件

BufferedReader

1.能够读一行

2.提高字符输入流的效率

Writer 【抽象类】

写一个字节

写一个字节数组

写一个字节数组的一部分

写一组字符串

写一组字符串的一部分

追加写入一组字符序列

追加写一组字符序列的一部分

OutputStreamWriter

1.能够将字节流转换成字符流

OutputStreamWriter(OutputStream in)

2.处理编码问题

OutputStreamWriter(OutputStream in, String charsetName)

3.能够具备字符流的功能

FileWriter

1.能够写文件

BufferedWriter

1.能够写是适配操作系统的换行符

2.能够提高字符输出流的效率

十万个为什么

什么是比特(Bit),什么是字节(Byte),什么是字符(Char),它们长度是多少,各有什么区别?

Bit最小的二进制单位 ,是计算机的操作部分取值0或者1。

Byte是计算机中存储数据的单元,是一个8位的二进制数,(计算机内部,一个字节可表示一个英文字母,两个字节可表示一个汉字。) 取值(-128-127)

Char是用户的可读写的最小单位,他只是抽象意义上的一个符号。如‘5’,‘中’,‘¥’等等。在java里面由16位bit组成Char 取值(0-65535)

Bit 是最小单位 计算机他只能认识0或者1

Byte是8个字节 是给计算机看的

字符 是看到的东西 一个字符=二个字节

DataInputStream和DataOutputStream

之前学习的核心流框架只能够读写字节和字符,接下来我们可以学习一套可以读写基本数据类型的流,它们就是DataInputStream和DataOutputStream,基本数据类型输入输出流

特点

  • 读写字节数据
  • 能够读写基本数据类型
  • 使用该流写入基本数据类型到文件中实现数据的持久化,提高了数据的安全性
  • 使用该流读取文件中数据一定要按照写入的类型顺序对应才能够成功读取

序列化流和反序列化流ObjectInputStream和ObjectOutputStream

概述

Java是面向对象语言,万事万物皆对象,如果我们想要将对象持久化写入到本地或者在网络中传输,我们可以使用序列化流和反序列化流

特点

字节流读写文件的功能

能够读写引用数据类型,即读写对象

需要写入到文件的对象需要该对象的类实现Serializable,否则会抛出异常

如果不希望对象的某个成员写入到文件,保障成员的安全性,可以使用transient关键字修饰。

java中的transient关键字详解_transient关键字作用-CSDN博客

PrintStream和PrintWriter 打印流

概述

该流只有输出流没有输入流,可以向外界输出数据的流,该流又称为万能输出流,顾名思义,该类的功能具备了所有输出流的功能,非常全面方便的流。

特点

  • 打印流只有输出流没有输入流
  • 具备读写文件的功能
  • 具备处理编码的功能
  • 具备装饰任意字节流的功能
  • 自动刷新, 自动帮助我们flush
  • 能够追加写入
  • 能够格式化输出
  • 能够写出任意类型包括基本数据类型和引用数据类型,这里写入到文件是看得懂的
  • 带换行输出,可以适配不同的操作系统
  • 具备装饰任意字符流流的功能
  • 能够格式化输出
  • 能够将字节流转换成字符流的功能

常用方法

PrintStream

  • PrintStream(File file) 创建具有指定文件且不带自动行刷新的新打印流。
  • PrintStream(File file, String csn) 创建具有指定文件名称和字符集且不带自动行刷新的新打印流。
  • PrintStream(OutputStream out) 创建新的打印流。
  • PrintStream(OutputStream out, boolean autoFlush) 创建新的打印流。
  • PrintStream(OutputStream out, boolean autoFlush, String encoding) 创建新的打印流。
  • PrintStream(String fileName) 创建具有指定文件名称且不带自动行刷新的新打印流。
  • PrintStream(String fileName, String csn) 创建具有指定文件名称和字符集且不带自动行刷新的新打印流。

PrintWriter

  • PrintWriter(File file) 使用指定文件创建不具有自动行刷新的新 PrintWriter。
  • PrintWriter(File file, String csn) 创建具有指定文件和字符集且不带自动刷行新的新 PrintWriter。
  • PrintWriter(OutputStream out) 根据现有的 OutputStream 创建不带自动行刷新的新 PrintWriter。
  • PrintWriter(OutputStream out, boolean autoFlush)通过现有的 OutputStream 创建新的 PrintWriter。
  • PrintWriter(String fileName) 创建具有指定文件名称且不带自动行刷新的新 PrintWriter。
  • PrintWriter(String fileName, String csn) 创建具有指定文件名称和字符集且不带自动行刷新的新 PrintWriter。
  • PrintWriter(Writer out) 创建不带自动行刷新的新 PrintWriter。
  • PrintWriter(Writer out, boolean autoFlush) 创建新 PrintWriter。

系统输入输出流

概述

System类中的静态变量:in,out 。

"标准"输入流:static InputStream in 。

"标准"输出流:static PrintStream out 。

它们各代表了系统标准的输入和输出设备。

默认输入设备是键盘,输出设备是显示器。

系统输入流本质是一个字节输入流InputStream,系统输出流本质是一个PrintStream

RandomAccessFile 随机访问文件

概述

此类的实例支持对随机访问文件的读取和写入。随机访问文件的行为类似存储在文件系统中的一个大型byte 数组。存在指向该隐含数组的光标或索引,称为文件指针;输入操作从文件指针开始读取字节,并随着对字节的读取而前移此文件指针。如果随机访问文件以读取/写入模式创建,则输出操作也可用;输出操作从文件指针开始写入字节,并随着对字节的写入而前移此文件指针。写入隐含数组的当前末尾之后的输出操作导致该数组扩展。该文件指针可以通过 getFilePointer 方法读取,并通过seek 方法设置。

特点

  • RandomAccessFile 类不属于流,是Object类的子类。
  • 包含了InputStream和OutputStream的功能。支持字节输入输出流的功能。
  • 支持对随机访问文件的读取和写入getFilePointer + seek
  • length() 可以获取文件长度, setLength() 可以轻松实现文件的覆盖或者设置文件长度

readLine() 方法,实际上是一个循环读取字节,然后根据字节的值构造字符,直到遇到换行符(\n)、回车符(\r')、回车换行符(\r\n')或者文件结束为止。
这个方法的实现逻辑如下:
首先,创建一个 StringBuilder 对象用于存储读取到的字符序列。
然后,循环读取字节,直到遇到换行符或文件结束。在循环中,首先判断读取到的字节的值:
如果读取到的是回车符(\r),则将其判断为换行符,并且检查后面是否紧跟着一个换行符(\n),如果是,则忽略;否则,需要回退一个字节。
如果读取到的是换行符(\n'),则认为已经到达行尾。
如果读取到的是文件结束标志(-1),则表示文件已经读取完毕。
其他情况下,将读取到的字节转换为字符,并添加到 StringBuilder 对象中。
最后,返回 StringBuilder 中的字符串,即一行文本数据。
需要注意的是!!!,该方法并不支持完整的 Unicode 字符集,因为它将每个字节的值作为字符的低八位,然后将字符的高八位设为零。这意味着,只能支持 ASCII 字符集或者使用单字节编码的字符集

Properties集合

概述

Properties 类表示了一个持久的属性集。Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。一个属性列表可包含另一个属性列表作为它的“默认值,如果未能在原有的属性列表中搜索到属性键,则搜索第二个属性列表。

特点

  • Properties可以当做Map集合类使用
  • 使用Properties当做属性集合使用,结合Properties特殊的方法
    • public Object setProperty(String key,String value)
    • public String getProperty(String key)
    • public Set<String> stringPropertyNames()
  • Properties和IO流结合使用
    • public void load(Reader reader)
    • public void store(Writer writer,String comments)

内存字节流ByteArrayInputStream和ByteArrayOutputStream

概述

(经常用在需要流和数组之间转化的情况!)

ByteArrayInputStream 包含一个内部缓冲区,该缓冲区包含从流中读取的字节。内部计数器跟踪 read 方法要提供的下一个字节。

说白了,FileInputStream是把文件当做数据源。ByteArrayInputStream则是把内存中的某个数组当做数据源。

ByteArrayOutputStream类实现了一个输出流,其中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。可使用 toByteArray() 和 toString() 获取数据。 ByteArrayOutputStream将一个输出流指向一个Byte数组,但这个Byte数组是ByteArrayOutputStream内部内置的,不需要我们来定义。

注:不需要关闭流的,但是调用close也没有问题,close不做任何事情。因为ByteArrayOutputStream本身操作的是数组,并没有打开文件描述符之类的,所以不需要关闭。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值