invia file di grandi dimensioni su socket java


Sto cercando di trasferire file più grandi su socket.Trasferirò il file in chunks.As mostrato nel codice. collegamento

int count;
byte[] buffer = new byte[8192];
while ((count = in.read(buffer)) > 0)
{
  out.write(buffer, 0, count);
}

Prima di inviare questo file,voglio inviare un oggetto che contiene i dettagli del file.Usando quale flusso dovrei inviare Oggetto + File.

Sono nuovo ai flussi,posso ottenere qualsiasi codice di esempio.

Posso inviare prima la lunghezza del byte dell'oggetto per leggere l'oggetto, salvarlo e inviare il file data.is possibile, qualsiasi codice di esempio ?

Grazie 421

Author: Community, 2014-09-07

3 answers

Non sono sicuro che l'utilizzo del meccanismo di serializzazione di Java sia il modo migliore per eseguire un semplice trasferimento di file. Come suggerisce la tua domanda, cerchi di evitare di mantenere l'intero file in memoria in qualsiasi momento. Questo può essere fatto con gli oggetti usando il modello Proxy ma se tutto ciò che vuoi fare è trasferire il file, questa potrebbe non essere la soluzione più semplice. (Inoltre, legherà efficacemente il tuo peer per essere implementato anche in Java.)

Invece, perché non dare un'occhiata a un estremamente protocollo di successo che fa esattamente quello che ti serve: HTTP.

Content-Type: application/octet-stream
Content-Length: 542183

542183 bytes of data follow...

Non dovrebbe essere troppo difficile per te scrivere un parser per l'intestazione dei meta-dati.

 0
Author: 5gon12eder, 2014-09-07 12:26:46

È necessario garantire l'ordine di scrittura/lettura. Se write an object -> write raw bytes sul client, quindi read an object -> read raw bytes sul server. Durante la lettura, ObjectInputStream dovrebbe essere in grado di trovare il limite dei dati dell'oggetto serializzato.

Se si desidera mantenere una connessione socket a lungo in diretta e utilizzare i suoi flussi più volte, il wrapping del socket Output/InputStream in un ObjectOutput/InputStream non è una buona idea IMO. Quando si chiude un flusso di oggetti, si chiude anche il flusso sottostante.

Quindi potresti voler scrivere prima la lunghezza dei dati dell'oggetto serializzato (la lunghezza del file è contenuta nell'oggetto, quindi non è necessario scriverlo esplicitamente), ad esempio 4 byte di BigEndian codificati int. Quindi serializzare l'oggetto in un ByteArrayOutputStream e scrivere i byte nel suo buffer. Sul server, leggere prima 4 byte, decodificare i byte in un int e leggere molti byte in un byte[], avvolgere l'array di byte con un ByteArrayInputStream e deserializzare l'oggetto da esso.

Scrivi così:

......
OutputStream out = socket.getOutputStream();

ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);  

oos.writeObject(fileInfoObject);
oos.close();

byte[] header = encodeInteger(baos.size());

out.write(header, 0, 4);
baos.writeTo(out);

// write the file to out just as your question shows

Sul lato ricevente: ...... InputStream in = presa.getInputStream ();

// read the int
byte[] header = new byte[4];

in.read(header, 0, 4);

int size = decodeInteger(header);

// read the object
byte[] objectbuf = new byte[size];

int count;

while((count += in.read(objectbuf)) < size); // not sure if this works...

ObjectInputStram ois = new ObjectInputStream(new ByteArrayInputStream(objectbuf));

Object fileInfoObject = ois.readObject();
ois.close();

// read the file
FileOutputStream fos = new FileOutputStream(new File("somefile"));

byte[] buffer = new byte[8192];
count = 0;
long left = castedFileInfoObject.fileSize;

// also not sure if this works, not tested.
int maxRead = buffer.length;

while (true) {
    count = in.read(buffer, 0, maxRead);

    left -= count;

    if (left < 8192) {
        maxRead = (int)left;
    }

    fos.write(buffer, 0, count);

    if (left == 0) {
        break;
    }
}

Non ho testato il codice di esempio nella mia risposta.. solo per mostrare l'idea.

 0
Author: coolcfan, 2014-09-07 13:11:59

Classe MyClass dovrebbe implementare l'interfaccia serializzabile. Quindi, un oggetto di questa classe può essere scritto in un ObjectOutputStream e riletto da ObjectInputStream utilizzando i metodi writeObject e readObject (Vedere sotto).

Sul cliente:

Socket socket = new Socket(url, port);  
OutputStream os = socket.getOutputStream();  
ObjectOutputStream oos = new ObjectOutputStream(os);  
MyClass obj = new Myclass();  
oos.writeObject(obj);  
int count;
byte[] buffer = new byte[8192];
while ((count = in.read(buffer)) > 0) {
  out.write(buffer, 0, count);
}

Sul server:

ServerSocket sSocket = new ServerSocket(port);
Socket socket = sSocket.accept();  
InputStream is = socket.getInputStream();  
ObjectInputStream ois = new ObjectInputStream(is);  
MyClass obj = (MyClass)ois.readObject();
byte arr[];
try {
  while(arr = (byte[])ois.readObject()) {
    //do something with arr
  }
} catch(java.io.EOFException) {
  // End of data
}

Se hai bisogno di inviare più dati dopo che il file è finito, hai bisogno di un modo per capire il numero di byte in cui è composto il file. Quindi, è possibile inviare il numero di byte in anticipo sul socket al server. Sul server, leggere solo che molti byte di informazioni per il file e poi fare lo stesso per il resto dei dati che si sta per inviare. Questa strategia di pre-invio della dimensione del file è consigliata e viene utilizzata principalmente durante il trasferimento dei dati. Se puoi farlo, non devi fare affidamento sulla cattura di java.io.EOFException per rilevare la fine dei dati.

 -1
Author: Ashu Pachauri, 2014-09-07 12:19:45