目录标题
缓冲流
缓冲流提供了带缓冲区的输入输出功能,目的是提高处理数据的效率,尤其是在进行大量数据的读写时。
BufferedInputStream和BufferedOutputStream
两者同为字节流,BufferedInputStream
是 InputStream
的子类,它通过提供一个缓冲区(内存中的数组)来提高读取数据的效率。它会从底层的输入流中读取数据,并将其缓存在内存中。当需要读取数据时,首先从缓冲区读取,而不是每次都从底层输入流中读取。这样可以减少底层流的读取次数,提高性能。
BufferedOutputStream
是OutputStream
的子类,它同样使用缓冲区来提高写入数据的效率。它会将数据写入一个缓冲区,当缓冲区满时才将数据写入底层输出流。这减少了每次写入时对底层流的操作次数,从而提高了性能。
构造函数
BufferedInputStream
提供两种构造函数:
public BufferedInputStream(InputStream in)
- 参数
InputStream in
是底层输入流
- 参数
public BufferedInputStream(InputStream in, int size)
- 参数
InputStream in
是底层输入流 - 参数
int size
是缓冲区大小,默认为8192
- 参数
示例:
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("src/1.txt"));
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("src/1.txt"), 1024);
BufferedOutputStream
的构造函数与之类似
public BufferedOutputStream(OutputStream out)
public BufferedOutputStream(OutputStream out, int size)
常用方法
BufferedInputStream
提供了一些方法,主要用于提高读取数据的效率。
read()
该方法读取下一个字节的数据,并返回该字节。如果到达流的末尾,则返回-1
。
int byteRead = bufferedInputStream.read();
read(byte[] b)
该方法将数据读取到指定的字节数组中,返回实际读取的字节数。如果到达流的末尾,返回-1
。
int bytesRead = bufferedInputStream.read(byteArray);
read(byte[] b, int off, int len)
该方法将数据读取到指定的字节数组b
的某个位置,最多读取len
个字节。如果到达流的末尾,返回-1
。
int bytesRead = bufferedInputStream.read(byteArray, offset, length);
skip(long n)
该方法跳过指定数量的字节n
,返回实际跳过的字节数。此方法会在读取流时跳过n
字节的数据。
long bytesSkipped = bufferedInputStream.skip(n);
available()
该方法返回流中当前可供读取的字节数,返回值可能不准确。
int availableBytes = bufferedInputStream.available();
mark(int readlimit)
该方法标记当前流的位置,并将该位置作为后续reset()
方法调用的起点。readlimit
指定在流被标记后可以读取的最大字节数。如果超过了该限制,流的标记位置将失效。
bufferedInputStream.mark(readLimit);
reset()
该方法将流的位置重置为先前通过mark()
方法标记的位置。如果未调用mark()
方法,调用reset()
会抛出IOException
。
bufferedInputStream.reset();
close()
该方法关闭流,释放流的相关资源。
bufferedInputStream.close();
以下是 BufferedOutputStream
类的几个常用方法:
write(int b)
该方法将一个字节的数据写入到流中。
bufferedOutputStream.write(byteData);
write(byte[] b)
该方法将整个字节数组的数据写入到流中。它会将数组b
中的所有字节写入到输出流。
bufferedOutputStream.write(byteArray);
write(byte[] b, int off, int len)
该方法将字节数组b
从索引off
位置开始,最多写入len
个字节到流中。可以指定写入的部分字节数,而不是整个数组。
bufferedOutputStream.write(byteArray, offset, length);
flush()
该方法将缓冲区中的所有数据强制写入到底层的输出流中。在调用flush()
之后,缓冲区中的数据会被立即写入目标输出流。通常在写入完成后,应该调用该方法来确保所有数据都被写入。
bufferedOutputStream.flush();
close()
该方法关闭输出流,并将缓冲区中的任何剩余数据写入到底层流中。关闭流时,还会释放流所占用的资源。
bufferedOutputStream.close();
BufferedReader和BufferedWriter
两者都是字符流
构造函数
BufferedReader
提供两种构造函数:
public BufferedReader(Reader in, int sz)
- 参数
Reader in
是输入字符流 - 参数
int sz
是缓冲区的大小(默认8192个字符)
- 参数
public BufferedReader(Reader in)
- 参数
Reader in
是输入字符流
- 参数
示例:
BufferedReader br = new BufferedReader(new FileReader("src/1.txt"));
BufferedReader br = new BufferedReader(new FileReader("src/1.txt"), 1024);
BufferedWriter
的构造函数与之相似:
public BufferedWriter(Writer out)
public BufferedWriter(Writer out, int sz)
常用方法
BufferedReader
的常用方法:
read()
该方法读取单个字符(以整数形式返回),如果到达流的末尾,返回-1
。
int charRead = bufferedReader.read();
read(char[] cbuf)
该方法读取字符数据,并将读取到的字符存储到字符数组cbuf
中,返回实际读取的字符数。如果到达流的末尾,返回-1
。
int charsRead = bufferedReader.read(cbuf);
readLine()
该方法读取一行字符,直到遇到行结束符(\n
或\r\n
)为止。如果到达流的末尾,返回null
。该方法在 Java 1.7 之后已经被标记为弃用,建议使用read()
和相关方法替代。
String line = bufferedReader.readLine();
skip(long n)
该方法跳过n
个字符的输入。如果n
大于流中剩余的字符数,实际跳过的字符数可能会少于n
。返回跳过的字符数。
long charsSkipped = bufferedReader.skip(n);
ready()
该方法检查是否可以进行读操作。如果可以读取字符,返回true
;否则,返回false
。
boolean isReady = bufferedReader.ready();
close()
该方法关闭流,释放与该流相关的资源。关闭流时,缓冲区中的所有数据都会被自动刷新并写入
bufferedReader.close();
BufferedWriter
的常用方法:
write(int c)
该方法写入单个字符数据。如果要写入的字符是一个字节,则可以使用此方法。
bufferedWriter.write(65); // 写入字符 'A'
write(char[] cbuf)
该方法将整个字符数组的数据写入到流中。它会将数组cbuf
中的所有字符写入到输出流。
bufferedWriter.write(cbuf); // 写入字符数组
write(char[] cbuf, int off, int len)
该方法将字符数组cbuf
从索引off
位置开始,最多写入len
个字符到输出流中。可以指定写入的部分字符数,而不是整个数组。
bufferedWriter.write(cbuf, offset, length); // 写部分字符数组
newLine()
该方法写入一个平台相关的行分隔符(如 Windows 使用\r\n
,Unix 使用\n
)。它通常用于表示一行的结束。
bufferedWriter.newLine(); // 写入行分隔符
flush()
该方法将缓冲区中的所有数据强制写入到底层的输出流中。在调用flush()
之后,缓冲区中的数据会被立即写入目标输出流。通常在写入完成后,应该调用该方法来确保所有数据都被写入。
bufferedWriter.flush();
close()
该方法关闭输出流,并将缓冲区中的任何剩余数据写入到底层流中。关闭流时,还会释放流所占用的资源。
bufferedWriter.close();
工作原理
在 FileInputStream
中,每次调用 read()
方法时,都会直接从文件中读取一个字节。这意味着每调用一次 read(),就需要一次磁盘 I/O 操作。对于每次读取一个字节来说,这会造成很多不必要的磁盘访问,从而降低了读取效率。BufferedInputStream
通过内部缓冲区来优化文件读取。它会一次性从磁盘读取多个字节的数据,存入内存中的缓冲区(默认大小为8192个字节)。之后的read()
调用将直接从这个缓冲区返回数据,而不需要每次都访问磁盘。这样,在缓冲区填满后,之后的 read()
调用只是从内存中读取数据,极大减少了磁盘 I/O 操作。
转换流
转换流的作用是将字节流和字符流进行转换。这两个类通常用于在处理非字符流(如文件、网络等)时,实现字符编码和解码功能
InputStreamReader
构造函数
1. public InputStreamReader(InputStream in)
2. public InputStreamReader(InputStream in, String charsetName)
3. public InputStreamReader(InputStream in, Charset cs)
4. public InputStreamReader(InputStream in, CharsetDecoder dec)
构造函数中需要指定包装的字节流,后三种构造方法实际上都是在指定编码方式
常用方法
常用方法与基本的字节流类似,只是会把读取到的数据通过指定字符编码将字节转换为字符。以下是 InputStreamReader
的常用方法:
int charRead = inputStreamReader.read();
int charsRead = inputStreamReader.read(cbuf);
int charsRead = inputStreamReader.read(cbuf, offset, length);
long skippedChars = inputStreamReader.skip(n);
boolean isReady = inputStreamReader.ready();
inputStreamReader.mark(readAheadLimit);
inputStreamReader.reset();
inputStreamReader.close();
OutputStreamWriter
构造方法
public OutputStreamWriter(OutputStream out)
public OutputStreamWriter(OutputStream out, String charsetName)
public OutputStreamWriter(OutputStream out, Charset cs)
public OutputStreamWriter(OutputStream out, CharsetEncoder enc)
构造函数中需要指定包装的字节流,后三种构造方法实际上都是在指定编码方式
常用方法
OutputStreamWriter
是 Java 中的一个字符流类,用于将字符流(如 Writer
)转换为字节流(如 OutputStream
)。它用于将字符数据写入到字节流中,并且支持字符编码的转换。下面是 OutputStreamWriter
常用的方法:
outputStreamWriter.write(65); // 写入字符 'A'
char[] chars = "Hello, OutputStreamWriter!".toCharArray();
outputStreamWriter.write(chars);
outputStreamWriter.write(chars, 0, 5); // 写入数组的前5个字符
outputStreamWriter.flush(); // 强制写入缓冲区的内容
outputStreamWriter.close(); // 关闭流,释放资源
String encoding = outputStreamWriter.getEncoding();
使用示例
读取一个GBK
文件,将其写入一个UTF-8
的文件
public static void main(String[] args) throws IOException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("src/gbk.txt"), "GBK");
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("src/utf8.txt"), StandardCharsets.UTF_8);
char[] buf = new char[1024];
int len;
while ((len = isr.read(buf)) != -1) {
osw.write(buf, 0, len);
}
isr.close();
osw.close();
}
序列化流
ObjectInputStream
构造方法
public ObjectInputStream(InputStream in)
包裹指定的输入字节流
常用方法
ObjectInputStream
可以将从输入流中读取的字节反序列化为 Java 对象。常见的应用场景包括读取从 ObjectOutputStream
写入的数据,进行对象的反序列化。
以下是 ObjectInputStream
的常用方法:
readObject()
该方法用于从输入流中读取一个对象,并将其反序列化为 Java 对象。返回类型是Object
,因此需要进行强制类型转换。
Object obj = objectInputStream.readObject();
- 返回值:返回一个被反序列化的对象。
- 异常:如果反序列化的类没有实现
Serializable
接口,或者发生了 I/O 错误,则会抛出异常(ClassNotFoundException
和IOException
)。
readInt()
该方法从输入流中读取一个整数值。它将字节转换为一个int
类型。
int intValue = objectInputStream.readInt();
readLong()
该方法从输入流中读取一个长整型值。
long longValue = objectInputStream.readLong();
readUTF()
该方法从输入流中读取一个 UTF-8 编码的字符串,返回该字符串。
String str = objectInputStream.readUTF();
readByte()
该方法从输入流中读取一个字节。
byte byteValue = objectInputStream.readByte();
readBoolean()
该方法从输入流中读取一个布尔值。
boolean booleanValue = objectInputStream.readBoolean();
readChar()
该方法从输入流中读取一个字符。
char charValue = objectInputStream.readChar();
close()
该方法关闭流并释放资源。当关闭流时,ObjectInputStream
将关闭其底层流(如文件流、网络流等)。
objectInputStream.close();
ObjectOutputStream
构造方法
public ObjectOutputStream(OutputStream out)
包裹指定的输出字节流
常用方法
ObjectOutputStream
是 Java 中用于将对象写入输出流的类,它负责将对象进行序列化并写入流中,以便可以将其保存到文件、网络、数据库等地方。以下是 ObjectOutputStream
的常用方法:
writeObject(Object obj)
该方法将一个对象序列化并写入流中。如果对象没有实现Serializable
接口,会抛出java.io.NotSerializableException
异常。
objectOutputStream.writeObject(myObject); // 序列化并写入对象
- 参数:
obj
— 要写入的对象。 - 返回值:无。
- 异常:抛出
IOException
或NotSerializableException
。
write(int v)
该方法将一个字节(int
类型的值)写入输出流。该方法将整数值(0–255)转换为一个字节,并写入流。
objectOutputStream.write(65); // 写入单个字节,'A' 的 ASCII 值
writeByte(int v)
该方法将一个字节写入输出流,v
必须是byte
范围内的整数(即-128
到127
)。
objectOutputStream.writeByte(100); // 写入一个字节值 100
writeBoolean(boolean v)
该方法将一个布尔值写入输出流。
objectOutputStream.writeBoolean(true); // 写入布尔值 true
writeChar(int v)
该方法将一个字符(char
)写入输出流。
objectOutputStream.writeChar('A'); // 写入字符 'A'
writeFloat(float v)
该方法将一个浮点值(float
)写入输出流。
objectOutputStream.writeFloat(3.14f); // 写入浮点数 3.14
writeDouble(double v)
该方法将一个双精度浮点值(double
)写入输出流。
objectOutputStream.writeDouble(3.141592); // 写入双精度浮点数 3.141592
writeUTF(String str)
该方法将一个字符串写入输出流,并将其转换为 UTF-8 编码的字节流。
objectOutputStream.writeUTF("Hello, world!"); // 写入字符串
flush()
该方法将缓冲区中的所有数据强制写入到底层输出流中。一般来说,当流被关闭之前,可以调用此方法来确保所有数据被写入。
objectOutputStream.flush(); // 强制写入缓冲区数据
close()
该方法关闭输出流,并释放资源。当调用close()
时,ObjectOutputStream
会将任何剩余的字节数据写入流中并关闭流。
objectOutputStream.close(); // 关闭流并释放资源
使用示例
- 序列化的类需要实现
Serializable
接口 - 实现接口后类中会包含一个
serialVersionUID
- 类变化时
serialVersionUID
同样变化,如果没有找到相同的serialVersionUID
反序列化会失败 - 可以手动指明
serialVersionUID
private static final long serialVersionUID = 1L;
- 不想序列化的值可以通过
transient
关键字
// 序列化的实体类
public class A implements Serializable {
@Serial
private static final long serialVersionUID = -4476946105183235212L;
public String name = "aaa";
public int age = 0;
public A() {
}
public A(String name, int age) {
this.name = name;
this.age = age;
}
}
// 将A类型的对象a写入文件
public static void main(String[] args) {
A a = new A();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("src/a.txt"));
oos.writeObject(a);
oos.close();
}
// 从文件中读取A类型的对象a
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("src/a.txt"));
A a = (A)ois.readObject();
System.out.println(a);
}