java 如何通过 FileWriter 在 BufferedWriter 上设置缓冲区大小

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32451526/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 20:14:01  来源:igfitidea点击:

How to set the buffer size on a BufferedWriter over a FileWriter

javafile-iofilewriterbufferedwriter

提问by jinhong_lu

I met a problem with BufferedWriterwhen I write data to a single file with some threads.

BufferedWriter当我使用某些线程将数据写入单个文件时遇到问题。

I set the buffer size of the BufferedWriter, but no matter what number I set, it flushes the data to disk when the buffer is 8192 (the default buffer size), not the size I set (here is 16384). Is there a problem with my code?

我设置了 的缓冲区大小BufferedWriter,但是无论我设置什么数字,当缓冲区为 8192(默认缓冲区大小)而不是我设置的大小(这里是 16384)时,它都会将数据刷新到磁盘。我的代码有问题吗?

This is how I'm constructing the BufferedWriter:

这就是我构建的方式BufferedWriter

new BufferedWriter(new FileWriter(fileName, true), 16384);

This is the full code:

这是完整的代码:

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

public class Test1 {
    public static void main(String[] args) throws IOException {
        for(int i =0;i<10;i++){
            MyThread r = new MyThread();
            Thread t = new Thread(r);
            t.start();
        }
    }
}

