我们可以打开一个像Files.newByteChannel(path)
一样简单的频道,这将正常工作。问题是如果我想打开多个频道:
Channel chan1 = Files.newByteChannel(path);
Channel chan2 = Files.newByteChannel(path);
上面的例子通常效果不佳。考虑以下情况:
Channel chan1 = Files.newByteChannel(path); //OK
//Some other process moved path and created an new file with the path
Channel chan2 = Files.newByteChannel(path); //Damn!
出现争用条件。在 Linux 中,我们有类似dup
的系统调用以及fcntl(F_DUPFD, int)
int fd == open(path);
int duplicated = fcntl(fd, F_DUPFD, fd);
这应该有效。
有没有办法在 Java 中做到这一点并避免编写JNI
函数?
UPD:我想要副本的原因是我想同时将数据从一个文件传输到多个SocketChannel
。因此,将单独的FileChannel
转移到单个SocketChannel
似乎是合理的。
Java 没有用于复制 FileChannels 的公共 API。
但是,无需复制文件通道即可同时写入多个套接字通道。
-
FileChannel.transferTo
可以在多个线程中同时使用(至少在类Unix系统上(。正如Javadoc所说,这种方法不会修改通道的位置。 -
FileChannel.read(ByteBuffer, long)
也可以在Unix上同时使用。在 Windows 上,此方法保持通道的位置锁定。 - 或者,可以使用
FileChannel.map
创建同一文件通道的多个字节缓冲区视图。这些 MappedByteBuffers 可以同时使用。
如果你仍然想从Java调用dup
(尽管我不建议这样做(,你可以使用Reflection滥用私有API:
-
int sun.nio.fs.UnixNativeDispatcher.dup(int fd)
是 Unix 上dup
的直接 Java 包装器; -
long sun.nio.ch.FileDispatcherImpl.duplicateHandle(long handle)
是Windows上DuplicateHandle
的Java包装器。