Search code examples
javasocketsfileinputstreamfileoutputstream

File is not received unless i call os.close()


I am sending file from server to client using java socket programming. Here is my server side code:

public void fileSendingProtocol(String filePath) {

    File myFile = new File(filePath);
    byte[] mybytearray = new byte[(int) myFile.length()];

    FileInputStream fis = null;

    try {
        fis = new FileInputStream(myFile);
    } catch (FileNotFoundException ex) {
        System.err.println(ex);
    }
    BufferedInputStream bis = new BufferedInputStream(fis);

    try {

        bis.read(mybytearray, 0, mybytearray.length);
        os.write(mybytearray, 0, mybytearray.length);
        os.flush();
        System.out.println(filePath + " Submitted");
        // File sent, exit the main method
    } catch (IOException ex) {
        // Do exception handling
        System.out.println(ex.toString());
    } finally {
        try {
            os.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

Here i have closed the os in the finally block. Because if i omit os.close() then i am not able to receive the file in the client side. Here is my client file receiving code:

 public static void fileReceivingProtocol(String filePath) {

    try {
        fos = new FileOutputStream(filePath);
    } catch (FileNotFoundException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }
    bos = new BufferedOutputStream(fos);
    /* read question paper from the server. */
    try {       

        bytesRead = is.read(aByte, 0, aByte.length);

        do {
            baos.write(aByte);
            bytesRead = is.read(aByte);         
        } while (bytesRead != -1);
        bos.write(baos.toByteArray());
        bos.flush();
        fos.close();            

    } catch (IOException e) {
        System.err.println("IOException:  " + e);
    }

}

I need the server first send a file . Then after receiving that file the client need to send another file to server after some minutes. But if i call the os.close() in the server side then my socket get closed and i am not able to continue any further communication between then.


Solution

  • You do not need to close os (the OutputStream), just call its flush() method. Streams are often buffered for performance reasons. A call to flush() will instruct the implementation to send all cached data.

    Most likely the file you send is small (maybe a few KB at the most) which is less than the typical cache size. If you write less data than the cache size (or the data that can be transmitted in a TCP packet in case of a Socket's OutputStream), the implementation will likely not send it for some time. flush() will send whatever data there is cached.

    If your client does not know the file size (does not know how many bytes to wait for), you have to implement some kind of "protocol" to exchange these information. A very basic would be to first send the file size (number of bytes) in 4 bytes (that is the size of a Java int), and then send the content of the file. The client will know that the first 4 bytes will be the file size, and it will wait for / read that amount of bytes.

    How to convert int to bytes: Convert integer into byte array (Java) or Java integer to byte array

    Modified file sender

    // First write the file's length (4 bytes)
    int length = (int) myFile.length();
    os.write((length >>> 24) & 0xff);
    os.write((length >>> 16) & 0xff);
    os.write((length >>>  8) & 0xff);
    os.write(length & 0xff);
    
    // And now send the content of the file just as you did
    

    Modified file receiver

    // First read the file's length (4 bytes)
    int b1 = is.read();
    int b2 = is.read();
    int b3 = is.read();
    int b4 = is.read();
    if (b1 < 0 || b2 < 0 || b3 < 0 || b4 < 0)
        throw new EOFException(); // Less than 4 bytes received, end of stream
    int length = (b1 << 24) + (b2 << 16) + (b3 << 8) + b4;
    
    // And now read the content of the file which must be exactly length bytes