2013-11-28 20 views
0

Я пытаюсь отправить большие файлы через сокет. Программа отлично работает для небольших файлов (например, html-страниц или pdf), но когда я отправляю файлы на 3/4 мб, вывод всегда поврежден (просмотр его текстовым редактором я заметил, что последние несколько строк всегда отсутствуют).Ошибка при отправке больших файлов через сокет

Вот код сервера:

BufferedInputStream in = null; 
    FileOutputStream fout = null; 
    try { 
     server = new ServerSocket(port); 

     sock = server.accept(); 
     in = new BufferedInputStream(sock.getInputStream()); 

     setPerc(0); 

     received = 0; 

     int incByte = -1; 
     fout = new FileOutputStream(path+name, true); 
     long size = length; 
     do{ 
      int buffSize; 
      if(size >= 4096){ 
       buffSize = 4096; 
      }else{ 
       buffSize = 1; 
      } 
      byte[] o = new byte[buffSize]; 
      incByte = in.read(o, 0, buffSize); 
      fout.write(o); 

      received+=buffSize; 
      setPerc(calcPerc(received, length)); 
      size -= buffSize; 
      //d("BYTE LETTI => "+incByte); 
     }while(size > 0); 
     server.close(); 
    } catch (IOException e) { 
     e("Errore nella ricezione file: "+e); 
    }finally{ 
     try { 
      fout.flush(); 
      fout.close(); 
      in.close(); 
     } catch (IOException e) { 
      e("ERRORE INCOMINGFILE"); 
     } 
    } 
    pr.release(port); 

А вот код клиента:

FileInputStream fin = null; 
    BufferedOutputStream out = null; 
    try { 
     sock = new Socket(host, port); 

     fin = new FileInputStream(file); 
     out = new BufferedOutputStream(sock.getOutputStream()); 

     long size = file.length(); 
     int read = -1; 
     do{ 
      int buffSize = 0; 
      if(size >= 4096){ 
       buffSize = 4096; 
      }else{ 
       buffSize = (int)size; 
      } 

      byte[] o = new byte[buffSize]; 
      for(int i = 0; i<o.length;i++){ 
       o[i] = (byte)0; 
      } 
      read = fin.read(o, 0, buffSize); 
      out.write(o); 
      size -= buffSize; 
      //d("BYTE LETTI DAL FILE => "+read); 
     }while(size > 0); 
    } catch (UnknownHostException e) { 
    } catch (IOException e) { 
     d("ERRORE NELL'INVIO DEL FILE: "+e); 
     e.printStackTrace(); 
    }finally{ 
     try { 
      out.flush(); 
      out.close(); 
      fin.close(); 
     } catch (IOException e) { 
      d("Errore nella chiusura dei socket invio"); 
     } 
    } 

я думаю, что это что-то связано с размером буфера, но я не могу понять что здесь не так.

+0

Никогда не полагайтесь на размер файла, предоставляемый 'File.length()', вместо этого продолжайте читать, пока не закончите. 'File.length()' следует использовать как представление о том, насколько велика она может быть. –

ответ

3

Это неверно:

 byte[] o = new byte[buffSize]; 
     incByte = in.read(o, 0, buffSize); 
     fout.write(o); 

Вы читаете доbuffSize байт, а затем писать точноbuffSize байт.

Вы делаете то же самое на другом конце.

Вы можете быть в состоянии уйти с этим при чтении из файла , но когда вы читаете из сокета то read обязан дать вам частично заполненный буфер, особенно если в конце письма не может всегда держитесь впереди конца считывания, потому что вы забиваете сеть с большой передачей.

Правильный способ сделать это:

 incByte = in.read(o, 0, buffSize); 
     fout.write(o, 0, incByte); 

1 - Было отмечено, что, когда вы читаете из локального файла, read вызов обычно даст вам все байты, вы запросили (с учетом размера файла и т. д.). Итак, если вы установите buffSize на длину файла, этот код, вероятно, будет работать при чтении из локального файла. Но делать это - плохая идея, потому что вы полагаетесь на поведение, которое не гарантируется ни Java, ни типичной операционной системой.

+0

Спасибо, это работает! – giuse

0

Возможно, у вас возникла проблема, например. Вот.

read = fin.read(o, 0, buffSize); 
out.write(o); 

Здесь чтения дает количество байт, вы на самом деле только для чтения. На следующей строке вы должны записать только столько байтов, сколько вы прочитали.

Другими словами, вы не можете ожидать размер файла , который вы читаете, чтобы быть кратным вашему размеру буфера.

Просмотрите также код сервера для той же проблемы.

0

Правильный способ скопировать потоки в Java заключается в следующем:

while ((count = in.read(buffer)) > 0) 
{ 
    out.write(buffer, 0, count); 
} 

count, где это int, и buffer является byte[] массив длины> 0, как правило, 8k.Вам не нужно выделять байтовые массивы внутри цикла, и вам не нужен массив байтов определенного размера. В частности, это полная трата пространства, чтобы выделить буфер размером с файл; он работает только с файлами Integer.MAX_VALUE байт, и он не масштабируется.

Вам нужно сохранить счет, возвращаемый 'read()', и использовать его в методе write(), как показано выше.

Смежные вопросы