2

I tried to write specific bytes to certain position of a file using FileChannel. But actually the file shrink to the last position where I write change. I do it like this:

    Path path = Paths.get("I://music - Copy.mp3");

    System.out.println(Files.size(path)/1024 + "KB");

    try (FileChannel chan = new FileOutputStream(path.toFile()).getChannel()) {
        chan.position(1024 * 1024);

        ByteBuffer b = ByteBuffer.allocate(1024);
        chan.write(b);

        System.out.println("Write 1KB of data");
    }

    System.out.println(Files.size(path)/1024 + "KB");

and this is the output I get:

3670KB
Write 1KB of data
1025KB

Can anybody tell me where it goes wrong??

Henry
  • 43
  • 9

3 Answers3

4

You're missing the FileOutputStream constructor which allows to append to the file. If you create it as above, you overwrite the content of the file.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • I try it and I got the output size increased by 1 KB (3670KB-3671KB). Doesn't that just mean it is written to end of file instead on the specified position? – Henry May 17 '12 at 11:46
1

try to use your FileOutputStream in append mode and avoid specifing current channel position:

new FileOutputStream(path.toFile(), true)

upd. didn't see the prevoius answer

Alex Stybaev
  • 4,623
  • 3
  • 30
  • 44
1

FileOutputStream truncates the file to zero length when not in append mode. It does not overwrite a file's contents so much as it throws away the contents and starts over. You can verify this by calling chan.size() after creating the channel, which will give you 0. [1]

FileChannels can be advanced past the end of a file and told to write there; this causes the file size to increase to position + bytes_written (emphasis mine):

Setting the position to a value that is greater than the current size is legal but does not change the size of the entity. [..] A later attempt to write bytes at such a position will cause the entity to grow to accommodate the new bytes; the values of any bytes between the previous end-of-file and the newly-written bytes are unspecified.

So while it looks like the FileChannel is cutting off your file after writing, it is the FileOutputStream truncating to 0 length, and then the FileChannel expanding it again.

To prevent this from happening, avoid using a FileOutputStream to create a channel. You have a Path, so you can call Files.newByteChannel or FileChannel.open :

Path path = Paths.get("I://music - Copy.mp3");

System.out.println(Files.size(path)/1024 + "KB");

// pick either:
try (FileChannel chan = FileChannel.open(path, StandardOpenOption.WRITE)) {
try (SeekableByteChannel chan = Files.newByteChannel(path, StandardOpenOption.WRITE)) {
    chan.position(1024 * 1024);

    ByteBuffer b = ByteBuffer.allocate(1024);
    chan.write(b);

    System.out.println("Write 1KB of data");
}

System.out.println(Files.size(path)/1024 + "KB");

[1] Note that programs outside the JVM, such as a file explorer, may not indicate this until you flush or close the stream.

JvR
  • 1,187
  • 8
  • 8