2012-05-20 9 views
6

Devo trasferire ~ 100 MB di dati su ServerSocket utilizzando NIO, ma non riesco a capire come farlo senza interruzione del trasferimento in qualsiasi luogo/mantenendo lo stato del trasferimento.Java - Trasferimento di file di grandi dimensioni su canali - NIO

La mia prima idea era quella di inviare la dimensione del file, apparentemente non posso inviare la dimensione di quei file di grandi dimensioni perché non si adatta nemmeno alla RAM in una volta. Poi ho pensato, perché non basta trasferire fino nulla viene ricevuto, ma questo è quando il problema si presenta in.

Anche se sto scrivendo i dati del server-retro per tutto il tempo

 FileChannel fc = new FileInputStream(f).getChannel(); 
     ByteBuffer buffer = ByteBuffer.allocate(1024); 
     while(fc.read(buffer) > 0) { 
      buffer.flip(); 
      while(channel.write(buffer) > 0); 
      buffer.clear(); 
     } 

ma perché ci devono essere interruzioni nel trasferimento di file un po 'di tempo leggendo i dati costantemente e rompendo quando nulla è disponibile era una cattiva idea.

Non riesco a capire come potrei dire al cliente se ci sono ancora dati disponibili senza dover inviare ogni porzione di dati come nuovo pacchetto con codice operativo ecc. O è addirittura possibile?

Inoltre sto chiedendo se modo theres meglio mandare intero buffer che sotto

while(channel.write(buffer) > 0); 
+0

Ho risposto a una parte di questo, ma devo dire che non capisco cosa intendi con "ci devono essere pause nel trasferimento dei file un po 'di tempo" e "leggere i dati costantemente e interrompere quando nulla è disponibile era una cattiva idea ". Spiega per favore. – EJP

risposta

3

Il modo corretto per copiare canali via buffer è la seguente:

while (in.read(buffer) >= 0 || buffer.position() > 0) 
{ 
    buffer.flip(); 
    out.write(buffer); 
    buffer.compact(); 
} 

Questo si prende cura di tutti i casi angolo compreso lunghezza lettura = lunghezza scrittura ed avente i dati rimasti alla fine dell'input!.

NB: questa è la modalità di blocco. Se si è in modalità non bloccante, è necessario tornare al ciclo select() se read() o write() restituisce zero.

+0

Vorrei poter accettare più risposte, perché non sono affatto sicuro di chi appartenga a questa accettazione. Il visir mi ha offerto una soluzione perfetta ma tu l'hai realizzata. Attualmente sto usando un codice quasi esatto come il tuo e funziona perfettamente. Grazie mille per entrambi. Eppure non sono sicuro di cosa faccia l'operazione compatta, ma suppongo che debba essere meglio della pulizia. Grazie ancora! – Ruuhkis

+1

@Ruuhkis 'compact()' rimuove il materiale che è stato scritto ma lascia tutto ciò che non è stato scritto. Se usi 'clear()' invece stai rischiando la perdita di dati se la lunghezza di lettura! = La lunghezza di scrittura, che può accadere in qualsiasi momento. – EJP

+0

Grazie, questo è un ottimo consiglio. – Ruuhkis

4

Forse siete alla ricerca di questo:

channel.transferFrom(0, fc.size(), fc); 
+0

Wow, come potrei averlo perso? Ci proverò domani e spero che accetti la tua risposta se funziona bene. – Ruuhkis

+0

@Ruuhkis Si noti che è necessario chiamare questo metodo in un ciclo, poiché non è garantito il trasferimento dell'intera lunghezza in un richiamo. Vedi anche la mia risposta. – EJP

+0

Per favore leggi il mio commento al visir di risposta dell'EJP. – Ruuhkis

0

Se non si può dipendere la presa a rimanere aperti, non c'è modo di costruire un meccanismo di recupero e mantenimento nel protocollo. Come per dire al cliente quanti byte aspettarsi, è possibile trovare la dimensione di un file senza leggerlo in memoria usando File.length.