【问题标题】:BufferedWriter advantages [duplicate]BufferedWriter的优势[重复]
【发布时间】:2014-01-05 10:54:12
【问题描述】:

我有以下方法:

public void writeToFile(
  String id, 
  String no, 
  int systol, 
  int diastol, 
  int pulsDiff, 
  double speedAvg, 
  double spread
) { 
  String line = 
    id + "\t" + no + "\t" + systol + "/" + diastol + "\t" + pulsDiff 
    + "\t" + speedAvg + "\t" + spread + "\r\n";

    File fil = new File("resultat.txt");
    BufferedWriter writer = null;
    try { 
      writer = new BufferedWriter(new FileWriter(fil, true)); 
      writer.write(line); 
      writer.close();
    } catch (Exception e) {
      System.err.println("Fejl: " + e.getMessage());
    }

这可以用不同的方式完成吗?用一些不同的方法?这样做有什么好处?

我试图了解拥有bufferedWriter 的优势。我还处于起步阶段,正在努力理解这句话:”

通常,Writer 将其输出立即发送到底层字符或字节流。除非需要快速输出,否则建议将 BufferedWriter 包装在任何 write() 操作可能成本高昂的 Writer 周围,例如 FileWriters 和 OutputStreamWriters。例如,

 PrintWriter out    = new PrintWriter(new BufferedWriter(new 
     FileWriter("foo.out")));   

会将 PrintWriter 的输出缓冲到文件中。如果没有缓冲,每次调用 print() 方法都会导致字符转换为字节,然后立即写入文件,这可能非常低效。

尤其是“一般来说,Writer 将其输出立即发送到底层字符或字节流”部分。

【问题讨论】:

    标签: java printwriter bufferedwriter


    【解决方案1】:

    由于您正在向写入器写入单个字符串,因此在这种情况下缓冲是无用的。

    不过,真正应该修复的是异常处理和关闭编写器的方式。如果写入或关闭不成功,则应使用异常警告调用者,而不是简单地记录错误并继续,就好像什么都没发生一样。

    编写器应该在 finally 块中关闭,或者使用 try-with-resources 构造,以确保它始终处于关闭状态。

    【讨论】:

    • 我不太清楚你的意思。我在 .txt 文档的每一行都写了 7 个字符串。应该如何警告调用者,它有什么不同?我不太确定 finally 块是什么,以及为什么作者应该合二为一。我刚写的时候不是关闭了吗:“writer.close();”?
    • 对作者有一个单一的写调用:writer.write(line);。调用后,writer 立即关闭。所以缓冲是没用的。您可以直接将此行直接写入底层 FileWriter。应该通过使方法抛出 IOException 而不是捕获它来警告调用者。 Reac 一个关于异常的教程。不同之处在于调用者会知道发生了问题并可以告诉最终用户(通过显示对话框、打印消息或其他方式)。
    • 所以我不需要使用 writer.close();因为它在 writer.write(line) 之后已经关闭; ?但它应该已经通过 System.err.println 向最终用户打印错误消息?还是我错了?
    • 我从没这么说过。相反,我说将 close() 放在 finally 块中以确保它始终被执行。我说的是缓冲是不必要的,因为完成了一次写入。打个比方:把10本书装在一个盒子里更容易运输。但是,如果您要运输一本书,则无需将其包装在盒子中:直接运输该书既简单又快捷。
    • 关于错误信息:该方法的职责是写入文件。不与用户互动。假设您在一个循环中使用此方法 10 次:您希望循环在写入失败后立即停止。如果第一次写入失败,您不希望循环继续并写入 10 次相同的错误消息。
    【解决方案2】:

    假设您是一条与操作系统对话的 Java 指令。没有缓冲,情况就像(非常简化):

    Java -> OS: Hello, operating system, I'd like to write character c to file F
    OS -> HDD : Hello, disk, please append character c to file F
    HDD -> OS after a few milliseconds : I'm done.
    OS -> Java : Done
    

    如果您将许多字符写入文件,则无需进行此通信 - 他们仍在谈论相同的内容,这是浪费时间!这就是我们使用缓冲区的原因。看看情况如何变化:

    Java -> OS: Hello, operating system, I'd like to write bunch of characters c[] to file F
    OS -> HDD : Hello, disk, please append characters c[] to file F
    HDD -> OS after a few tens of milliseconds : I'm done.
    OS -> Java : Done
    

    期间。整个机器,所有磁盘搜索等等,只被调用一次。

    【讨论】:

    • 那么缓冲区究竟有什么作用?它跳过所有样板操作并且只使用一次操作?
    • 必须说我真的很喜欢这个解释:) 但是可以说情况与第 2 部分相同,我想将许多字符写入文件,但这次我没有缓冲区。 HDD 会占用每个字符而不是整个数组吗?
    • @user3161344 是的,完全正确。它一直重复相同的操作。
    • 上述对话的第二步是虚构的。该序列以从 Java 到操作系统的系统调用开始,并以系统调用返回结束。操作系统和应用程序之间没有其他交互,除了异步 I/O 的情况,这不是这里的主题。
    • @EJP :我理解你的意思,但是,正如我在第一段中所说的,这只是一个原理演示,而不是对整个 IO 过程的精确描述。
    【解决方案3】:

    使用BufferedReader 或BufferedWriter 的优点是减少从磁盘读取和写入磁盘的物理次数。它利用缓冲系统并一次执行读/写。因此效率更高。您可以尝试使用和不使用 BufferedReader/BufferedWriter 读/写一个大文件,看看有什么不同。

    【讨论】:

    • 那么可以说它更省时吗?我的意思是,如果我有一个大文件,使用 BufferedReader 会更快吗?如果我需要在 .txt 文件中写下很多内容,使用 BufferedWriter 会更快吗?
    • 嗯,根据我的个人经验,我可以说它可以至少快一倍。我复制并粘贴了一个大小约为 80 mb 的文件,有和没有它。结果:=> 9 秒;没有 => 21 秒。
    • @user3161344 我认为它应该更快,因为您只对内存管理进行 1 次调用而不是 xxx 调用。所以它应该更快。
    • @ambigram_maker:如果您多次写入缓冲写入器,效率会更高,因为例如,1000 次缓冲写入将仅转换为 2 或 3 次物理写入。但是在这里,只有一次 write() 调用,这将转换为单个物理写入。因此,直接进行物理写入实际上会更有效。
    • 阅读Scanner的javadoc。它不能用来写任何东西。
    【解决方案4】:

    如果您使用 + 运算符进行连接,您实际上会创建许多字符串,直到获得最终结果: “a”+“b”+“c”+“d”意味着你首先有“ab”,然后你想添加另一个字符来得到“abc”,最后你有另一个加法来得到“abcd”。

    第二种选择是您克服这种低效率的方法。

    编辑

    我的回答通常是关于字符串连接。正如 boxed__l 在他的评论中给出的参考资料中所提到的,在某些情况下可能会有优化,然后由 StringBuilder 完成连接(即使它没有明确完成)。但是,在某些情况下(例如,在循环中完成连接时),这很重要并且编译器无法进行优化。

    【讨论】:

    • @JBNizet 为什么不呢?我的意思是 - 使用流连接许多字符串更有效 - 不是吗?
    • 像这样连接字符串不会创建很多字符串。它使用单个 StringBuilder,附加所有内容,然后调用 toString()。
    • @JBNizet 你能给我一些参考吗?不知道s1+s2+s3+s4+...其实是用StringBuilder完成的。
    • @GariBN SO question
    • 查看docs.oracle.com/javase/specs/jls/se7/html/…,表示该优化已授权,使用 javap -c SomeExample.class 反汇编该代码生成的字节码,查看该优化是由编译器完成的。
    猜你喜欢
    • 2010-11-15
    • 2011-09-07
    • 2017-05-04
    • 2014-07-20
    • 2017-10-25
    • 1970-01-01
    • 2012-08-14
    • 1970-01-01
    • 2014-11-01
    相关资源
    最近更新 更多