Java file transfer client not reading all bytes

I have a file sender and receiver. From the 10 or so posts I've found on the internet, this is the correct way to send files through sockets in Java. Take a look at the code snippets below.

Sender:

OutputStream bos = clientSocket.getOutputStream();
FileInputStream fis = new FileInputStream(sendingFile);
BufferedInputStream bis = new BufferedInputStream(fis);

int n;
int total = 0;
byte[] buffer = new byte[8192];

while ((n = bis.read(buffer)) > 0) {
    bos.write(buffer, 0, n);
    System.out.println("Sending File... ");
    total += n;
    System.out.println(total);
}

Receiver:

InputStream bis = clientSocket.getInputStream();
FileOutputStream fos = new FileOutputStream(fileOut);
BufferedOutputStream bos = new BufferedOutputStream(fos);

int n;
int total = 0;
byte[] buffer = new byte[8192];
while ((n = bis.read(buffer)) > -1) {
    bos.write(buffer, 0, buffer.length);
    System.out.println("Writing File... ");
    total += n;
    System.out.println(total);
    if (total == fileSize) {
        break;
    }
}
System.out.println("File Received");

Here's the output from the Sender

Sending File: D:\Users\Administrator\Documents\AAAAAAAAAAAAAAAAAAAAAAAAAAA.avi
File Size: 54236160
Sending File...
8192
Sending File...
16384
....................some time later
Sending File...
54231040
Sending File...
54236160
File Sent

The last number, 54236160, is the exact size of the file being sent. Now here is the last line on the receiver side.

Writing file...
54234710

So for this particular file, it always stops at this size and so because the entire file isn't sent, the receiver never stops waiting for data. I dont understand how the sender is sending the correct amount of data but the receiver doesn't get it all. I never see "File Received" on the receiver side and the amount of data that the receiver reads is never equal to the amount being sent.

This issue occurs for any file I sent and if I send really small files, such as those that are in bytes not kb, I dont see any "Writing File..." on the receiver side at all, almost like it just ignores the stream.

Yet every post on the internet says this is the proper way to send files. Oh and if I close the sending socket and/or stream, which I dont want to do because there are other things the client and server need to do, it still doesnt fix the problem anyway.

The other thing I've noticed is that while the sender always seems to indicate its writing the full amount to the buffer (always multiples of 8192 for "total"), the receiver doesnt.

Below is the code that gets the filesize and filename. Perhaps this is where the error lies? I dont see how since its all done before we start sending and receiving the file.

System.out.println("Receiving File");
try {
    clientScanner.nextLine();
    String fileName = clientScanner.nextLine();
    int fileSize = clientScanner.nextInt();
    System.out.println("File: " + fileName + " Size: " + fileSize);
    File fileOut = new File("C:\\Users\\owner\\AppData\\Local\\temp\\" + fileName);

    InputStream bis = clientSocket.getInputStream();
    FileOutputStream fos = new FileOutputStream(fileOut);
    BufferedOutputStream bos = new BufferedOutputStream(fos);
Jon Skeet
people
quotationmark

You shouldn't try to read more data than expected. Your loop should be:

int n;
int bytesLeft = fileSize;
byte[] buffer = new byte[8192];
while (bytesLeft > 0) {
    int n = bis.read(buffer, 0, Math.min(buffer.length, bytesLeft));
    if (n < 0) {
        throw new EOFException("Expected " + bytesLeft + " more bytes to read");
    }
    bos.write(buffer, 0, n);
    System.out.println("Writing File... ");
    bytesLeft -= n;
    System.out.println(total " bytes left to read");
}

(You can adjust the output to show how many bytes you've read instead of how many you've got left to read if you want, but I think this approach is simpler.)

If that still doesn't get you all the data, you should flush the output stream in the writing code - I wouldn't expect you'd have to, but if you're not closing the socket, I guess it could be buffering it forever.

If the loop terminates but the file appears to be incomplete, make sure you're closing bos after all of this.

If none of that helps, then it's possible that something else has read the start of your data before you get into this loop. You should compare the data in the output file with the original file. Look at the first (say) 16 bytes in the output file, and check that they're at the start of the input file. If they're not, then that suggests that the problem is with what you're doing with the connection before the code you've shown us. (For example, the code used to send and receive the expected file size.)

Now that we can see how you're sending / receiving the file size, that's definitely the problem. The scanner is reading some of the file data. To fix this, just use DataOutputStream on the sending side and DataInputStream on the receiving side:

DataOutputStream output = new DataOutputStream(clientSocket.getOutputStream());
output.writeUTF(fileName);
output.writeInt(fileSize);
// Write the data as before, to output

On the receiving side:

DataInputStream input = new DataOutputStream(clientSocket.getInputStream());
String fileName = input.readUTF(name);
int fileSize = input.readInt();
// Read the data before, as above, from input

people

See more on this question at Stackoverflow