1

I am using Java's MappedByteBuffer with a fixed buffer size to write into a file, as part of an assignment. It should write character by character since the buffer size can be smaller than the line length. But the problem is that it writes the remaining positions of the buffer at the end of the file as null characters. How can I remove those null characters?

Here's an example code:

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

And here's the output (opened with Sublime Text utf-8 encoding):

Fabrício
  • 91
  • 2
  • 7

1 Answers1

2

As indicated by Progman, truncating will fix the issue you are seeing. I duplicated what you saw using TextWrangler and show hidden characters, and then I redid it using the following code and the trailing nulls disappeared. The key change was to track the number of bytes actually written and then truncate the file to that length.

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);
Jeremy Kahan
  • 3,796
  • 1
  • 10
  • 23
  • 1
    I’m pretty sure the `bytesWritten` variable is not necessary and you can use `buffer.position()` instead. – VGR Dec 31 '19 at 00:53
  • Good call. I tried it with file.getChannel().truncate(buffer.position()); and it did work. – Jeremy Kahan Dec 31 '19 at 01:33
  • @JeremyKahan, I am following the same steps but getting error - The requested operation cannot be performed on a file with a user-mapped section open. Could you please help me on this. – Shubham Pandey Dec 28 '20 at 12:00
  • @ShubhamPandey is the file perhaps already open by something else? See https://stackoverflow.com/questions/1302698/system-io-exception-error-the-requested-operation-cannot-be-performed-on-a-fil – Jeremy Kahan Dec 29 '20 at 13:11
  • Thanks for you reply @JeremyKahan , there are only 2 objects which are doing the job here, 1st the FileChannel, other the MappedByteBuffer. Since I am getting error from fileChannel.truncate(), I think since the mappedByteBuffer is still open, fileChannel.truncate() is throwing that error. However there is no method to close mappedByteBuffer. If I dont get a solution my last option would be to replace these java.nio classes and swtich to normal java.io classes, because I am struggling with this issue since days. – Shubham Pandey Dec 30 '20 at 03:41
  • I am sorry, but I don't know. It was working for me, but perhaps your OS is different or something has changed since I wrote. @Progman do you have any ideas? – Jeremy Kahan Dec 31 '20 at 08:43