PDF-Datei in Datenbank uploaden in ein BYTEA

Hallo, ich hätte eine Frage bei einem Problem. Ich versuche zur Zeit eine Datei in meine Datenbank hochzuladen. Es sollen keine größeren Files als 1MB sein.

Die Datenbanktabelle zu Testzwecken sieht zur Zeit so aus:

CREATE TABLE uploadtest(
fileid SERIAL PRIMARY KEY,
filename VARCHAR(50),
file BYTEA,
filesize INT
);

Der dazugehörige Java-Code sieht folgendermaßen aus:

File f=new File(pfad);            
FileInputStream fis = new FileInputStream(f);
System.out.println("name: " + file.getName());
System.out.println("fis: " + fis);
System.out.println("länge: " + (int)file.length());
PreparedStatement pstmt = con.prepareStatement("INSERT INTO uploadtest(filename,file,filesize) VALUES (?,?,?)");
			 
pstmt.setString(1,file.getName());
pstmt.setBinaryStream(2, fis, (int)file.length());
pstmt.setInt(3,(int)file.length());
pstmt.executeUpdate();
pstmt.close();
fis.close();

Bei der Konsolenausgabe kommt folgendes raus:

name: test.pdf
fis: java.io.FileInputStream@5dbacdad
länge: 121335

Die Ausgabe bei PostgreSQL sieht folgendermaßen aus:

1 | test.pdf | | 121335

Ich bekomme also für das Feld vom Datentyp BYTEA keine Ausgabe. Frage mich nun wieso im Feld nichts drin steht. Den Rest zeigt er mir genau so an, wie ich es erwartet habe. Habe ich da noch etwas vergessen?

Was meinst Du mit “die Ausgabe bei PostgreSQL”? Welchen SQL client verwendest Du? Dieser muss schon in der Lage sein auch bytea spalten irgendwie anzuzeigen.

Ich benutze pgAdmin

Überprüf doch mal mit

select fileid, length(file) from uploadtest;

ob in der Spalte was drin steht.

Wenn ja (length > 0), dann liegt’s einfach an Deinem SQL client.

Ausgabe:

1 | 121335

Also scheint wohl doch etwas drin zu stehen? :slight_smile: Na dann werde ich nun mal versuchen die Datei auszugeben über mein Java Programm. Wäre ja schön, wenn es doch so geklappt hat und es bei pgAdmin nur nicht angezeigt wird.
Ich danke dir erstmal!

entspricht die Länge denn der original PDF ?

Unwahrscheinlich…

test=# select '123'::bytea;
  bytea
----------
 \x313233
(1 row)

Andreas

Ich würde sagen, es ist exact die Länge.

length(file) hat genau die gleiche Zahl angezeigt wie in der Spalte filesize gespeichert wurde.

Genau, es ist die exakte Länge. Ausprobiert habe ich es aber noch nicht, ob es wirklich geklappt hat.

Hallo,
ich sitze zur Zeit noch immer daran wie ich die PDF aus der Datenbank hole und verzweifel ein wenig. Habe es nun erstmal wieder so gemacht. Mit folgendem habe ich zumindestens erstmal herausgefunden, das wirklich etwas drin steht:

public LinkedList<Test> testSelect(){
	LinkedList<Test> resultList = new LinkedList<Test>();
	try {		
		Statement stmt = con.createStatement();
		rs = stmt.executeQuery("SELECT * FROM uploadtest");
		
		while(rs.next()){
			resultList.add(new Test(rs.getString(1), rs.getString(2),rs.getByte(3),rs.getString(4)));
		}
		
		rs.close();
		stmt.close();
		con.close();
	} catch (SQLException e) {
		System.out.println("MgrSQL.aufgabenElektrotechnikAnzeige\n"+e);
	}	
	return resultList;
}

Dabei kam nämlich folgendes heraus:

Unzulässiger Wert für den Typ byte : \x255044462d312e350d0a25b5b5b5b50d0a312030206f626a0d0a3c3c2f547970652f436(…)

Dies ist ja aber auch erstmal nicht so wichtig. Das habe ich zwischendurch nur getestet. Habe es dann mal folgendermaßen ausprobiert:

public LinkedList<UploadWerte> testNEUnummer2() throws IOException{
	LinkedList<UploadWerte> resultList = new LinkedList<UploadWerte>();
	FileOutputStream fos = null;
	
	try {        	
		Statement stmt = con.createStatement();			
		rs = stmt.executeQuery("SELECT * FROM uploadtest");
		
		while(rs.next()){
			File f = new File("filename");
			InputStream is = rs.getBinaryStream(2);
			fos = new FileOutputStream(f);
			int length = rs.getInt(4);
			byte[] buf = new byte[length];
//			while(0 < length){
//				fos.write(buf,0,length);
//			}
			resultList.add(new UploadWerte(rs.getString(1),buf,rs.getString(3),rs.getString(4)));
		}
		
		rs.close();
		stmt.close();
		con.close();
	} catch (SQLException e) {
		System.out.println("MgrSQL.testNEU\n"+e);
	}
	return resultList;		
}

Bei filename weiß ich jedoch nicht genau was ich da reinpacken soll. Gehört da der Ort hin wo die Datei abegelegt bzw. zwischengespeichert werden soll? Fehlermeldung bekomme ich da erstmal keine, bekomme aber folgende Ausgabe:

