Ifta
Ifta

Reputation: 1595

How to detect end of a file while receiving it through InputStream

I am trying to send multiple files through socket. The sender and receiver function i wrote is given below. Sender

public void sendFileX() throws IOException {
    DataOutputStream dos = new DataOutputStream(
            connection.getOutputStream());
    //send file number
    dos.writeInt(filesToSend.length);
    dos.flush();
    //send file names
    for (int i = 0; i < filesToSend.length; i++) {
        dos.writeUTF(filesToSend[i].getName());
    }
    dos.flush();
    //send file sizes
    for (int i = 0; i < filesToSend.length; i++) {
        File myFile = new File("" + filesToSend[i] + "");
        dos.writeLong(myFile.length());
    }
    dos.flush();
    // send the file
    os = connection.getOutputStream();
    for (int i = 0; i < filesToSend.length; i++) {
        File myFile = new File("" + filesToSend[i] + "");
        byte[] mybytearray = new byte[(int) myFile.length()];

        fis = new FileInputStream(myFile);
        bis = new BufferedInputStream(fis);
        bis.read(mybytearray, 0, mybytearray.length);

        os.write(mybytearray, 0, mybytearray.length);
    }
    os.flush();
    os.close();
    bis.close();
}

And the receiver is: Receiver

private void recieveFileY() throws IOException
{
    DataInputStream dis = new DataInputStream(connection.getInputStream());
    //receive file number
    int len = dis.readInt();

    //receive file names
    fileNames = new String[len];
    for(int i = 0; i < len; i++)
    {
        fileNames[i] = dis.readUTF();
    }
    //receive file sizes
    fileSizes = new long[len];
    for(int i = 0; i < len; i++)
    {
        fileSizes[i] = dis.readLong();
    }

    for(int i = 0; i <len; i++)
    {
        System.out.println(fileNames[i]+", size: "+fileSizes[i]);
    }
    //receive files
    is = connection.getInputStream();
    BufferedReader br = new BufferedReader(new InputStreamReader(is));
    for(int i = 0; i < len; i++)
    {
        String fileSaveLocation = "c:/"+fileNames[i];
        fos = new FileOutputStream(fileSaveLocation);
        bos = new BufferedOutputStream(fos);
        byte[] bytesToRead = new byte[(int) fileSizes[i]];
        is.read(bytesToRead, 0, bytesToRead.length);
        bos.write(bytesToRead);

}

For this receiver I am getting all files but some file have data missing as is.read() may not read full data. But if I use this receiver , I supposed to get the whole file. Receiver2

private void recieveFileX() throws IOException
{
    DataInputStream dis = new DataInputStream(connection.getInputStream());
    //receive file number
    int len = dis.readInt();

    //receive file names
    fileNames = new String[len];
    for(int i = 0; i < len; i++)
    {
        fileNames[i] = dis.readUTF();
    }
    //receive file sizes
    fileSizes = new long[len];
    for(int i = 0; i < len; i++)
    {
        fileSizes[i] = dis.readLong();
    }

    for(int i = 0; i <len; i++)
    {
        System.out.println(fileNames[i]+", size: "+fileSizes[i]);
    }
    //receive files
    is = connection.getInputStream();
    BufferedReader br = new BufferedReader(new InputStreamReader(is));
    for(int i = 0; i < len; i++)
    {
        String fileSaveLocation = "c:/"+fileNames[i];
        fos = new FileOutputStream(fileSaveLocation);
        bos = new BufferedOutputStream(fos);
        byte[] bytesToRead = new byte[(int) fileSizes[i]];

        bytesRead = is.read(bytesToRead, 0, bytesToRead.length);
        current = bytesRead;

        do {
            bytesRead = is.read(bytesToRead, current,
                    (bytesToRead.length - current));
            if (bytesRead >= 0)
                current += bytesRead;
            System.out.println("I am in do while loop");
        } while (bytesRead > -1);

        bos.write(bytesToRead);
        System.out.println("Saved " + fileNames[i]);
    }
    bos.flush();
    bos.close();
    is.close();
}

But the problem here is after finishing reading one file more data is available in inputStream so is.read() does not return -1 to bytesRead and I got stuck in infinity loop. Please anyone help me. Thanks in advance.

FINALLY MY CODE WORKED

private void recieveFileX() throws IOException
{
    DataInputStream dis = new DataInputStream(connection.getInputStream());
    //receive file number
    int len = dis.readInt();

    //receive file names
    fileNames = new String[len];
    for(int i = 0; i < len; i++)
    {
        fileNames[i] = dis.readUTF();
    }
    //receive file sizes
    fileSizes = new long[len];
    for(int i = 0; i < len; i++)
    {
        fileSizes[i] = dis.readLong();
    }

    for(int i = 0; i <len; i++)
    {
        System.out.println(fileNames[i]+", size: "+fileSizes[i]);
    }
    //receive files
    is = connection.getInputStream();
    BufferedReader br = new BufferedReader(new InputStreamReader(is));
    for(int i = 0; i < len; i++)
    {
        String fileSaveLocation = "c:/"+fileNames[i];
        fos = new FileOutputStream(fileSaveLocation);
        bos = new BufferedOutputStream(fos);
        byte[] bytesToRead = new byte[(int) fileSizes[i]];
        /*is.read(bytesToRead, 0, bytesToRead.length);
        bos.write(bytesToRead);
        bos.flush();
        int count;
        while ((count = is.read(bytesToRead)) > 0)
        {
            bos.write(bytesToRead, 0, count);
        }
        bytesRead = is.read(bytesToRead, 0, bytesToRead.length);
        current = bytesRead;

        do {
            bytesRead = is.read(bytesToRead, current,
                    (bytesToRead.length - current));
            if (bytesRead >= 0)
                current += bytesRead;
            System.out.println("I am in do while loop");
        } while (bytesRead > -1);*/
        while(true)
        {
            bytesRead = is.read(bytesToRead,current,(bytesToRead.length - current));
            System.out.println("BytesRead = " + bytesRead);
            if(bytesRead <=0)
            {
                System.out.println("loop breker 1 worked");
                break;
            }
            current += bytesRead;
            if(current == fileSizes[i])
            {
                System.out.println("loop breker 2 worked");
                break;
            }
            System.out.println("Current = " + current);
        }
        bos.write(bytesToRead);
        System.out.println("Saved " + fileNames[i]);
        current = 0;
    }
    bos.flush();
    bos.close();
    is.close();
}

Thanks Everybody for helping me.

Upvotes: 0

Views: 3176

Answers (1)

user207421
user207421

Reputation: 310884

You're using two different kinds of copy loop. In this one:

is.read(bytesToRead, 0, bytesToRead.length);

you're completely ignoring the return value. It could be -1 indicating end of file, or it could be a read count. So you're also assuming that read() fills the buffer. It isn't specified to do that. You don't need two different loops to do the same thing. Use the same code at both ends:

while ((count = in.read(buffer)) > 0)
{
    out.write(buffer, 0, count);
}

This works with any buffer size greater than zero. I usually use 8192 but you can use more if you wish.

If you want to keep the socket open for more sends, you need to:

  • send the length of the file ahead of the file, with DataOutputStream.writeLong()
  • read it at the receiver, with DataInputStream.readLong()
  • modify the copy loop to read exactly that many bytes:

    long runningTotal = 0;
    while (runningTotal < total && (count = in.read(buffer, 0, (int)Math.min(buffer.length, total-runningTotal)) > 0)
    {
        out.write(buffer, 0, count);
        runningTotal += count;
    }
    

E&OE

Upvotes: 1

Related Questions