开发者

How to write file data correctly?

My application is unable to transfer data properly over a socket connection and write it to a file properly. Files over about 65,535 bytes get corrupted and are no longer recognized by the programs designed to run them.

I have been able to send small .doc and .txt files successfully, but .mp3 .wmv .m4a .avi and just about anything else does not work. Neither do larger docs.

I have looked all over the internet for a solution to this problem. I have repeatedly tweaked the I/O code to fix the problem but it still doesn't work! Here is the I/O code in the super class that handles sending and receiving files. If you need anymore information/other parts of code, let me know.

protected void sendFile() throws IOException {
    byte[] bytes = new byte[(int) file.length()];
    buffin = new BufferedInputStream(new FileInputStream(file));
    int bytesRead = buffin.read(bytes,0,bytes.length);
    System.out.println(bytesRead);
    out = sock.getOutputStream();
    out.write(bytes,0,fileBytes);
    out.flush();
    out.close();
}

protected void receiveFile() throws IOException {
    byte[] bytes = new byte[fileBytes];
    in = sock.getInputStream();
    for(int i=0;i<fileBytes;i++) {
        in.read(bytes);
    }
    fos = new FileOutputStream("/Datawire/"+fileName);
    buffout = new BufferedOutputStream(fos);
    buffout.write(bytes,0,fileBytes);
    buffout.flush();
    buffout.close();
}

UPDATED CODE (that works):

    protected void sendFile() throws IOException {
    if((file.length())<63000) {
        byte[] bytes = new byte[(int)file.length()];
        buffin = new BufferedInputStream(new FileInputStream(file));
        buffin.read(bytes,0,bytes.length);
        out = sock.getOutputStream();
        out.write(bytes,0,bytes.length);
        out.close();
    } else {
        byte[] bytes = new byte[32000];
        buffin = new BufferedInputStream(new FileInputStream(file));
        out = sock.getOutputStream();
        int bytesRead;
        while((bytesRead = buffin.read(bytes))>0) {
            out.write(bytes,0,bytesRead);
        }
        out.close();
    }
}

protected void receiveFile() throws IOException {
    if(fileBytes<63000) {
        byte[] bytes = new byte[32000];
        in = sock.getInputStream();
        System.out.println(in.available());
        in.read(bytes,0,fileBytes);
        fos = new FileOutputStream("/Datawire/"+fileName);
        buffout = new BufferedOutputStream(fos);
        buffout.write(bytes,0,bytes.length);
        buffout.close();
    } else {
        byte[] bytes = new开发者_Python百科 byte[16000];
        in = sock.getInputStream();
        fos = new FileOutputStream("/Datawire/"+fileName);
        buffout = new BufferedOutputStream(fos);
        int bytesRead;
        while((bytesRead = in.read(bytes))>0) {
            buffout.write(bytes,0,bytesRead);
        }
        buffout.close();
    }
}


The issue is that you are sending only chunks of it. That is, you are only sending 64k of the file ever. If the file is ever larger then 64k the other end will never see it.

You want to continously read from the BufferedInputStream until the read() returns either less then the length or -1.


Your code is completely wrong. This is how to copy a stream in Java:

int count;
byte[] buffer = new byte[8192]; // more if you like but no need for it to be the entire file size
while ((count = in.read(buffer)) > 0)
{
  out.write(buffer, 0, count);
}

You should use this both when sending the file and when receiving the file. At present your sending method hopes that the entire file fits into memory; fits into INTEGER_MAX bytes; and is read in one chunk by the read method, without even checking the result. You can't assume any of those things. Your receive method is complete rubbish: it just keeps overwriting the same array, again without checking any read() results.

EDIT: Your revised code is just as bad, or worse. You are calling read() to check for EOS and then throwing that byte away, and then calling read() again and throwing away the read count it returns. You pointlessly have a different path for files < 64000, or 63000, or whatever it is, that has zero benefit except to give you two code paths to test, or possibly four, instead of one. The network only gives you 1460 bytes at a time at best anyway so what is the point? You already have (a) a BufferedInputStream with a default buffersize of 8192, and (b) my code that uses a byte[] buffer of any size you like. My code above works for any amount of data in two lines of executable code. Yours is 20. QED.


I suggest that you use some good library to read and write file contents as well as socket read/write. For example Apache Commons IO. If you insist on writig code yourself, do it smaller chunks rather than the whole file at once.


You have to consider that InputStream.read returns the number of bytes read which may be less than the total number of bytes in the file.

You would probably be better off just letting something like CopyUtils.copy take care of this for you.


You need to loop until bytesRead < 0. You need to make sure that fileBytes is => than the transferred file.

protected void receiveFile() throws IOException {
    byte [] bytes  = new byte [fileBytes];
    InputStream is = sock.getInputStream();
    FileOutputStream fos = new FileOutputStream("/Datawire/"+fileName);
    BufferedOutputStream bos = new BufferedOutputStream(fos);

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

    do {
       bytesRead =
          is.read(bytes, current, (bytes.length-current));
       if(bytesRead >= 0) current += bytesRead;
    } while(bytesRead > -1);

    bos.write(bytes, 0 , current);
    bos.flush();
    bos.close();

}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