【问题标题】:Program design when using BufferedWriter, do I repeatedly open and close file?使用BufferedWriter时的程序设计,我会重复打开和关闭文件吗?
【发布时间】:2019-04-17 18:34:01
【问题描述】:

我有一个程序,它使用循环进行大量处理,并在许多不同点将字符串写入文件。我不确定如何最好地做到这一点的整体设计。在运行期间的任何时候我都不需要从文件中读取,但之后会想要查看它。

首先,带有 FileWriter 的 BufferedWriter 是否合理?

其次,大概我不想在每次我想写东西的时候打开和关闭这个(每秒几次)。

但是,如果我使用资源的 try,那么我实际上必须将整个程序放在该 try 中,这正常吗?

此刻骨架的样子:

try (FileWriter writer = new FileWriter("filename.txt");
     BufferedWriter bw = new BufferedWriter(writer)) {

} catch (IOException e) {
    //catch IO error
}

for (//main loop){
    bw.write(string);
    for (//several sub loops){
        bw.write(//more strings);
    }
    for (//several sub loops){
        bw.write(//more strings);
    }
}

bw.write(//final string);

try {
    bw.close();
} catch (IOException ex) {
    //catch IO error
}

这看起来合理还是有更好的方法?非常感谢您的帮助。

编辑 - 感谢大家的帮助,完全回答了我的问题。

【问题讨论】:

  • 这段代码如何编译? bw 不在 try-with-resources 块之后的范围内。您是否在其他地方定义了另一个 bw
  • 它不能编译,它只是一个草图。这是我的问题之一,我是否需要将整个代码放入 try-with-resources 中的 for 循环中?
  • @John 有一些你没有的方法,一种方法是在 try-with-resources 块之前生成String 写入,然后将其作为一个整体写入。但正如我在回答中所描述的,这对大文件不是那么友好。但是,只要您不长时间停顿写几个小时,请不要犹豫,保持文件打开并将块包裹在它周围。通过在单一方法中生成内容来提高可读性,这样 try 块就不会变得过于臃肿和难以阅读。

标签: java bufferedwriter


【解决方案1】:

首先,带有 FileWriter 的 BufferedWriter 是一种合理的方法吗?

是的,这应该是最方便的方式。

其次,大概我不想在每次我想写东西的时候打开和关闭这个(每秒几次)。

你真的不应该。但无论如何,每次打开文件时,您实际上都会以这种方式覆盖您的进度。那是因为您没有告诉 FileWriter 附加到现有文件(通过 new FileWriter("filename.txt", true);

但是,如果我使用资源的 try,那么我实际上必须将整个程序放在该 try 中,这正常吗?

我认为这没有问题。您可以(并且应该)始终将您的逻辑移动到自己的方法或类中,这可能会返回 Strings 来编写。这样,您就可以将实际的业务逻辑与技术文件编写逻辑分开,并构建您的代码,使其更易于理解。

您也可以只写一个巨大的String,然后在try-with-resources 块中写那个String。但这对于非常大的文件是有限制的,有时可能不是最佳选择。

【讨论】:

    【解决方案2】:

    将整个代码放入 try-catch 例程中是完全可以的。每当您有问题要写入文件时,它只会捕获它并且不会给您错误。但是,我建议您只使用一个 try-catch 例程来尝试这种结构。

    try  { (FileWriter writer = new FileWriter("filename.txt");
     BufferedWriter bw = new BufferedWriter(writer)) 
    
    for (/*main loop*/){
       bw.write(string);
       for (/*several sub loops*/){
        bw.write(/*more strings*/);
        }
    for (/*several sub loops*/){
        bw.write(/*more strings*/);
        }
       }
    
    bw.write(/*final string*/);
    
    
    bw.close(); 
    
    
    } catch (IOException e) {
       System.out.println("error");
    }
    

    PS:如果您在某些代码之间注释某些内容,请使用 this:/* comment */ 而不是 this://,因为它会注释掉整行。

    【讨论】:

    • 你弄错了 try-with-resources 的开头语法。此外,您无需再关闭 BufferedWriter,因为托管的 try 块会为您执行此操作。
    • 你在TWR区块,不需要显式关闭
    • @Zhedar,语法怎么错了?好点重新不必要的关闭。
    【解决方案3】:

    但如果我对资源使用 try 那么我必须将 整个程序里面那个try,这样正常吗?

    这就是 try-catch-with-resources 的工作原理 - 它在退出 try 块时关闭资源。如果这让您感到困扰,请不要使用该结构,您自己管理writer

    上面的骨架将不起作用,因为第一个 try 将打开和关闭您的作家;

    【讨论】:

      【解决方案4】:

      这是一个可以更好地处理异常的替代方法。在许多情况下,这是首选。使用 catch 块处理过多的异常会变得非常混乱:控制流会变得模糊,并且诊断错误会变得更加困难。

      在程序运行的整个过程中打开文件是很常见的。这通常是日志文件的情况。 如果你知道你的程序会运行很长时间,并且如果你怀疑输出到单个文件之间会有很长的延迟,你可以打开和关闭文件对于每批及时关闭的操作。但是您必须清楚地了解要执行此操作的活动模式,因为您需要将文件的打开时间与预期的即时批写入相匹配。您应该非常避免高频打开和关闭操作。这会产生各种不必要的额外开销。

      package my.tests;
      
      import java.io.BufferedWriter;
      import java.io.FileWriter;
      import java.io.IOException;
      import java.io.Writer;
      import java.util.function.Consumer;
      
      public class WriterTest {
          public static final String TARGET_NAME = "filename.txt";
      
          public void performMainLoop() {
              performWrites( this::mainLoop, TARGET_NAME );
          }
      
          public void performWrites( Consumer<Writer> writeActor, String targetName ) {
              FileWriter fileWriter;
              try {
                  fileWriter = new FileWriter(targetName);
              } catch ( IOException e ) {
                  System.out.println("Open failure: " + e.getMessage());
                  e.printStackTrace();
                  return;
              }
      
              BufferedWriter bufferedWriter = null;
              try {
                  bufferedWriter = new BufferedWriter(fileWriter);
                  writeActor.accept(bufferedWriter);
      
              } finally {
                  if ( bufferedWriter != null ) {
                      try {
                          bufferedWriter.close();
                      } catch ( IOException e ) {
                          System.out.println("Unexpected close failure: " + e.getMessage());
                          e.printStackTrace();
                      }
                  } else {
                      try {
                          fileWriter.close();
                      } catch ( IOException e ) {
                          System.out.println("Unexpected close failure: " + e.getMessage());
                          e.printStackTrace();
                      }
                  }
              }
          }
      
          public void mainLoop(Writer writer) {
              for ( int loopNo = 0; loopNo < 10; loopNo++ ) {
                  try {
                      writer.write("Loop [ " + Integer.toString(loopNo) + " ]\n");
      
                  } catch ( IOException e ) {
                      System.out.println("Unexpected write failure: " + e.getMessage());
                      e.printStackTrace();
                      return;
                  }
              }
          }
      }
      

      【讨论】:

      • 大量样板代码,没有try-catch-with-resources,关闭两个写入器同时关闭缓冲写入器就可以了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-26
      • 1970-01-01
      • 1970-01-01
      • 2018-09-26
      • 1970-01-01
      相关资源
      最近更新 更多