Python 官方文档:入门教程 => 点击学习
目录BufferedOutputStream类的常用方法构造方式常用方法程序示例BufferedOutputStream深入分析代码准备原因分析手动刷盘buffer源码分析关于buf
BufferedOutputStream字节缓冲输出流
第一种开发中
public BufferedOutputStream(OutputStream out)
采用的默认的缓冲区大小(足够大了) ,来构造一个字节缓冲输出流对象
public BufferedOutputStream(OutputStream out,int size)
指定size缓冲区大小构造缓冲输出流对象
IllegalArgumentException - 如果 size <= 0
public void write(int b)throws IOException
一次写一个字节
public void write(byte[] b,int off,int len) throws IOException
一次写一个字节数组的一部分
public void flush() throws IOException
刷新此缓冲的输出流。这迫使所有缓冲的输出字节被写出到底层输出流中。
public void close() throws IOException
关闭此输出流并释放与此流有关的所有系统资源。
FilterOutputStream 的 close 方法先调用其 flush 方法,然后调用其基础输出流的 close 方法。
public static void main(String[] args) throws Exception {
//符合Java一种设计模式:装饰者设计模式(过滤器:Filter)
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt")) ;
//写数据
bos.write("hello".getBytes());
//释放资源
bos.close();
}
FileOutputStream和BufferedOutputStream都提供了一系列的将数据写入文件的方式,并且我们都知道BufferedOutputStream要比直接使用FileOutputStream写入速度要快,本文通过案例实际演示一下两者的区别。
public class BufferFile {
public static void main(String[] args) {
//每次向文件中写入一个8字节的数组
byte[] bytes = "1234567\n".getBytes();
//每隔100毫秒通过buffer的方式向文件中写入数据
new Thread(() -> {
System.out.println("buffer_while start...");
File file = new File("/var/file_test_data/out_buffer_while.txt");
FileOutputStream fileOutputStream;
try {
fileOutputStream = new FileOutputStream(file);
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
while (true) {
Thread.sleep(100);
bufferedOutputStream.write(bytes);
}
} catch (Exception e) {
e.printStackTrace();
}
}).start();
//通过buffer的方式向文件中写入1千万次
new Thread(() -> {
System.out.println("buffer_for start...");
File file = new File("/var/file_test_data/out_buffer_for.txt");
FileOutputStream fileOutputStream;
try {
fileOutputStream = new FileOutputStream(file);
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
for (int i = 0; i < 10000000; i++) {
bufferedOutputStream.write(bytes);
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(new Date() + ": buffer_for end...");
}).start();
//通过file的方式向文件中写入1千万次
new Thread(() -> {
System.out.println("file_for start...");
File file = new File("/var/file_test_data/out_file_for.txt");
FileOutputStream fileOutputStream;
try {
fileOutputStream = new FileOutputStream(file);
for (int i = 0; i < 10000000; i++) {
fileOutputStream.write(bytes);
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(new Date() + ": file_for end...");
}).start();
}
}
开始运行
强行停止后的运行结果
1、file和buffe写入速度比较
两者分别写入1千万次,时间上buffer比file快8秒,如果当写入次数指数级增加时,buffer的优势将更加明显。
2、数据写入完整性问题
buffer虽然要比file快,但是从最终数据上可以看出,buffer会丢数据
当使用buffer读写文件时,数据并没有直接被写入磁盘,而是被缓存到一个字节数据中,这个字节数组的大小是8kb,默认情况下只有当8kb被填充满了以后,数据才会被一次性写入磁盘,这样一来就大大减少了系统调用的次数(file是每一次write都会产生系统调用),当然也正是因为buffer中的每一次write只是写入到内存中(JVM自身内存中),所以当数据未写入磁盘前,如果JVM进程挂了,那么就会造成数据丢失。
为了解决数据丢失的问题,buf中提供了flush()方法,用户可以自行决定合适将数据刷写到磁盘中
将无限循环写入的代码注释掉,在buf写1千万完成后,加上bufferedOutputStream.flush();
public class BufferFile {
public static void main(String[] args) {
//每次向文件中写入一个8字节的数组
byte[] bytes = "1234567\n".getBytes();
//每隔100毫秒通过buffer的方式向文件中写入数据
//通过buffer的方式向文件中写入1千万次
new Thread(() -> {
System.out.println("buffer_for start...");
File file = new File("/var/file_test_data/out_buffer_for.txt");
FileOutputStream fileOutputStream;
try {
fileOutputStream = new FileOutputStream(file);
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
for (int i = 0; i < 10000000; i++) {
bufferedOutputStream.write(bytes);
}
bufferedOutputStream.flush();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(new Date() + ": buffer_for end...");
}).start();
//通过file的方式向文件中写入1千万次
new Thread(() -> {
System.out.println("file_for start...");
File file = new File("/var/file_test_data/out_file_for.txt");
FileOutputStream fileOutputStream;
try {
fileOutputStream = new FileOutputStream(file);
for (int i = 0; i < 10000000; i++) {
fileOutputStream.write(bytes);
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(new Date() + ": file_for end...");
}).start();
}
}
这次再看数据写入完整了
类的机构图
首先当创建一个BufferedOutputStream对象时,构造方法就初始化了缓冲的字节数组大小为8kb
protected byte buf[];
public BufferedOutputStream(OutputStream out) {
this(out, 8192);
}
public BufferedOutputStream(OutputStream out, int size) {
super(out);
if (size <= 0) {
throw new IllegalArgumentException("Buffer size <= 0");
}
buf = new byte[size];
}
当调用buffer.write(b)时,调用的是父类FilterOutputStream的方法
public void write(byte b[]) throws IOException {
//写入的字节数组b,从0开始,一共要写入的长度
write(b, 0, b.length);
}
public void write(byte b[], int off, int len) throws IOException {
if ((off | len | (b.length - (len + off)) | (off + len)) < 0)
throw new IndexOutOfBoundsException();
//遍历数组,一个字节一个字节的把数据写入数组中
for (int i = 0 ; i < len ; i++) {
write(b[off + i]);
}
}
public synchronized void write(int b) throws IOException {
//判断字节长度是否超过buf.length,buf在初始化已经指定大小为8192,即8kb
//如果超过则调用flushBuffer
if (count >= buf.length) {
flushBuffer();
}
把每一个字节写入缓冲的buf数组中,并且统计值count++
buf[count++] = (byte)b;
}
private void flushBuffer() throws IOException {
if (count > 0) {
//真正的调用OutputStream,写入数据到磁盘中
//写入buf缓冲字节数组数据,从0下标开始,一直写到count,即有多少写多少。
out.write(buf, 0, count);
count = 0;
}
}
buffer提供了可以自定义缓冲大小的构造方法
public BufferedOutputStream(OutputStream out, int size) {
super(out);
if (size <= 0) {
throw new IllegalArgumentException("Buffer size <= 0");
}
buf = new byte[size];
}
如果缓冲大小设置的比较大。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。
--结束END--
本文标题: Java BufferedOutputStream类的常用方法讲解
本文链接: https://lsjlt.com/news/137858.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-03-01
2024-03-01
2024-03-01
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0