简体   繁体   English

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

[英]Writing to and reading from a text file using java.nio.FileChannel from two different JVMs concurrently

I'm trying to write two programs, one that writes to a text file, and the other one that reads from it. 我正在尝试编写两个程序,一个程序写入文本文件,另一个程序从该文件读取。 I've tried using java.io, but ran into concurrency problems. 我尝试使用java.io,但遇到了并发问题。 However, when I switched to java.nio, I ran into even bigger problems, probably not related to concurrency since I lock the file in both programs when trying to read/write, but the actual way of reading from or writing to a file. 但是,当我切换到java.nio时,遇到了更大的问题,可能与并发无关,因为在尝试读取/写入时,我在两个程序中都锁定了文件,但实际上是从文件中读取或写入文件。

Writer program code (the part that is relevant): 编写器程序代码(相关部分):

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 is a simple class with some fields and an overridden toString() method and airbornUnitsList is a list of those objects, so I'm basically iterating through the list, appending the FlyingObject objects to StringBuilder object, removing the last "new line" from StringBuilder, putting it into the buffer and writing to the file. FlyingObject是一个简单的类,具有一些字段和重写的toString()方法,airbornUnitsList是这些对象的列表,因此我基本上遍历该列表,将FlyingObject对象附加到StringBuilder对象,从中删除最后一个“换行” StringBuilder,将其放入缓冲区并写入文件。 As you can see, I have locked the file prior to writing to the file and then unlocked it afterwards. 如您所见,在写入文件之前,我已将文件锁定,然后再将其解锁。

Reader program code (the part that is relevant): 读者程序代码(相关部分):

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);
}

Even when I manually write a few lines in the file and then run the Reader program, it doesn't read it correctly. 即使我手动在文件中写了几行然后运行Reader程序,它也无法正确读取它。 What could be the issue here? 这里可能是什么问题?

EDIT: After playing with buffer size a bit, I realized that the file is read wrongly because the buffer size is smaller than the content in the file. 编辑:在播放了一些缓冲区大小后,我意识到该文件被错误地读取,因为缓冲区大小小于文件中的内容。 Could this be related to file encoding? 这可能与文件编码有关吗?

I found out what the problem was. 我发现了问题所在。

Firstly, in the writer program, I needed to add the fileChannel.truncate(0); 首先,在fileChannel.truncate(0);程序中,我需要添加fileChannel.truncate(0); after opening the file channel. 打开文件通道后。 That way, I would delete the old content of the file and write it from the beginning. 这样,我将删除文件的旧内容并从头开始写入。 Without that line, I would just overwrite the old content of the file with new content when writing and if the new content is shorter than the old content, the old content would still remain in those positions not covered by new content. 如果没有这一行,我将在写入时用新内容覆盖文件的旧内容,并且如果新内容比旧内容短,则旧内容仍将保留在新内容未覆盖的那些位置。 Only if I was sure that the new content is at least as big as the old content and would rewrite it completely, I wouldn't need the truncate option, but that wasn't the case for me. 仅当我确定新内容至少与旧内容一样大并且可以完全重写它时,才不需要truncate选项,但对我而言并非如此。

Secondly, regarding the reader, the reason it wasn't reading the whole file is because the while loop would end before the last part of the file content was appended to the StringBuilder . 其次,对于读者而言,之所以没有读取整个文件,是因为while循环将在文件内容的最后一部分附加到StringBuilder After I modified the code and changed the order of operations a bit, like this: 在修改代码并更改了操作顺序后,如下所示:

numOfBytesRead = 0;

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

it worked without problems. 它没有问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM