java - 同时使用 java.nio.FileChannel 从两个不同的 JVM 写入和读取文本文件

标签 java concurrency

我正在尝试编写两个程序,一个程序写入文本文件,另一个程序读取文本文件。我尝试过使用 java.io,但遇到了并发问题。然而,当我切换到 java.nio 时,我遇到了更大的问题,可能与并发性无关,因为我在尝试读/写时锁定了两个程序中的文件,而是与读取或写入文件的实际方式有关。

编写器程序代码(相关部分):

Path filePath = Paths.get("map.txt");
FileChannel fileChannel;
ByteBuffer buffer;
StringBuilder existingObjects = new StringBuilder();

while (true) {
    for (FlyingObject fo : airbornUnitsList) {
        existingObjects.append(fo.toString() + System.lineSeparator());
    }
    if(existingObjects.length() > System.lineSeparator().length())
        existingObjects.setLength(existingObjects.length() - System.lineSeparator().length());
    buffer = ByteBuffer.wrap(existingObjects.toString().getBytes());
    fileChannel = FileChannel.open(filePath, StandardOpenOption.READ, StandardOpenOption.WRITE);
    fileChannel.lock();
    fileChannel.write(buffer);
    fileChannel.close();
    existingObjects.delete(0, existingObjects.length());
    sleep(100);
}
FlyingObject 是一个简单的类,带有一些字段和一个重写的 toString() 方法,airbornUnitsList 是这些对象的列表,所以我基本上是迭代列表,将 FlyingObject 对象附加到 StringBuilder 对象,删除最后一个“new” line”来自 StringBuilder,将其放入缓冲区并写入文件。正如您所看到的,我在写入文件之前锁定了文件,然后又将其解锁。

阅读器程序代码(相关部分):

Path filePath = Paths.get("map.txt");
FileChannel fileChannel;
ByteBuffer buffer;
StringBuilder readObjects = new StringBuilder();

while (true) {
    fileChannel = FileChannel.open(filePath, StandardOpenOption.READ, StandardOpenOption.WRITE);
    fileChannel.lock();
    buffer = ByteBuffer.allocate(100);
    numOfBytesRead = fileChannel.read(buffer);

    while (numOfBytesRead != -1) {
        buffer.flip();
        readObjects.append(new String(buffer.array()));
        buffer.clear();
        numOfBytesRead = fileChannel.read(buffer);
    }
    fileChannel.close();
    System.out.println(readObjects);
}

即使我在文件中手动写入几行然后运行 ​​Reader 程序,它也无法正确读取。这里可能出现什么问题?

编辑:稍微调整一下缓冲区大小后,我意识到文件读取错误,因为缓冲区大小小于文件中的内容。这可能与文件编码有关吗?

最佳答案

我发现问题所在了。

首先,在writer程序中,我需要在打开文件 channel 后添加fileChannel.truncate(0);。这样,我会删除文件的旧内容并从头开始写入。如果没有该行,我将在写入时用新内容覆盖文件的旧内容,如果新内容比旧内容短,则旧内容仍将保留在新内容未覆盖的位置。只有当我确定新内容至少与旧内容一样大并且会完全重写它时,我才不需要截断选项,但对我来说情况并非如此。

其次,对于阅读器来说,它没有读取整个文件的原因是因为 while 循环将在文件内容的最后一部分附加到 StringBuilder 之前结束。我修改了代码并稍微更改了操作顺序后,如下所示:

numOfBytesRead = 0;

    while (numOfBytesRead != -1) {
        numOfBytesRead = fileChannel.read(buffer);
        buffer.flip();
        readObjects.append(new String(buffer.array()));
        buffer.clear();
    }

它运行没有问题。

关于java - 同时使用 java.nio.FileChannel 从两个不同的 JVM 写入和读取文本文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57760284/

相关文章:

java - Vaadin WebApplication - 可以使用离线模式吗?

java正则表达式匹配文件路径

java - ExecutorService 中的 InterruptedException

python - 在超时中包装 asyncio.gather

java - 同时向一个 URL 发送多个 POST 请求

ruby-on-rails - Rails 4 并发问题

multithreading - 您如何订阅线程间的状态更改?

java - 编程的 Android 应用程序不显示在 AVD 中

java - 将 ArrayList 嵌入式循环转换为 Iterator

java - JTree:TreeCellRenderer 未按预期执行