FileChannel.transferTo requests a byte range be copied to another channel. A return smaller than the requested count is permitted, so a complete copy needs explicit progress accounting.
Java FileChannel.transferTo: verify the byte count on every pass
Operational contract
The method creates a new destination, captures the source size, and advances by the actual transferred count. It fails on zero progress to avoid an infinite loop. The size is only an observation: if another process changes the source during transfer, the result may not represent one stable version. For reliable publication, copy from an immutable source into a staged destination and then apply an accepted move contract. A failed transfer can leave a partial destination, so the owner must remove or quarantine it.
Failure case
A 47-megabyte archive is copied to a new review location. A transfer call moves only part of the requested range. Without the loop, the review location has a plausible filename but missing tail bytes. The loop checks every returned count; it does not claim that this operation verifies content identity or durability.
Java code
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
public class ArchiveChannelTransfer {
public static long copy(Path source, Path destination) throws IOException {
try (FileChannel input = FileChannel.open(source, StandardOpenOption.READ);
FileChannel output = FileChannel.open(destination,
StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)) {
long expected = input.size();
long copied = 0;
while (copied < expected) {
long count = input.transferTo(copied, expected - copied, output);
if (count <= 0) throw new IOException("Transfer stopped before expected size");
copied += count;
}
return copied;
}
}
}Performance and ownership cost
The method performs O(B) data movement for B bytes and uses O(1) application buffer space. An operating system may optimize some transfers, but that is platform-dependent. File creation and failure cleanup remain separate costs.
Common Mistakes
- Do not assume one transferTo call copies its full count.
- Do not trust a size sampled before concurrent mutation as a snapshot.
- Do not leave a partial destination available as a valid archive.
Connected lessons
- Java FileChannel.write: finish the buffer before reporting success
- Java Files.move: atomic publication is a filesystem contract
- Java file I/O: UTF-8, streaming reads, and path ownership
- Java positioned FileChannel.read: detect a short record without moving the cursor
- Java FileChannel.force: distinguish written bytes from forced storage
- Java FileLock: coordinate one byte range with a shared protocol
- Java FileChannel.truncate: cut only after validating the recovery offset
- Java AsynchronousFileChannel: own the buffer through completion
- Java file channels and JVM observations quiz
- Advanced Java
