3

I'm writing a file transfer protocol, in which files are sent between server and client in packets of 512 bytes each. If a file is larger than that size, the file will be split into multiple packets. I'm doing the splitting ok I think, but I'm having trouble re-assembling the files. If the file is smaller than 512 byte (one packet) the assembly process works, but if the file is larger, only the last packet to arrive is being written to the file.

Here is the code of the FileAssembler:

public class FileAssambler {

List<byte[]> bytesList;
private String name;
boolean finished=false;
private FileOutputStream fileOutputStream;

public FileAssambler(String name){
    bytesList = new ArrayList<byte[]>();
    this.name = name;
}

public void addBytes(byte[] bytes){
    if(bytes.length<512)
        finished=true;
    bytesList.add(bytes);
}

public boolean isFinished(){
    return finished;
}

public void createFile() throws IOException{
    Iterator<byte[]> it = bytesList.iterator();
    while(it.hasNext())
        writeBytesToFile(it.next());
}

private void writeBytesToFile(byte[] bytes){

    try{
        fileOutputStream = new FileOutputStream(name);
        fileOutputStream.write(bytes);
    }catch(IOException e){
        e.printStackTrace();
    }
}

}

I think that the fileOutputStream.write(bytes) simply replaces the existing bytes with the new one, what is the alternative to writing into a file?

How do I combine multiple byte[] arrays into a single file?

Thanks in advance :)

Dolav
  • 45
  • 1
  • 4
  • 1
    It's not the `write`; creating `FileOutputStream` with the 1-arg String (or File) ctor **truncates any existing file**. You should create _one_ stream in `createFile` then `write` _all_ buffers to that one stream, and then `close` or at least `flush` it; in some filesystems not flushing or closing might lose data. – dave_thompson_085 Jan 14 '17 at 19:21
  • You can't rely on `< 512` as an EOF indication. A short read can happen at any time, and a file can be a multiple of 512 bytes. You don't need a superimposed packetising protocol just to transfer a file: the standard Java copy loop will do. And you neither need nor want to assemble all the bytes of a file before writing any of it. Unclear what you're asking. – user207421 Jan 14 '17 at 19:25
  • See my answer [here](http://stackoverflow.com/questions/10367698/java-multiple-file-transfer-over-socket) for the right way to do it. – user207421 Jan 15 '17 at 00:09

2 Answers2

1

Answer to "FileOutputStream simply replaces the existing bytes with the new one, what is the alternative to writing into a file?"

FileOutputStream(File file, boolean append) 

This is the syntax for FileOutputStream so you can put append as true :)

Answer to "How do I combine multiple byte[] arrays into a single file?"

You can use addAll method. Here is an example:

    List<byte[]> listFinal = new ArrayList<byte[]>();
    listFinal.addAll(listA);
    listFinal.addAll(listB);
0

You create a new FileOutputStream for every element in your bytesList. Every of those output stream start writing to the file at the start of the file. So you end up overwriting all the bytes until the last element of your bytes-list.

What you want to do is create only one FileOutputStream and use it for all the write(bytes) calls. This way every write will append to the already opened file. Something like that:

public void createFile() throws IOException{
    FileOutputStream fos = new FileOutputStream(name);
    Iterator<byte[]> it = bytesList.iterator();
    while (it.hasNext())
        fos.write(it.next());
}

Also depending on your Java version you can avoid the Iterator by using the for each loop:

public void createFile() throws IOException {
    FileOutputStream fos = new FileOutputStream(name);
    for (byte[] data: bytesList)
        for.write(data);
}
Quota
  • 573
  • 3
  • 11
  • No reason to construct the list of `byte[]` in the first place. It just wastes memory. Just write the bytes directly to the file as they are received. – user207421 Jul 31 '19 at 04:24