5

I'm working on a sc2replay parsing tool. I build it on top of MPQLIB http://code.google.com/p/mpqlib/

Unfortunately the tool uses filechannels to read through the bzip files, and uses map(MapMode.READ_ONLY, hashtablePosition, hashTableSize);

After calling that function closing the file channel does not release the file in the process. To be specific I cannot rename/move the file.

The problem occurs in Java 7 and it works fine on Java 6.

Here is a simple code snippet to replicate it:

    FileInputStream f = new FileInputStream("test.SC2Replay");
    FileChannel fc = f.getChannel();

    fc.map(MapMode.READ_ONLY, 0,1);

    fc.close();

    new File("test.SC2Replay").renameTo(new File("test1.SC2Replay"));

commenting out the fc.map will allow you to rename the file.

P.S. from here Should I close the FileChannel?

It states that you do not need to close both filechannel and filestream because closing one will close another. I also tried closing either or both and still did not worked.

Is there a workaround on renaming the file after reading the data using FileChannel.map on Java 7, because every one seems to have Java 7 nowadays?

Community
  • 1
  • 1
  • Does the closing of the channel or the stream throw some kind of RuntimeException? – 0xCAFEBABE Oct 25 '12 at 09:24
  • no exception generated. I think it might be a bug on java 7 itself. I'm thinking porting everything to .NET xD –  Oct 25 '12 at 09:31

3 Answers3

2

Good day,

it seems that FileChannel.map causes the problem on java 7. if you use FileChannel.map, you can no longer close the the file.

a quick work around is instead of using FileChannel.map(MapMode.READ_ONLY, position, length)

you can use

ByteBuffer b = ByteBuffer.allocate(length); 
fc.read(b,position);
b.rewind();
0

It's a documented bug. The bug report referes to Java 1.4, and they consider it a documentation bug. Closing the filechannel does not close the underlying stream.

0xCAFEBABE
  • 5,576
  • 5
  • 34
  • 59
  • 1
    @tskaahyeah The bug report referred to here is dubious and marked as 'cannot reproduce'. Closing a `FileChannel` closes the underlying file descriptor: I read the source code earlier this week. The issue here is that closing a *mapped* file doesn't release the *mapping*. – user207421 Oct 25 '12 at 09:51
  • from above i tried closing both filechannel and fileinputstream, also tried closing fileinputstream only and closing filechannel only. All did not work. the code works well on java6 but not on java7 –  Oct 25 '12 at 09:53
0

If you're using Sun JRE, you can cheat by casting to their implementation and telling it to release itself. I'd only recommend doing this if you're not reliant on the file being closed or never plan to use another JRE.

At some point, I hope that something like this will make it into the proper public API.

try (FileInputStream stream = new FileInputStream("test.SC2Replay");
     FileChannel channel = stream.getChannel()) {

    MappedByteBuffer mappedBuffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, 1);
    try {
        // do stuff with it
    } finally {
        if (mappedBuffer instanceof DirectBuffer) {
            ((DirectBuffer) mappedBuffer).cleaner().clean();
        }
    }
}
Hakanai
  • 12,010
  • 10
  • 62
  • 132