Java中的重复文件通道

时间:2019-02-09 11:11:42

标签: java file io jvm

我们可以打开一个简单的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似乎是合理的。

1 个答案:

答案 0 :(得分:2)

Java没有用于复制FileChannel的公共API。

但是,无需复制FileChannel即可同时写入多个SocketChannel。

  1. FileChannel.transferTo可以在多个线程中同时使用(至少在类似Unix的系统上)。如Javadoc所说,此方法不会修改频道的位置。
  2. FileChannel.read(ByteBuffer, long)也可以在Unix上同时使用。在Windows上,此方法可保存频道的位置锁定。
  3. 或者,可以使用FileChannel.map创建同一FileChannel的多个ByteBuffer视图。这些MappedByteBuffer可以同时使用。

如果您仍想从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包装器。