2012-05-20 11 views
6

Tengo que transferir a ~ 100 MB de datos a través de ServerSocket usando NIO, pero no puedo encontrar la manera de hacer esto sin romper la transferencia en cualquier lugar/mantener el estado de la transferencia.Java - La transferencia de archivos de gran tamaño a través de canales - NIO

Mi primera idea era enviar el tamaño del archivo, al parecer, no puedo enviar el tamaño de los archivos que los grandes, ya que incluso no cabe en la memoria RAM de una sola vez. Entonces pensé, ¿por qué no transferir hasta que no se recibe nada, pero eso es cuando problema viene.

Incluso si estoy escribiendo los datos del servidor del lado todo el tiempo

 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(); 
     } 

sino porque tiene que haber pausas en la transferencia de archivos, leer los datos constantemente y romper cuando no hay nada disponible era una mala idea.

No puedo entender cómo podría decirle al cliente si todavía hay datos disponibles sin tener que enviar cada porción de datos como un nuevo paquete con código de operación, etc., o ¿es posible?

También me pregunto si tener una mejor manera de enviar búfer entero que por debajo

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

he respondido a parte de esto, pero tengo que decir que no entiendo qué quiere decir con "tiene que haber interrupciones en la transferencia de archivos algún tiempo" y "leer los datos constantemente y romper cuando nada está disponible fue mala idea ". Por favor explique. – EJP

Respuesta

3

La forma correcta para copiar los canales a través de los tampones es el siguiente:

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

Este se encarga de todos los casos de esquina, incluida la duración leer = longitud de escritura y tener los datos sobrantes al final de la entrada!.

NB que es para el modo de bloqueo. Si se encuentra en el modo sin bloqueo, debe volver al ciclo select() si read() o write() devuelve cero.

+0

Desearía poder aceptar respuestas múltiples, porque no estoy seguro en absoluto a quién pertenece esta aceptación. Vizier me ofreció una solución perfecta, pero la cumpliste. Actualmente estoy usando un código casi exacto como el suyo y está funcionando perfectamente. Muchas gracias por los dos. Sin embargo, no estoy seguro de qué hace la operación compacta, pero creo que debe ser mejor que borrar. ¡Gracias de nuevo! – Ruuhkis

+1

@Ruuhkis 'compact()' elimina las cosas que se han escrito pero deja todo lo que no se ha escrito. Si utiliza 'clear()' en su lugar, se arriesga a perder datos si la longitud de lectura es = la longitud de escritura, lo que puede suceder en cualquier momento. – EJP

+0

Gracias, ese es un gran consejo. – Ruuhkis

4

Quizás esté interesado para esto:

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

Guau, ¿cómo podría haberme perdido eso? Lo intentaré mañana y espero aceptar tu respuesta si funciona bien. – Ruuhkis

+0

@Ruuhkis Tenga en cuenta que debe llamar a este método en un bucle, ya que no se garantiza que transfiera toda la longitud en una invocación. Ver también mi respuesta. – EJP

+0

Por favor, lea mi comentario al visor de respuesta de EJP. – Ruuhkis

0

Si no puede depender de la toma de permanecer abiertos, no hay forma de construir un mecanismo de recuperación y continuación en su protocolo. En cuanto a decirle al cliente cuántos bytes esperar, puede encontrar el tamaño de un archivo sin leerlo en la memoria usando File.length.

Cuestiones relacionadas