简体   繁体   English

以追加模式打开文件但如果在 JAVA 11 中不为空则截断文件

[英]Opening a file in append mode but truncating the file if not empty in JAVA 11

I would like to create a result.csv file if it does not exist, then I call write several times and append corresponding messages one by a call.如果它不存在,我想创建一个 result.csv 文件,然后我多次调用write并通过调用附加相应的消息。

But If the file already exists and contain something before the run of the program, I would like to erase its contents and then begin to append corresponding messages .但是如果文件在程序运行之前已经存在并且包含一些东西,我想删除它的内容,然后开始附加相应的消息。

I have tried the following:我尝试了以下方法:

public final class Writer {
    public static void write(String message, String destinationPath) {
        try (FileWriter fw = new FileWriter(destinationPath, true);
             BufferedWriter bw = new BufferedWriter(fw)
        ) {
            bw.write(message);
            bw.newLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

But, as you may guess, when I run the program over and over it just appends new line on existing ones not erasing what was inside before the program was ran.但是,正如您可能猜到的那样,当我一遍又一遍地运行程序时,它只是在现有行上添加新行,而不是在程序运行之前擦除里面的内容。

the call of write is done like: write的调用是这样完成的:

studentNamesAndIds.values().forEach(id -> Writer.write(id+","+ DecideGrade.softLookUp(id, studentIdsAndGrades),writeFilePath));

What should I change to get the result I mentioned at the beginning?我应该改变什么才能得到我一开始提到的结果?

PS If I were declaring new FileWriter(destinationPath) without the second argument true then every call of write would erase the content of my file, I would withe the last line inside. PS 如果我在没有第二个参数的情况下声明new FileWriter(destinationPath)true ,那么每次调用write都会删除我文件的内容,我会删除里面的最后一行。

This code should do the job according to your description from the question:这段代码应该根据您对问题的描述来完成这项工作:

public final class Writer 
{
  private static final Set<String> m_AppendMarkers = new HashMap<>();

  public static void write( final String message, final String destinationPath ) 
  {
    final var append = m_AppendMarkers.contains( destinationPath );
    try( final var fw = new FileWriter( destinationPath, append );
      final var bw = new BufferedWriter( fw ) )
    {
      bw.write( message );
      bw.newLine();
      m_AppendMarkers.add( destinationPath );
    } 
    catch( final IOException e ) 
    {
      e.printStackTrace();
    }
  }
}

The set will be empty at each restart of the program, therefore Set::contains will return false for the first attempt to write to the given file;每次重新启动程序时,集合都是空的,因此Set::contains将在第一次尝试写入给定文件时返回false for further attempts, the path to the file was added to the set and the contains check will give you true , so further lines will be appended.为了进一步尝试,文件的路径已添加到集合中,包含检查将为您提供true ,因此将附加更多行。

But to be honest, although this works, you should consider a different design!但老实说,虽然这可行,但您应该考虑不同的设计! So it is not a good idea to open and close a file for each and every new line you write to it.因此,为您写入的每一行新行打开和关闭文件并不是一个好主意。

Also working with a static method is not good design (and that is the reason why you need the Set instead of a simple boolean flag).使用静态方法也不是好的设计(这就是为什么需要Set而不是简单的boolean标志的原因)。

To do it right (or at least a bit better) try this:要做到正确(或至少更好一点)试试这个:

public class YourProgram
{
  private static class Writer implements AutoClosable
  {
    private final String m_DestinationPath;
    private final StringJoiner m_Buffer ) = new StringJoiner( "\n", "", "\n" );

    public Writer( final String destinationPath )
    {
      m_DestinationPath = destinationPath;
    }

    @Overwrite
    public final void close() throws IOException
    {
      try( final var writer = new BufferedWriter( new FileWriter( m_DestinationPath, false ) ) )
      {
        writer.write( m_Buffer.toString() );
      }
    } 

    public static void write( final String message )
    {
      m_Buffer.add( message );
    }
  }
  //  class Writer

  private static Writer m_Writer;

  public static final void main( final String... args )
  {
    try( var w = new Writer( "TheNameOfYourOutputFile" ) )
    {
      m_Writer = w;

      // Your code goes here …
      …
    }
    catch( final IOException e )
    {
      err.println( "Failed to write the output file" );
      e.printStackTrace( err );
    }
    catch( final Throwable t )
    {
      err.println( "Unhandled exception" );
      t.printStackTrace( err );
    }
  }
}
// class YourProgram

Error handling was omitted to keep readability.省略了错误处理以保持可读性。

As long as you do not attempt to write several GigaBytes of data, this should work much more smoothly than the other design.只要您不尝试写入几千兆字节的数据,这应该比其他设计更顺畅。 Ok, it is not crash-save, nothing will be written to the output file if the program will be killed externally.好的,它不是崩溃保存,如果程序将被外部终止,则不会将任何内容写入输出文件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM