0

I'm trying to copy part of a file from a filechannel to another (writing a new file, in effect, equals to the first one).

So, I'm reading chunks of 256kb, then putting them back into another channel

static void openfile(String str) throws FileNotFoundException, IOException {
    int size=262144;
    FileInputStream fis = new FileInputStream(str);
    FileChannel fc = fis.getChannel();
    byte[] barray = new byte[size];
    ByteBuffer bb = ByteBuffer.wrap(barray);

    FileOutputStream fos = new FileOutputStream(str+"2" /**/);
    FileChannel fo = fos.getChannel();

    StringBuilder sb;
    while (fc.read(bb) != -1) {            
        fo.write(bb /**/);            
        bb.clear();
    }
}

The problem is that fo.write (I think) writes again from the beginning of the channel, so the new file is made only of the last chunk read.

I tried with fo.write (bb, bb.position()) but it didn't work as I expected (does the pointer returns to the beginning of the channel?) and with FileOutputStream(str+"2", true) thinking it would append to the end of the new file, but it didn't.

I need to work with chunks of 256kb, so I can't change much the structure of the program (unless I am doing something terribly wrong)


Resolved with bb.flip();

while (fi.read(bb) != -1) {
        bb.flip();
        fo.write(bb);
        bb.clear();
    }
Jack Allen
  • 549
  • 2
  • 5
  • 19
Mewster
  • 1,057
  • 3
  • 11
  • 21
  • Why do you have to use a FileChannel? Maybe this: http://stackoverflow.com/questions/2520305/java-io-to-copy-one-file-to-another is what youre looking for? – Sören Titze Oct 13 '13 at 19:10
  • Because of this article I have found. http://nadeausoftware.com/articles/2008/02/java_tip_how_read_files_quickly I'm checking that one now. – Mewster Oct 13 '13 at 19:11
  • 1
    [`IOUtils.copy`](http://commons.apache.org/proper/commons-io/javadocs/api-1.4/org/apache/commons/io/IOUtils.html) should be enough. Related http://stackoverflow.com/questions/1605332/java-nio-filechannel-versus-fileoutputstream-performance-usefulness?rq=1 ? –  Oct 13 '13 at 19:11
  • The problem of the first article is that it transfers everything instead of chunks. Checking now RC's solution – Mewster Oct 13 '13 at 19:14
  • It seems I had to use bb.flip(); if you write it I'll accept the answer – Mewster Oct 13 '13 at 19:22
  • I am really wondered why do we really need `ByteBuffer` here?! you would simply find the possition from the src file and start reading, and write to the target file. exactly read bunch of data and write it with same time. –  Oct 13 '13 at 19:35
  • Because I need to work chunk-to-chunk with the file (for example, I would want to change every "a" into "b") – Mewster Oct 13 '13 at 19:39
  • @user1722791 instead of answering your question in the question text, you can also answer it as an answer, and then accept it. – Paul Wagland Oct 13 '13 at 20:55

2 Answers2

1

This is a very old question but I stumbled upon it and though I might add another answer that has potentially better performance using using FileChannel.transferTo or FileChannel.transferFrom. As per the javadoc:

This method is potentially much more efficient than a simple loop that reads from the source channel and writes to this channel. Many operating systems can transfer bytes directly from the source channel into the filesystem cache without actually copying them.

public static void copy(FileChannel src, FileChannel dst) throws IOException {
    long size = src.size();
    long transferred = 0;
    do {
        transferred += src.transferTo(0, size, dst);
    } while (transferred < size);
}

on most cases a simple src.transferTo(0, src.size(), dst); will work if non of the channels are non-blocking.

krico
  • 5,723
  • 2
  • 25
  • 28
0

The canonical way to copy between channels is as follows:

while (in.read(bb) > 0 || bb.position() > 0)
{
    bb.flip();
    out.write(bb);
    bb.compact();
}

The simplified version in your edited answer doesn't work in all circumstances, e.g. when 'out' is non-blocking.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • what do you mean with non-blocking? – Mewster Oct 13 '13 at 23:11
  • Look it up. Some channels, e.g. `SocketChannels,` can be put into non-blocking mode, which means that `write()` can return without having written all the data, or indeed any of it. This makes `compact()` essential instead of `clear()`, and makes the extra test for `position() > 0` essential at end of stream as well. – user207421 Oct 14 '13 at 01:31