1

The Files.write & Files.writeString methods in Java 7+ are a concise handy way to write text to a file.

try
{
    Files.write (
            Paths.get ( "/Users/My_UserName/Example.txt" ) ,
            List.of( "Hello world" , Instant.now().toString() ) ,
            StandardCharsets.UTF_8 ,
            StandardOpenOption.WRITE ;
}
catch ( IOException e )
{
    throw new RuntimeException ( e );
}

Unfortunately, I cannot get this to work the first time, before the file exists. I get an exception thrown:

java.nio.file.NoSuchFileException

My goal is always blow away any existing file, to write a new fresh file.

I tried adding TRUNCATE_EXISTING.

try
{
    Files.write (
            Paths.get ( "/Users/My_UserName/Example.txt" ) ,
            List.of( "Hello world" , Instant.now().toString() ) ,
            StandardCharsets.UTF_8 ,
            StandardOpenOption.WRITE,
            StandardOpenOption.TRUNCATE_EXISTING );  // <--- Combining Open-options.
}
catch ( IOException e )
{
    throw new RuntimeException ( e );
}

But that too fails when the file does not already exist.

Is there some combination of OpenOption/StandardOpenOption objects to make use of these convenient Files methods?

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154

1 Answers1

4

CREATE, WRITE, & TRUNCATE_EXISTING

So the behaviour you want is the effect of using CREATE, and TRUNCATE_EXISTING options with WRITE.

    Files.write (
            Paths.get ( "/Users/My_UserName/Example.txt" ) ,
            List.of ( "Hello world" , Instant.now ( ).toString ( ) ) ,
            StandardCharsets.UTF_8 ,
            StandardOpenOption.CREATE ,
            StandardOpenOption.WRITE ,
            StandardOpenOption.TRUNCATE_EXISTING
    );

Fortunately, this is the default behaviour, as documented by both your API references like Files.write :

If no options are present then this method works as if the CREATE, TRUNCATE_EXISTING, and WRITE options are present.

So simply don’t override that default - don’t give that WRITE, so

    Files.write (
            Paths.get ( "/Users/My_UserName/Example.txt" ) ,
            List.of ( "Hello world" , Instant.now ( ).toString ( ) ) ,
            StandardCharsets.UTF_8  
            // <--- Omitting the 3 CREATE, WRITE, & TRUNCATE_EXISTING arguments.
    );

Also, the Charset parameter is documented as optional, defaulting to UTF-8, in Java 8+ (but not the original Java 7 arrival of this class). So we can further shorten your code to this:

    Files.write (
            Paths.get ( "/Users/My_UserName/Example.txt" ) ,
            List.of ( "Hello world" , Instant.now ( ).toString ( ) ) 
            // <--- Omitting the StandardCharsets.UTF_8  argument.
            // <--- Omitting the 3 CREATE, WRITE, & TRUNCATE_EXISTING arguments.
    );
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
racraman
  • 4,988
  • 1
  • 16
  • 16
  • I'm pretty certain that from 17, the default *would* be UTF-8, so yes, that might be a redundant parameter too. OTOH, it might give some (particularly Windows) users a problem if they *don't* specify an 8-bit encoding – g00se Aug 05 '23 at 22:45
  • Indeed. Some newer I/O routines default to UTF-8, some default to the platform default charset, and up to Java 17 inclusive, that's a bit of a crapshoot. I work on a lot of legacy code, don't have a clear mental model for which category (UTF-8/platform default) of routines any given method falls into, so I have a bad habit of writing StandardCharsets.UTF_8 regardless. – Arfur Narf Aug 05 '23 at 22:49
  • @ArfurNarf For `Files.*` specifically, `UTF-8` has _always_ been the default. From Java18 or whatnot, it's the default everywhere, but Files has always defaulted to that. – rzwitserloot Aug 05 '23 at 22:53
  • Thanks. We have a lot of java.io of the form `out = new ThisWriter(new ThatStream(new FileThing)))`. One day I'll get annoyed enough to blitz it all. I only recently decided I couldn't stand seeing "UTF-8" as a string, replacing it by StandardCharsets.UTF_8 (with the intent of getting rid of the never-going-to-happen exception handling). – Arfur Narf Aug 05 '23 at 22:58
  • @g00se - [JEP 400](https://openjdk.org/jeps/400), in Java 18 – Arfur Narf Aug 05 '23 at 22:59
  • 1
    (A) I found the last of the `write` methods does indeed document that `Charset` is optional, defaulting to UTF-8, going back to Java 8 (not the original Java 7 arrival of this class). So I replaced your last paragraph. (B) Thanks so much for your Answer. My mind was not processing the writing in the Javadoc, but your Answer makes it all clear now. – Basil Bourque Aug 06 '23 at 00:23