outputstream.close() wymiana plików

0

Witam,
Napotkałem pewien problem, otóż jestem w trakcie pisania programu synchronizującego dwa wybrane katalogi na dowolnych komputerach. Wszystko przebiega pomyślnie, aż do próby przesłania drugiego pliku. Mianowicie, żeby socket odbierający plik zrozumiał, że to już koniec pliku do odbierania trzeba wyłączyć outputstream. Program musi być przygotowany na przyjęcie wielu plików, niestety po wyłączeniu outputstream'a nie działa mi:
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
ponieważ przy wczytywaniu linii za pomocą readLine() kompilator wyrzuca błędy.
funkcja odbierająca:

public void DownloadFile() throws IOException{
    	int bytesRead;
    	InputStream is = clientSocket.getInputStream();
        
        DataInputStream clientData = new DataInputStream(is);
        
        //String fileName = clientData.readUTF();
        adding.append("\n"+catalogOfFiles+fileToDownload);
        adding.append("sciaganie pliku");
        OutputStream output = new FileOutputStream(catalogOfFiles+"\\"+fileToDownload);
        long size = clientData.readLong();
        byte[] buffer = new byte[1024];
        while (size >= 0 && (bytesRead = clientData.read(buffer, 0, (int)Math.min(buffer.length, size))) != -1)
        {
            output.write(buffer, 0, bytesRead);
            size -= bytesRead;
        }
        is.close();
        output.close();
        clientData.close();
        out.println("end");
        
    }

wysyłająca:

public void SendFile(File file) throws IOException{
		byte[] buf = new byte[1024];
	    OutputStream os = socket.getOutputStream();
	    BufferedOutputStream bos = new BufferedOutputStream(os, 1024);
	    FileInputStream in = new FileInputStream(file);
	    int i = 0;
	    int bytecount = 1024;
	    while ((i = in.read(buf, 0, 1024)) != -1) {
	      bytecount = bytecount + 1024;
	      bos.write(buf, 0, i);
	      bos.flush();
	    }
	    os.close();
	    bos.close();
	    in.close();
	}

Odbieranie pliku następuje po uprzednim odebraniu od drugiego socketa słówka "file". Natomiast odebraniu pliku przesyłana jest informacja "end", żeby socket wysyłający wiedział, że może wysłać już kolejny plik. Niestety właśnie przy drugim pliku wyskakują błędy z wczytywaniem linii przy pomocy in.readLine(), gdzie BufferedReader jest zdefiniowany na początku i wcześniej działa bez zarzutów.

0

Wklej stack trace tego błędu.

1

Jeżeli piszesz już taki program, postaraj się zorganizować najprostszy protokół do przesyłu informacji.
Niech będzie to powiedzmy prosta klasa. Zawiera dwa pola - kod typu int oraz dane typu Object.

I zastosuj jakiś prosty schemat:

Kod Dane Funkcja
0 null Inicjalizacja protokołu
1 null Rozpoczęcie wysyłania pliku
2 byte[] Wysyłana część pliku bądź całość
3 null Koniec wysyłania pliku
4 null Koniec działania programu.

Wysyłanie czystych byte[] to szlachetna idea ale nie dąży do niczego. Otwórz sobie po prostu ObjectInput/OutputStream, pakuj dane w takie obiekty i ułatw sobie robotę.

0

dzięki Visher, Twój pomysł wydaję się zdecydowanie lepszy. Jak będę miał jakieś problemy to będę pisał.
Pozdrawiam

0

mógłbyś jednak mi bardziej to przybliżyć, ponieważ nie mogę za bardzo znaleźć jak przesyłać obiekty oraz zastanawia mnie potrzeba int kod w klasie.
Miało to tak wyglądać?:
public class Package {
//private int code;
private Object data;

public Package(File file) throws IOException{
	Path path = Paths.get(file.getPath());
	data = Files.readAllBytes(path);
}
    public Package(){
	data = null;
}

   public Object getData(){
           return data;
  }

}

Zastanawiam się, czy chodziło Ci o wysłanie 5 obiektów typu Package w tym jeden zawierający byte[], a reszta null?

1

Po pierwsze klasa Package musi być serializowalna, ale to akurat ogranicza się do dopisania implements Serializable zaraz po nazwie klasy.
Obecna konstrukcja jest jak najbardziej dobra.

A co do samego przesyłania, jak już wspominałem - ObjectOutputStream i ObjectInputStream na przykładach:
http://www.java2s.com/Tutorial/Java/0180__File/0191__ObjectOutputStream.htm
http://www.java2s.com/Tutorial/Java/0180__File/0190__ObjectInputStream.htm

Także otwierasz te strumienie na bazie OutputStream socketa i wysyłasz poprzez writeObject(obiekt_do_wysłania). Przy otrzymywaniu pakietów dostajesz obiekt typu Object, który później rzutujesz sobie na obiekt typu Package. Dodatkowym warunkiem jest 100% zgodność klas w kliencie i serwerze, lub dopisane ID serializacji jako pole w Package. O tym tu:
http://stackoverflow.com/questions/285793/what-is-a-serialversionuid-and-why-should-i-use-it

0

Sprawdziłem, wszystko działa perfekcyjnie, dzięki wielkie
Mogę teraz bez problemowo wysyłać pliki nie tracąc przy tym niczego w plikach co potrafiło występować w poprzednim programie, wrzucę fragmenty kodu dla innych, gdyby się też borykali z takimi problemami

Package:

public class Package implements Serializable{
	private Object data;
	private String filename;
	
	public Package(File file) throws IOException{
		//this.code = code;
		filename = file.getName();
		Path path = Paths.get(file.getPath());
		data = Files.readAllBytes(path);
	}
	
	public Package(){
		data = null;
	}

	public Object getData() {
		return data;
	}

	public String getFilename() {
		return filename;
	}
}

łączenie, strumień, wysyłanie obiektów:

public Client() throws IOException{
    	try {
			socket = new Socket(HOST, PORT);
			out = new ObjectOutputStream(socket.getOutputStream());
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    	
    	Package n1 = new Package();
    	Package n2 = new Package(new File("D:\\s.pdf"));
    	Package n3 = new Package();
    	Package n4 = new Package(new File("D:\\plik.txt"));
    	Package n5 = new Package();
    	Package n6 = new Package();
    	out.writeObject(n1);
    	out.writeObject(n2);
    	out.writeObject(n3);
    	out.writeObject(n4);
    	out.writeObject(n5);
    	out.writeObject(n6);
    }

inputstream:

in = new ObjectInputStream(clientSocket.getInputStream());

oraz odbieranie i zapis danych do pliku:

while(true){
					try {
						pack = (Package)in.readObject();
						if(last==pack.getData())break;
						last = pack.getData();
						if(last!=null){
							BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(pack.getFilename()));
							bos.write((byte[]) last);
							bos.flush();
							bos.close();
						}
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (ClassNotFoundException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}

1 użytkowników online, w tym zalogowanych: 0, gości: 1