class MyThread implements Runnable {
    public void run() {
        String s = "{addffffffkkkljlkj2015dd}\n";
        BufferedWriter bw = null;
        try {
            bw = new BufferedWriter(new FileWriter(
                    "/Users/liaoliuqing/Downloads/1.txt", true),16384);
        } catch (IOException e) {
            e.printStackTrace();
        }
        for(int i =0 ; i<1000; i++){
            try {
                bw.write(String.format("%03d", i)+s);
                //bw.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

采纳答案by jinhong_lu

I solve the problem by using OutputStream, not writer, here is the code:

我通过使用 OutputStream 而不是 writer 解决了这个问题,这里是代码:

bw = new BufferedOutputStream(
                new FileOutputStream(new File("/Users/liaoliuqing/Downloads/1.txt"),true),165537);

回答by Raman Shrivastava

FileWriteractually uses its own fixed-size 1024 byte buffer. The BufferedWriteron the other hand, show that it uses and 8192 byte buffer size (default), which can be configured by the user to any other desired size.

FileWriter实际上使用它自己的固定大小的 1024 字节缓冲区。在BufferedWriter另一方面,显示,它使用和8192字节的缓冲区大小(默认值),其可以通过用户的任何其它期望的大小来配置。

And to further muddy the waters, the Java 6 implementation of OutputStreamWriteractually delegates to a StreamEncoder, which uses its own buffer with a default size of 8192 bytes. And the StreamEncoderbuffer is user-configurable, although there is no way to access it directly through the enclosing OutputStreamWriter.

为了进一步混淆水域,Java 6 实现OutputStreamWriter实际上委托给 a StreamEncoder,它使用自己的缓冲区,默认大小为 8192 字节。并且StreamEncoder缓冲区是用户可配置的,尽管无法通过封闭的 OutputStreamWriter 直接访问它。

回答by Javier

Is there a problem with my code?

我的代码有问题吗?

A few. Mainly: potential IO and concurrency errors. File buffer size might be a lesser concern (and one you can't effectively deal with).

一些。主要是:潜在的IO和并发错误。文件缓冲区大小可能不是一个问题(并且您无法有效处理)。

  • Trying to open already opened file. All your threads are trying to write into the same file (1.txt). That might be an issue. FileWriter documentation says:

    Some platforms, in particular, allow a file to be opened for writing by only one FileWriter (or other file-writing object) at a time. In such situations the constructors in this class will fail if the file involved is already open.

  • Lines might be cut and mixed. If you have several threads with their respective buffers flushing at some point into the same output, you might not even need weird race-conditions or threads stopped right of the middle or a write operation to see your output corrupted.

    As I solution (If your threads must share the same output) you can use a shared object with synchronized access to take care of actual writing. I implemented SafeAppenderin my example, but probably there are better alternatives out there.

  • No flushingand closingbuffers will mean (the tail of) your data will be lost (like tears in the rain). A finally block is usually good to take care of that.

  • Also, as stated by other users, BufferedWriterbuffer sizedoes not affect the buffer size in FileOutputStream(and so FileWriter). And it looks the java.ioand java.nioAPIs dont offer any way to mess with that. If you look at the Java library sources you might notice BufferedWriterbuffer size just means the amount of chars you store before actually writing into the delegate output. The default size (8192) is optimal for most cases, and increasing it might mean more trouble (potentially losing more data) than benefits.

  • 试图打开已经打开的文件。您的所有线程都试图写入同一个文件 ( 1.txt)。那可能是个问题。FileWriter 文档说:

    特别是某些平台,一次只允许一个 FileWriter(或其他文件写入对象)打开一个文件进行写入。在这种情况下,如果所涉及的文件已经打开,则此类中的构造函数将失败。

  • 线条可能会被剪切和混合。如果您有多个线程,它们各自的缓冲区在某个时刻刷新到同一输出中,您甚至可能不需要奇怪的竞争条件或线程在中间停止或写操作来查看您的输出已损坏。

    作为我的解决方案(如果您的线程必须共享相同的输出),您可以使用具有同步访问的共享对象来处理实际写入。我SafeAppender在我的例子中实现了,但可能有更好的选择。

  • 没有刷新关闭缓冲区将意味着(的尾部)您的数据将丢失(就像雨中的眼泪)。finally 块通常可以很好地处理这个问题。

  • 此外,正如其他用户所说,BufferedWriter缓冲区大小不会影响FileOutputStream(等等FileWriter)中的缓冲区大小。看起来java.iojava.nioAPI 没有提供任何方法来解决这个问题。如果您查看 Java 库源代码,您可能会注意到BufferedWriter缓冲区大小仅表示您在实际写入委托输出之前存储的字符数量。默认大小 (8192) 在大多数情况下是最佳的,增加它可能意味着更多的麻烦(可能丢失更多的数据)而不是好处。

This is my code, if it serves you:

这是我的代码,如果它为您服务:

// http://stackoverflow.com/questions/32451526/how-to-set-the-buffer-size-on-a-bufferedwriter-over-a-filewriter
public class TestWriter {

public static class SafeAppender {
    private BufferedWriter bw;
    private int users = 0;
    public SafeAppender(File f) throws IOException {
        bw = new BufferedWriter(new FileWriter(f));
    }

    public synchronized void append(String s) throws IOException {
        bw.write(s);
    }
    public synchronized void incrUsers() { 
        users ++; 
    }
    public synchronized void decrUsers() {
        if (--users <= 0) {
            try {
                bw.flush();
                System.err.println("INFO-appender-flush()");
            } catch (Throwable whatever) { /* log-if-you-care*/}
        }
    }
    // Might be called by GC, or not
    @Override protected void finalize() throws Throwable {
        try {
            bw.close();
            System.err.println("INFO-appender-close()");
        } catch (Throwable whatever) { /* log-if-you-care */}
        super.finalize();
    }
}

private static class MyRunnable implements Runnable {
    final static String S = "{addffffffkkkljlkj2015dd}";
    SafeAppender appender;
    String threadId;
    public MyRunnable (SafeAppender a, String tid) {
        appender = a; threadId = tid;
    }

    public void run() {
        appender.incrUsers();
        try {
            for(int i =0 ; i<1000; i++){
                // NOTE: Not a good idea to printStackTrace if each line fails. Let thread fail
                String line = String.format("%s-%03d-%s\n", threadId, i, S);
                appender.append(line);
            }
        } catch (IOException e) {
            System.err.printf("ERROR-%s-%s\n", threadId, e.toString());
        } finally {
            appender.decrUsers();
        }
    }
}

public static void main(String[] args) {
    try {
        File f = File.createTempFile("TestWriter", ".txt");
        System.err.printf("INFO-main-Writing into %s\n", f.getCanonicalPath());
        SafeAppender appender = new SafeAppender (f);
        for(int i =0;i<10;i++){
            MyRunnable r = new MyRunnable(appender, ""+i);
            Thread t = new Thread(r);
            t.start();
        }
    } catch (Throwable e) {
        e.printStackTrace(System.err);
    }
}

}

回答by Marco Sandrini

What you are seeing is not the size of the buffer BufferedWriter, but the size of the buffer used internally by FileWriter. Quoting from the Java Documentation (http://docs.oracle.com/javase/7/docs/api/java/io/FileWriter.html)

您看到的不是缓冲区 BufferedWriter 的大小,而是 FileWriter 内部使用的缓冲区大小。引用 Java 文档 ( http://docs.oracle.com/javase/7/docs/api/java/io/FileWriter.html)

The constructors of this class assume that the default character encoding and the default byte-buffer size are acceptable. To specify these values yourself, construct an OutputStreamWriter on a FileOutputStream.

此类的构造函数假定默认字符编码和默认字节缓冲区大小是可接受的。要自己指定这些值,请在 FileOutputStream 上构造一个 OutputStreamWriter。

So if you wanted to have a fine grain control on when the data is actually written to the disk you should instantiate your BufferedWriter as

因此,如果您想对数据实际写入磁盘的时间进行细粒度控制,则应将 BufferedWriter 实例化为

bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File('my_file.txt),true)));