3

Here is my code:

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

public class ExplicitChannelRead {

    public static void main(String[] args) {
        
        int count;
        Path filePath = null;
        
        // First, obtain a path to a file.
        try {
            filePath = Paths.get("test1.txt");
        }
        catch(InvalidPathException e) {
            System.out.println("Path error: "+e);
            return;
        }
        
        // Next, obtain a channel to that file within a try-with-resources block.
        try(SeekableByteChannel fChan = 
                Files.newByteChannel(filePath, StandardOpenOption.CREATE_NEW)) {
            
            // Allocate a buffer.
            ByteBuffer mBuf = ByteBuffer.allocate(128);
            
            while((count=fChan.read(mBuf)) != -1) {
                
                //Rewind the buffer so that it can be read.
                mBuf.rewind();
                
                for(int i=0; i<count; i++) System.out.print((char)mBuf.get());
                
            }
            
            System.out.println();
            
            
        } catch (IOException e) {
            e.printStackTrace();
//          System.out.println("I/O error: "+e);
        }
        

    }

}

On running the above code I get this exception:

java.nio.file.NoSuchFileException: test1.txt
    at java.base/sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:85)
    at java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:103)
    at java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:108)
    at java.base/sun.nio.fs.WindowsFileSystemProvider.newByteChannel(WindowsFileSystemProvider.java:235)
    at java.base/java.nio.file.Files.newByteChannel(Files.java:375)
    at java.base/java.nio.file.Files.newByteChannel(Files.java:426)
    at fileNIO.ExplicitChannelRead.main(ExplicitChannelRead.java:31)

I don't understand why test1.txt file is not being created as it doesn't exist currently and I am using the StandardOpenOption.CREATE_NEW option?

When I use StandardOpenOption.WRITE option along with StandardOpenOption.CREATE_NEW then I see the file text1.txt being created and at that time I get the exception:

Exception in thread "main" java.nio.channels.NonReadableChannelException

This exception I understand its cause because I have opened the file in write mode and in the code I am performing read operation on the file.

It seems to me that a new file can't be created when the file is opened in read mode.

Shri
  • 109
  • 9
  • Umm ... if you have just created the file, what do you expect to read from it? It will be empty. – Stephen C Jul 18 '22 at 07:37
  • Yes, test1.txt would be empty but then I should not be getting that exception: java.nio.file.NoSuchFileException: test1.txt , right? – Shri Jul 18 '22 at 07:46
  • No you shouldn't. According to the javadoc (and my reading of the code) the file should be opened for read, since you don't specify either WRITE or APPEND. So you shouldn't get `NonReadableChannelException`. However, >I think< you could get `NoSuchFileException` if you try to create a file in a directory that does not exist. Please add the **complete** stacktraces for the 2 exceptions to the question. – Stephen C Jul 18 '22 at 07:55
  • I am using JDK 8 and I have added the complete stack trace of the issue above. – Shri Jul 18 '22 at 08:07
  • The combination of `CREATE_NEW` and read access seems pointless to me, as it there's only ever two possible outcomes (even hypothetically, if you follow the docs, ignoring platform specifics): Either the file existed before, then you'll get an error or the file *didn't* exist then you'll get an empty file that's just opened for reading. – Joachim Sauer Jul 18 '22 at 08:14
  • (`Standard`)`CopyOptions` are for copying, not reading. – dan1st Jul 18 '22 at 08:15

1 Answers1

5

I have reproduced what you are seeing (on Linux with Java 17).

As I noted in the comments, the behavior seems to contradict what the javadocs say what should happen, but what I discovered is this:

  • With READ or neither READ or WRITE, a NoSuchFileException is thrown.

  • With WRITE (and no READ), the file is created but then NonReadableChannelException is thrown.

  • With both READ and WRITE, it works. At least ... it did for me.

I guess this sort of makes sense. You need READ to read the file and WRITE to create it. And the javadocs state that READ is the default if you don't specify READ, WRITE or APPEND.

But creating an empty file1 with CREATE_NEW and then immediately trying to read it is a use-case that borders on pointless. So it not entirely surprising that they didn't (clearly) document how to achieve this.


1 - As a comment noted, CREATE_NEW is specified to fail if the file already exists. If you want "create it if it doesn't exist", then you should use CREATE instead.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • Yeah, I agree that the docs don't show that both READ and WRITE options are required to create a file. Now I am able to create a file if it doesn't exist already. Thanks, Stephen. – Shri Jul 18 '22 at 08:29
  • 1
    @Shri: You say you want to create the file if it doesn't exist, but that's not what `CREATE_NEW` does! It creates the file and **fails** if it already exists! If you want to create *or* read the existing one, use `CREATE` instead. That's also why `CREATE_NEW` makes even less sense in combination with reading than `CREATE` does ... – Joachim Sauer Jul 18 '22 at 08:56