问题描述
我有以下代码:
@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,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
除非打开文件才能创建文件?
解决方法
我正在查看 JDK 7 Javadoc for FileChannel.open(...)
。
该方法的文档说:
READ
和 WRITE
选项确定是否应打开文件进行读取和/或写入。如果数组中不包含任何选项(或 APPEND
选项),则打开文件进行读取。
CREATE_NEW
的文档说:
当文件打开仅供阅读时忽略此选项。
CREATE
的文档说:
如果 CREATE_NEW
选项也存在或打开文件仅用于读取,则忽略此选项。
将这三个片段放在一起,是的,这是预期的行为。