如何防止 MappedByteBuffer 在文件末尾写入空字符?

Posted

技术标签:

【中文标题】如何防止 MappedByteBuffer 在文件末尾写入空字符?【英文标题】:How to prevent MappedByteBuffer put from writing null characters at the end of file? 【发布时间】:2019-12-30 22:50:46 【问题描述】:

我正在使用具有固定缓冲区大小的 Java 的 MappedByteBuffer 来写入文件,作为分配的一部分。它应该逐个字符地写入,因为缓冲区大小可以小于行长。但问题是它将文件末尾缓冲区的剩余位置写为空字符。如何删除那些空字符?

这是一个示例代码:

import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

public class Main 
    public static void main(String[] args) throws IOException 
        int bufferSize = 20;
        RandomAccessFile file = new RandomAccessFile("test.txt", "rw");
        MappedByteBuffer buffer = file.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, bufferSize);

        for (char c : "Line1".toCharArray()) 
            buffer.put((byte) c);
        
        buffer.put((byte)'\n');
        for (char c : "Line2".toCharArray()) 
            buffer.put((byte) c);
        
    

这是输出(使用 Sublime Text utf-8 编码打开):

【问题讨论】:

你试过在getChannel()返回的FileChannel上使用truncate()吗? 【参考方案1】:

正如 Progman 所指出的,截断将解决您看到的问题。我使用 TextWrangler 复制了您看到的内容并显示了隐藏字符,然后我使用以下代码重新编写了它,并且尾随的空值消失了。关键变化是跟踪实际写入的字节数,然后将文件截断为该长度。

int bufferSize = 20;
int bytesWritten = 0;
RandomAccessFile file = new RandomAccessFile("test.txt", "rw");
MappedByteBuffer buffer = file.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, bufferSize);

for (char c: "Line1".toCharArray()) 
    buffer.put((byte) c);
    bytesWritten++;

buffer.put((byte)
    '\n');
bytesWritten++;
for (char c: "Line2".toCharArray()) 
    buffer.put((byte) c);
    bytesWritten++;

buffer.force(); //make sure all is written before messing with truncating
file.getChannel().truncate(bytesWritten);

【讨论】:

我很确定bytesWritten 变量不是必需的,您可以改用buffer.position() 好电话。我用 file.getChannel().truncate(buffer.position()); 试过了它确实奏效了。 @JeremyKahan,我正在执行相同的步骤,但出现错误 - 无法在打开用户映射部分的文件上执行请求的操作。你能帮我解决这个问题吗? @ShubhamPandey 该文件可能已经被其他东西打开了吗?见***.com/questions/1302698/… 感谢您回复@JeremyKahan,这里只有 2 个对象在做这项工作,第一个是 FileChannel,另一个是 MappedByteBuffer。由于我从 fileChannel.truncate() 收到错误,我认为由于 mappedByteBuffer 仍处于打开状态,因此 fileChannel.truncate() 正在引发该错误。但是没有关闭 mappedByteBuffer 的方法。如果我没有得到解决方案,我的最后一个选择是替换这些 java.nio 类并转换为普通的 java.io 类,因为我从几天以来一直在努力解决这个问题。

以上是关于如何防止 MappedByteBuffer 在文件末尾写入空字符?的主要内容,如果未能解决你的问题,请参考以下文章

MappedByteBuffer - 页面到物理内存的映射

无法使用 MappedByteBuffer 读取块中的文件

在文件作为 RandomAccessFile 打开并映射为 MappedByteBuffer 后重命名文件

如何正确关闭 MappedByteBuffer?

MappedByteBuffer的实际开发遇到的问题

MappedByteBuffer文件句柄释放问题