1 [B@6beb2c5a
2 [B@1cad0010

Dies ist sichtbar, aber wenn ich die Zeile kopiere, steht dort scheinbar das ganze Byte. Würde es in einem Servlet aber gerne ausgeben und hänge grade ein wenig. Kann mir jemand einen Tipp geben wie ich da ran muss? Ist etwas frustrierend grade.

hm … das '\x…" steht doch für einen HEX String …
ich habe, als Newbie, ähnliches mit Bitmap und “ByteA” versucht … und bin dann beim HEX String ( '\x…’ ) gelandet.

ich lade das Bitmap von der Festplatte, mache daraus einen HEX String und “speichere” das dann ab.
wenn ich es “lesen” will muss ich den HEX String wieder zurück wandeln und kann dann das Bitmap anzeigen.

p.s. HEX String : alles was nach dem '\x kommt.

Ich habe es nun folgendermaßen hinbekommen:

public LinkedList<UploadWerte> testNEUnummer2() throws IOException{
	LinkedList<UploadWerte> resultList = new LinkedList<UploadWerte>();
	
	try {        	
		Statement stmt = con.createStatement();			
		rs = stmt.executeQuery("SELECT filename,file,fileid,length(file) FROM uploadtest");
		
		while(rs.next()){
			File file = new File("[[Ordner wo die Datei abgelegt werden soll]]");
			file = File.createTempFile("Aufgabe"+rs.getInt(3)+"-", ".pdf", file);

			InputStream is = rs.getBinaryStream(2);
			FileOutputStream fos = new FileOutputStream(f);
			
			int laenge=rs.getInt(4);
			byte[] buf = new byte[laenge];
		   	for(int i = 0; i < laenge; i++){
		   	   	buf[i] = (byte) is.read();
		   	}
		   	fos.write(buf, 0, laenge);
		   	
			is.close();
			fos.flush();
			fos.close();			

			resultList.add(new UploadWerte(rs.getString(1), file, rs.getInt(4)));
		}
		
		rs.close();
		stmt.close();
		con.close();
		
	} catch (SQLException e) {
		System.out.println("MgrSQL.testNEUnummer2\n"+e);
	}
	return resultList;		
}

Nun habe ich aber folgendes Problem. Ich würde gerne 2 BYTEA Dateien zusammenfassen. Dies habe ich folgendermaßen ausprobiert:

				InputStream is = rs.getBinaryStream(1);
				InputStream is2 = rs.getBinaryStream(3);
				
				FileOutputStream fos = new FileOutputStream(f);
				
				int laenge=rs.getInt(2);
				int laenge2=rs.getInt(4);
				
				byte[] buf = new byte[laenge+laenge2];
			   	for(int i = 0; i < (laenge+laenge2); i++){
			   	   	buf[i] = (byte) (is.read()+is2.read());
			   	}
			   	fos.write(buf,0,(laenge+laenge2));

Dei Größe der PDF stimmt. Habe die BYTE Zahlen von beiden Files die ich verknüpfen wollte addiert und mein “Endfile” hat genau die Größe, aber trotzdem wird mir ein “Fehler beim Laden des PDF-Dokuments” angezeigt. Kann mir einer sagen wo mein Denkfehler liegt?

Was ist denn der Stacktrace für den Fehler?

Was meinst du genau mit Stacktrace?

Wenn ich die PDF selber öffne, kommt die genannte Fehlermeldung. In der Konsole bei Eclipse selber bekomme ich keine Fehlermeldung.

Ich bin wohl mit dem falschen Gedanken an die Sache gegangen. Nach dem Auslesen der Datenbank kann man die PDFs nicht direkt verbinden, sondern muss diese erst zu PDFs umwandeln und kann diese dann mittels iText und PDFBOX verbinden. Hier nochmal der Quellcode, wie ich es gelöst habe.

public class main {
	public static void main(String[] args) throws IOException, COSVisitorException, DocumentException {
        OutputStream file = new FileOutputStream(new File("C:\\Temp\\Test23.pdf"));
        
        Document document = new Document();
        PdfWriter.getInstance(document, file);
        document.open();
        document.add(new Paragraph("Klappt das so?"));
        document.add(new Paragraph(new Date().toString()));

        document.close();
        file.close();        
        
        LinkedList<File> fileList = new LinkedList<File>();
        fileList.add(new File("C:\\Users\\xxxx\\workspace\\[[Projektname]]\\WebContent\\data\\header22.pdf"));
        fileList.add(new File("C:\\Temp\\Test23.pdf"));
        fileList.add(new File("C:\\Users\\xxxx\\workspace\\[[Projektname]]\\WebContent\\data\\header34.pdf"));

        mergePDF(fileList, "C:\\Users\\xxxx\\workspace\\[[Projektname]]\\WebContent\\data\\merge23345.pdf");
	}
	
	static void mergePDF(LinkedList<File> fileList, String fileLink){
        PDFMergerUtility mergePdf = new PDFMergerUtility();
        ListIterator<File> it =  fileList.listIterator();
        File filetemp;
        while(it.hasNext()){
        	filetemp = it.next();
            mergePdf.addSource(filetemp);
        }
        mergePdf.setDestinationFileName(fileLink);
        try {
        	mergePdf.mergeDocuments();
        }catch (COSVisitorException | IOException e) {
        	System.out.println(e);
        }
    }
}