【问题标题】:FileChannel.open(path, CREATE|CREATE_NEW) without WRITE option throws NoSuchFileExceptionFileChannel.open(path, CREATE|CREATE_NEW) 没有 WRITE 选项会抛出 NoSuchFileException
【发布时间】:2023-03-05 03:30:01
【问题描述】:

我有以下代码:


  @Nonnull
  @SneakyThrows
  private Pair<InputStream, Long> probeSize(@Nonnull final InputStream image) {
    final String tmpId = UUID.randomUUID().toString();
    final File probeFile = new File(tmpDir, tmpId + ".jpg");

    try (final FileChannel outChannel = FileChannel.open(probeFile.toPath(), CREATE);
         final ReadableByteChannel innChannel = Channels.newChannel(image)) {
      outChannel.transferFrom(innChannel, 0, Long.MAX_VALUE);
    }

    final Long fileSize = probeFile.length();
    return Pair.of(new FileInputStream(probeFile), fileSize);
  }

此代码始终抛出以下异常:

Caused by: java.nio.file.NoSuchFileException: /tmp/4bbc9008-e91c-4f18-b0f2-c61eed35066e.jpg
    at sun.nio.fs.UnixException.translateToIOException(Unknown Source)
    at sun.nio.fs.UnixException.rethrowAsIOException(Unknown Source)
    at sun.nio.fs.UnixException.rethrowAsIOException(Unknown Source)
    at sun.nio.fs.UnixFileSystemProvider.newFileChannel(Unknown Source)

查看FileChannel.open(path, option) 的javadoc 和相关的StandardOpenOption,没有任何文档暗示要创建文件,您还必须打开它进行写入。

唯一有效的选项:

  • FileChannel.open(probeFile.toPath(), CREATE, WRITE)
  • FileChannel.open(probeFile.toPath(), CREATE_NEW, WRITE)

我只是通过UnixChannelFactory.newFileChannel 确定了这一点,并注意到以下内容:

UnixChannelFactory:

protected static FileDescriptor open(int dfd,
                                         UnixPath path,
                                         String pathForPermissionCheck,
                                         Flags flags,
                                         int mode)
        throws UnixException
    {
        // map to oflags
        int oflags;
        if (flags.read && flags.write) {
            oflags = O_RDWR;
        } else {
            oflags = (flags.write) ? O_WRONLY : O_RDONLY;
        }
        if (flags.write) {
            if (flags.truncateExisting)
                oflags |= O_TRUNC;
            if (flags.append)
                oflags |= O_APPEND;

            // create flags
            if (flags.createNew) {
                byte[] pathForSysCall = path.asByteArray();

                // throw exception if file name is "." to avoid confusing error
                if ((pathForSysCall[pathForSysCall.length-1] == '.') &&
                    (pathForSysCall.length == 1 ||
                    (pathForSysCall[pathForSysCall.length-2] == '/')))
                {
                    throw new UnixException(EEXIST);
                }
                oflags |= (O_CREAT | O_EXCL);
            } else {
                if (flags.create)
                    oflags |= O_CREAT;
            }
        }

这表明,除非您指定 WRITE 选项,否则永远不会创建该文件。

这是一个错误还是预期的功能,FileChannel.open 无法创建文件,除非它被打开以进行写入?

【问题讨论】:

    标签: java nio filechannel


    【解决方案1】:

    我在看JDK 7 Javadoc for FileChannel.open(...)

    该方法的文档说:

    READWRITE 选项确定是否应打开文件进行读取和/或写入。如果数组中不包含任何选项(或APPEND 选项),则打开文件进行读取。

    CREATE_NEW 的文档说:

    当文件只为阅读而打开时,该选项将被忽略。

    CREATE 的文档说:

    如果CREATE_NEW 选项也存在或打开文件仅供阅读,则忽略此选项。

    将这三个 sn-ps 放在一起,是的,这是预期的行为。

    【讨论】:

      猜你喜欢
      • 2013-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-15
      • 1970-01-01
      • 2017-11-19
      • 1970-01-01
      相关资源
      最近更新 更多