草庐IT

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

coder 2024-03-20 原文

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

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

这就是我构建 BufferedWriter 的方式:

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

这是完整的代码:

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();
            }
        }
    }
}

最佳答案

Is there a problem with my code?

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

  • 正在尝试打开已经打开的文件。您的所有线程都试图写入同一个文件 (1.txt)。这可能是个问题。 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.

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

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

  • 没有flushingclosing 缓冲区将意味着您的数据(尾部)将丢失(就像雨中的泪水)。 finally block 通常可以很好地解决这个问题。

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

这是我的代码,如果对你有用的话:

// 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);
    }
}

}

关于java - 如何通过 FileWriter 在 BufferedWriter 上设置缓冲区大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32451526/

有关java - 如何通过 FileWriter 在 BufferedWriter 上设置缓冲区大小的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  4. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  5. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  6. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  7. ruby-openid:执行发现时未设置@socket - 2

    我在使用omniauth/openid时遇到了一些麻烦。在尝试进行身份验证时,我在日志中发现了这一点:OpenID::FetchingError:Errorfetchinghttps://www.google.com/accounts/o8/.well-known/host-meta?hd=profiles.google.com%2Fmy_username:undefinedmethod`io'fornil:NilClass重要的是undefinedmethodio'fornil:NilClass来自openid/fetchers.rb,在下面的代码片段中:moduleNetclass

  8. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  9. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  10. ruby - 通过 rvm 升级 ruby​​gems 的问题 - 2

    尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub

随机推荐