2012-04-28 14 views
20

Ok, próbując przesłać określony katalog plików przez gniazdo, usuń obiekty katalogu z listy, więc pozostały tylko pliki i przenieś je 1 na 1 przez to samo gniazdo. Lista tablic tutaj jest wypełniona TYLKO plikami, bez katalogów. Oto kod odbierania i wysyłania odpowiednio dla klienta i serwera. Kod działa poprawnie bez błędów, z wyjątkiem WSZYSTKIE dane są zapisywane do pierwszego pliku. Kolejne pliki są tworzone w folderze serwera, ale mają 0 bajtów. Wszelkie dane wejściowe będą bardzo mile widziane.Przesyłanie wielu plików Java przez gniazdo

Jest to kod serwera dla ODBIERANIE pliki

public void receive(){ 


    try { 
     DataInputStream dis = new DataInputStream(new BufferedInputStream(socket.getInputStream())); 
     DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream())); 
//read the number of files from the client 
     int number = dis.readInt(); 
     ArrayList<File>files = new ArrayList<File>(number); 
     System.out.println("Number of Files to be received: " +number); 
     //read file names, add files to arraylist 
     for(int i = 0; i< number;i++){ 
      File file = new File(dis.readUTF()); 
      files.add(file); 
     } 
     int n = 0; 
     byte[]buf = new byte[4092]; 

     //outer loop, executes one for each file 
     for(int i = 0; i < files.size();i++){ 

      System.out.println("Receiving file: " + files.get(i).getName()); 
      //create a new fileoutputstream for each new file 
      FileOutputStream fos = new FileOutputStream("C:\\users\\tom5\\desktop\\salestools\\" +files.get(i).getName()); 
      //read file 
      while((n = dis.read(buf)) != -1){ 
       fos.write(buf,0,n); 
       fos.flush(); 
      } 
      fos.close(); 
     } 

    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 

    } 


} 

Jest to kod klienta dla wysyłanie plików

public void send(ArrayList<File>files){ 

    try { 
     DataInputStream dis = new DataInputStream(new BufferedInputStream(socket.getInputStream())); 
     DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream())); 
     System.out.println(files.size()); 
//write the number of files to the server 
     dos.writeInt(files.size()); 
     dos.flush(); 

     //write file names 
     for(int i = 0 ; i < files.size();i++){ 
      dos.writeUTF(files.get(i).getName()); 
      dos.flush(); 
     } 

     //buffer for file writing, to declare inside or outside loop? 
     int n = 0; 
     byte[]buf = new byte[4092]; 
     //outer loop, executes one for each file 
     for(int i =0; i < files.size(); i++){ 

      System.out.println(files.get(i).getName()); 
      //create new fileinputstream for each file 
      FileInputStream fis = new FileInputStream(files.get(i)); 

      //write file to dos 
      while((n =fis.read(buf)) != -1){ 
       dos.write(buf,0,n); 
       dos.flush(); 

      } 
      //should i close the dataoutputstream here and make a new one each time? 
     } 
     //or is this good? 
     dos.close(); 
    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 


} 
+0

Zasadniczo staramy się powielać funkcjonalność (S) FTP. Nie zaznaczyłeś tego pytania jako zadania domowego, więc możesz wyjaśnić, dlaczego próbujesz to zrobić, zamiast korzystać z biblioteki FTP? – ControlAltDel

+1

Próbujesz nauczyć się Java, po prostu wykonujesz proste projekty, aby grać z systemem io po raz pierwszy. Mam wrażenie, że mój dos.write (buf, 0, n) i jego partner odbierający po prostu czytają i zapisują wszystkie dane zapisywane do pierwszego pliku? Czy muszę dodać kontrolkę, aby zasygnalizować, kiedy pierwszy plik został całkowicie zapisany? –

+0

zasadniczo, tak. – ControlAltDel

Odpowiedz

22

Czytasz gniazdo aż read() zwraca -1. Jest to warunek końca strumienia (EOS). EOS dzieje się, gdy peer zamyka połączenie. Nie wtedy, gdy kończy się pisanie jednego pliku.

Musisz przesłać rozmiar pliku przed każdym plikiem. Już robisz coś podobnego z liczbą plików. Następnie upewnij się, że dokładnie przeczytać wiele bajtów dla tego pliku:

String filename = dis.readUTF(); 
long fileSize = dis.readLong(); 
FileOutputStream fos = new FileOutputStream(filename); 
while (fileSize > 0 && (n = dis.read(buf, 0, (int)Math.min(buf.length, fileSize))) != -1) 
{ 
    fos.write(buf,0,n); 
    fileSize -= n; 
} 
fos.close(); 

Można ująć to wszystko w pętli, który kończy kiedy readUTF() rzuca EOFException. Odwrotnie oczywiście przed wysłaniem danych musisz zadzwonić pod numer writeUTF(filename) i writeLong(filesize).

+0

Czy 'shutdownOutput' nie może być również użyty do wskazania' EOF'? – Cratylus

+0

@ użytkownik384706 Tak. Raz na połączenie. Więc możesz wysłać tylko jeden plik. – EJP

+0

To działało idealnie, jestem zdezorientowany z części n = dis.read (buf, 0, Math.min), czy math.min określa, czy rozmiar pliku jest mniejszy niż rozmiar bufora? a jeśli tak, to tylko częściowo wypełni bufor tylko plik.length? –

1

zrobiłem to w ten sposób, że działa perfekcyjnie, można spojrzeć:

send

byte[] done = new byte[3]; 
String str = "done"; //randomly anything 
done = str.getBytes(); 
for(int i =0; i < files.size(); i++){ 
    System.out.println(files.get(i).getName()); 
    FileInputStream fis = new FileInputStream(files.get(i)); 
    while((n =fis.read(buf)) != -1){ 
     dos.write(buf,0,n); 
     System.out.println(n); 
     dos.flush(); 
    } 
//should i close the dataoutputstream here and make a new one each time?     
    dos.write(done,0,3); 
    dos.flush(); 
} 
     //or is this good? 
     dos.close(); 

recieve

for(int i = 0; i < files.size();i++){ 
    System.out.println("Receiving file: " + files.get(i).getName()); 
//create a new fileoutputstream for each new file 
fos = new FileOutputStream("C:\\users\\tom5\\desktop\\salestools\\" +files.get(i).getName()); 
//read file 
while((n = dis.read(buf)) != -1 && n!=3){ 
     fos.write(buf,0,n); 
     fos.flush(); 
     } 
      fos.close(); 
     } 
+0

dzięki twojemu problemowi nauczyłem się czegoś nowego, że to, co prosiłeś o zamknięcie 'DataOutputStream' po każdym transferze pliku, faktycznie zamyka strumień bazowy, a więc gniazdo jest jakby zamknięte. 'Zamknij() - Zamyka ten strumień wyjściowy i zwalnia wszelkie zasoby systemowe związane ze strumieniem." Javadocs. – Nikhar

+0

hmmm, wysyłam teraz rozmiar pliku i zapisuję go w tablicy int. Dodałem to do mojego serwera podczas pętli, natomiast ((n = dis.read (buf))! = -1 && bytesRead

+0

ok, próbowałem tego również, ale była strata/zysk kilku bajtów. Po prostu sprawdź ostatni przesłany plik, czy traci on kilka bajtów? – Nikhar

Powiązane problemy