IO流简介
IO即Input/Output
,IO是实现输入和输出的基础,可以方便的实现数据的输入和输出。
- 将数据输出到外部存储的过程叫数据输出。
- 将数据输入到计算机内存的过程叫数据输入。
IO流的分类
按照不同的分类方式,可以把流分为不同的类型。常用的分类有三种:
- 按照流的流向分,可以分为输入流和输出流。
- 输入流: 只能从中读取数据,而不能向其写入数据。
- 输出流:只能向其写入数据,而不能向其读取数据。
- 按操作单元划分,可以分为字符流和字节流。
- 按流的角色划分可以分为节点流和处理流。
字节输入输出流
字节输入流(InputStream)常用方法
read
:返回输入流下一个节点的数据。返回的值介于0
到255
之间。如果未读取到数据,则代码返回-1
,表示文件结束。read(byte b[])
:从输入流中读取一些字节存储到数组b中,从零开始读取,最多读取到数组b的长度。read(byte b[], int off, int len)
:读取一些字节存储到数组b中,从off
位读取到len
位skip(long n)
:忽略输入流中的n个字节,返回实际忽略的字节数。available()
:返回输入流中可以读取的字节数。close()
:关闭输入流释放相关的系统资源。
字节输出流(OutStream)常用方法
write(int b)
:将特定字节写入输出流。write(byte b[ ])
: 将b数组的内容写到输出流中。write(byte[] b, int off, int len)
: 将b数组中从off到off+len的内容写到输出流中。flush()
:刷新此输出流并强制写出所有缓冲的输出字节。close()
:关闭输出流释放相关的系统资源。
数据流
DataInputStream
用于读取指定类型数据,不能单独使用,必须结合 FileInputStream
,注意格式必须严格准守,例如:
/**
* 注意读写顺序必须保持一致
*
*/
public static void main(String[] args) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream("file.txt");
DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream);
dataOutputStream.writeBoolean(true);
dataOutputStream.writeInt(9527);
dataOutputStream.writeShort(2);
dataOutputStream.writeDouble(9.527);
FileInputStream fileInputStream = new FileInputStream("file.txt");
DataInputStream dataInputStream = new DataInputStream(fileInputStream);
System.out.println(dataInputStream.readBoolean());
System.out.println(dataInputStream.readInt());
System.out.println(dataInputStream.readShort());
System.out.println(dataInputStream.readDouble());
}
对象流
ObjectInputStream
用于将文件内容反序列化,ObjectOutputStream
用于将对象写入文件中(序列化)
public static void main(String[] args) throws IOException {
Person person = new Person();
person.setName("Zayton Squid");
person.setAge(25);
person.setSex("male");
person.setArea("shenzhen");
ObjectOutputStream oos = new ObjectOutputStream(Files.newOutputStream(Paths.get("file.txt")));
oos.writeObject(person);
System.out.println(person);
try (ObjectInputStream ois = new ObjectInputStream(Files.newInputStream(Paths.get("file.txt")))) {
Person person1 = (Person) ois.readObject();
System.out.println(person1);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
字符流
字符流是由JVM将字节流转换而成的,以字符形式读取或写入数据,这个过程比较耗时,且不设置编码类型容易出现乱码。常见的编码有:
UTF8
:英文一个字节,一个中文占3个字节。unicode
:无论中文英文都占2个字节。GBK
:一个英文1个字节,中文2个字节。
字符输入流(Reader)常用方法
read()
: 从输入流读取一个字符。read(char[] cbuf)
: 从输入流中读取一些字节存储到数组b中,从零开始读取,最多读取到数组cbuf的长度 。read(char[] cbuf, int off, int len)
:读取一些字节存储到数组cbuf中,从off
位读取到len
位。skip(long n)
:忽略输入流中的n个字节,返回实际忽略的字节数。close()
: 关闭输入流并释放相关的系统资源。
示例代码:
public static void main(String[] args) {
try (FileReader fileReader = new FileReader("file.txt");) {
int content;
//跳过的字节数 5
fileReader.skip(5);
while ((content = fileReader.read()) != -1) {
System.out.print((char) content);
}
} catch (IOException e) {
e.printStackTrace();
}
}
字符输出流(Writer)常用方法
write(int c)
: 写入单个字符。write(char[] cbuf)
:将字符数组cbuf
的内容全部写到输出流。write(char[] cbuf, int off, int len)
:将字符数组cbuf
的内容从off到off+len写到cbuf中。write(String str)
:写入字符串,等价于write(str, 0, str.length())
。write(String str, int off, int len)
:在write(String str)
方法的基础上增加了off
参数(偏移量)和len
参数(要读取的最大字符数)。append(CharSequence csq)
:将指定的字符序列附加到指定的Writer
对象并返回该Writer
对象。append(char c)
:将指定的字符附加到指定的Writer
对象并返回该Writer
对象。flush()
:刷新此输出流并强制写出所有缓冲的输出字符。close()
:关闭输出流释放相关的系统资源。
示例代码:
public static void main(String[] args) {
try (FileWriter fileWriter = new FileWriter("spring-boot/src/main/java/com/example/springboot/Io/file.txt")) {
fileWriter.write("Zayton Squid");
fileWriter.write("Zayton Squid", 0, "Zayton Squid".length());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
字节缓冲流
BufferedInputStream(字节缓冲输入流)
BufferedInputStream
在创建流对象时,会创建一个内置的默认大小(8192 字节
)的缓冲区数组,通过缓冲区读写,避免频繁的IO操作,从而提高读写的效率;
public class BufferedInputStream extends FilterInputStream {
private static int DEFAULT_BUFFER_SIZE = 8192;
/**
* 内置缓冲区数组
*/
protected volatile byte buf[];
// 使用默认的缓冲区大小
public BufferedInputStream(InputStream in) {
this(in, DEFAULT_BUFFER_SIZE);
}
// 自定义缓冲区大小
public BufferedInputStream(InputStream in, int size) {
super(in);
if (size <= 0) {
throw new IllegalArgumentException("Buffer size <= 0");
}
buf = new byte[size];
}
BufferedOutputStream(字节缓冲输出流)
BufferedOutputStream
将数据写进缓冲区,当缓冲区满或者用户调用flush()函数时,它就会将缓冲区的数据写入到输出流中,避免频繁的IO操作,从而提高读写的效率;如下源码所示
public synchronized void write(int b) throws IOException {
if (count >= buf.length) {
flushBuffer();
}
buf[count++] = (byte)b;
}
字符缓冲流
和字节缓冲流差不多,内置维护了一个字节数组作为缓冲区数组,字符流是以字符为单位将数据存到数组中
随机访问流
随机访问流支持操作偏移量灵活改动到任意位置进行读写。
示例代码:
public static void main(String[] args) throws IOException {
RandomAccessFile randomAccessFile = new RandomAccessFile(new File("file.txt"), "rw");
System.out.println("读取之前的偏移量:" + randomAccessFile.getFilePointer() + ",当前读取到的字符" + (char) randomAccessFile.read() + ",读取之后的偏移量:" + randomAccessFile.getFilePointer());
// 指针当前偏移量为 7
randomAccessFile.seek(7);
System.out.println("读取之前的偏移量:" + randomAccessFile.getFilePointer() + ",当前读取到的字符" + (char) randomAccessFile.read() + ",读取之后的偏移量:" + randomAccessFile.getFilePointer());
// 从偏移量 8 的位置开始往后写入字节数据
randomAccessFile.write(new byte[]{'A', 'B', 'C', 'D'});
}