PDF und integer senden

Status
Nicht offen für weitere Antworten.

DEG1935

Mitglied
Hallo Zusammen,

ich würde gerne von einem Client eine Datei (z.B. PDF) an einen Server senden. Soweit so gut. Dazu möchte ich der Datei aber noch eine ID (integer) mitgeben.

Ich dachte mir, dass ich Datei und ID einfach über DataOutputStream versende. Leider klappt das bisher nur bei kleineren Textdateien, Binärdateien sind nicht möglich.

Ich gehe wie folgt vor: Datei in einen FileInputStream stecken und mittels read(byte []) in ein byte[] kopieren. Dann sende ich über DataOutputStream zuerst die ID writeInt(int) und danach sende ich das byte[]. Zum Testen erstelle ich aus dem byte[] mittels BufferedOutputStream.write eine Kopie der Datei.

Ergebnis: Senden klappt prima, Datei kommt an. Ist leider nur nicht zu gebrauchen. Die Kopie der Datei, die nicht versendet wurde ist ok. Bei Textdateien ist auch die versendete Datei ok.

Hier der Code des Senders:
Code:
Socket sock = new Socket(args[0], 1055);
InputStream in = sock.getInputStream();
OutputStream out = sock.getOutputStream();

sock.setSoTimeout(30000);

int telNr=2;
int laenge=-1;

File f = new File("C:\\temp\\A\\vm.pdf");
File tempF = new File("C:/temp/B/temp.pdf");

laenge = (int)f.length();

FileInputStream fis = new FileInputStream(f);			
DataOutputStream dos = new DataOutputStream(out);

try {
    
    dos.writeInt(telNr);
    dos.writeInt(laenge);
    
    // Datei ins byte[]
    byte[] b = new byte[laenge];
    int tempi = fis.read(b);
    fis.close();
    
    // byte[] senden
    dos.write(b, 0, tempi);
    dos.flush();

    //Kopie erstellen:
    BufferedOutputStream fileout = new BufferedOutputStream(new FileOutputStream(tempF));
    fileout.write(b, 0, laenge);
    fileout.close();

} catch (IOException e) {
    e.printStackTrace();
}
in.close();
out.close();
sock.close();

Beim Empfänger sieht es so aus:
Code:
InputStream in = client.getInputStream();
DataInputStream dis = new DataInputStream(in);

int telNr = dis.readInt();
int laenge = dis.readInt();

byte[] b = new byte[laenge];
int tempi = dis.read(b, 0, laenge);

System.out.println("gelesene Bytes=" + tempi);

File f = new File("C:\\temp\\B\\heute.pdf");
FileOutputStream fileout = new FileOutputStream(f);
fileout.write(b, 0, laenge);

client.close();
fileout.close();

Ach ja, was mich auch verwirrt ist der println() des Empfängers, der mir die gesendeten bytes zeigen soll, nur 64KB zurückgibt, obwohl es laut Feld Länge über 100KB sein müssten. Wo liegt mein Denkfehler? Oder würdet ihr diese Ausgabe überhaupt so lösen? Trete gerade ein wenig auf der Stelle.
 
Ein einfaches read() liest macht das übergebene byte[] nicht immer komplett mit Daten voll. Es wird hier nur so viel gelesen wie gerade gelesen werden kann (kann also sein dass ein Rest noch "unterwegs" ist oder irgendwo in einem Puffer feststeckt). Du kannst hier aber readFully() des DataInputStreams verwenden. Dann wird exakt so viel gelesen wie das byte[] groß ist (sofern so viele Daten auch wirklich zum lesen aus dem Stream kommen.

Weitere Infos findest du in der Java-Doc zu den jeweiligen Methoden.

- Alex
 
Super, das mit dem readFully hat es gebracht! Hatte ja auch gedacht, dass da irgendwo etwas hängengeblieben ist, aber genau das sollte am Client durch das flush() verhindert werden. readFully 😳 ich sollte aufmerksamer Doku lesen.

Vielen Dank für den Hinweis!
 
Naja, readFully() ist auch nichgt das gelbe vom Ei. Schlißelich wird da ja ne ganze Zeit blockiert bis alles da ist. Manchmal ist es sinnvoller in einer while-Schleife immer und immer wieder read() aufzurufen und sich so alles "zusammen zu lesen" bis man "laenge" erreicht hat.

Das macht vor allem dann Sinn, wenn man Speicher sparen will und die Datei nicht in ein einzelnes byte[] passt. Stell dir vor du müsstest eine Datei mit 150 MB transferieren. Würdest du dann ein byte[] mit 150MB größe anlegen? Sicher nicht. Deine JVM bedankt sich erst mal mit einer OutOfMemoryException oder so.

Also lieber eine sinnvolle Puffergröße für das Array wählen und in einer Schleifen Stück für Stück alles lesen und entsprechend weiterreichen (z.B. an einen Outputstream der die Datei gleich speichert.)..

- Alex
 
Guter Einwand, habe dies gestern Abend berücksichtigt und den Empfänger ein wenig umgestellt:

Code:
int Id = dis.readInt();
int laenge = dis.readInt();
byte[] b = new byte[1024];
File f = new File("C:/temp/B/heute.pdf");
BufferedOutputStream fileout = new BufferedOutputStream(new FileOutputStream(f));
int len;
while((len=dis.read(b))!=-1){
    fileout.write(b, 0, len);
}
fileout.close();

Wobei die vorherige Methode, also das readFully sehr wahrscheinlich gereicht hätte, da eigentlich nie Dateien > 10MB gesendet werden. Aber wer weiß schon was in Zukunft ist, besser gleich vernünftig. :wink:
 
Jupp, so sieht's besser aus. Nur die "Id" könntest du noch am Anfang klein schreiben (Java-Code-Convention: Variablennamen fangen klein an).

- Alex
 
Ja ne is klar! Das war auch nur das Beispiel zum Post. Werde auch dort demnächst mehr auf die Details achten. :wink:

Nochmals vielen Dank für deine Hilfe, funktioniert nun super! 😀
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben