Avatar billede petersss Nybegynder
22. marts 2004 - 01:23 Der er 19 kommentarer og
1 løsning

png billede gemt i mysql database. Tegn vises forkert

Jeg benytter mysql jdbc connector 3.0 . Jeg ønsker at lægge et png billede ind i i mysql database og derefter hente og gemme det som fil. Jeg benytter datatypen blob til at gemme billedet. Jeg uploader billedet ved at gemme dette som en streng, hvor jeg i øvrigt sætter backslashes foran ' (apostrof), da png-billedet ofte indeholder tegnet ' . Når jeg henter billedet ud igen sættes nogle af linjeskiftene tilsyneladende forkert, hvilket resulterer i en korrupt png fil med korrekt længde. Hvordan kommer jeg udenom problemet?
Avatar billede arne_v Ekspert
22. marts 2004 - 06:47 #1
Gæt: prøv at holde det som byte[] og undgå String. Og der skal ikke sættes
backslashes foran apostrof, hvis du gemmer rigtigt.
Avatar billede petersss Nybegynder
22. marts 2004 - 09:43 #2
hmm jeg har umiddelbart lidt svært ved at se hvordan jeg skulle kunne holde det som byte[], og gemme det i mysql db, når png-billedet fylder en del kb. Jeg kunne konvertere selve byte værdierne til en string adskilt af en eller anden delimiter.
Ang. apostrofferne: Hvis jeg ikke sætter backslashes foran, tror mysql at værdien for insertet er slut, da det jo netop er apostrof der markerer start og slut af værdier.
Avatar billede arne_v Ekspert
22. marts 2004 - 10:28 #3
Jeg ville aldrig bruge normal Statement til den slags data.

PreparedStatement og enten setBytes eller setBlob.

Og så er der ikke noget problem med single gnyffer.
Avatar billede petersss Nybegynder
22. marts 2004 - 11:52 #4
hvilken datatype skulle jeg sætte field til, hvis jeg ville holde det i byte[] ?
Avatar billede arne_v Ekspert
22. marts 2004 - 11:57 #5
stadig BLOB
Avatar billede petersss Nybegynder
22. marts 2004 - 18:15 #6
følgende skriver en masse tegn uden umiddelbar mening til fil1.png:
      InputStream is = connection.getInputStream();
      byte[] b = new byte[15000];    //is er mindre end 15 kb
      is.read(b)
      imageBytes = b;
      is.close();
...
Opret forbindelse til sql server
...
    PreparedStatement insert = con.prepareStatement("INSERT INTO table (imagefile) VALUES (?);");
        insert.setBytes(1,imageBytes);
        insert.execute();
...
Luk forbindelse, opret ny andet sted
...
      st = con.createStatement();
      rs = st.executeQuery("SELECT `imagefile` FROM `table`;");
      if (rs.next()) {
        FileOutputStream file = new FileOutputStream("fil1.png");
        file.write(rs.getBytes(1));
        file.flush(); file.close();
    }
Avatar billede petersss Nybegynder
22. marts 2004 - 19:30 #7
Jeg har hævet antallet af afsatte point, da jeg meget gerne vil have svar.
Avatar billede arne_v Ekspert
22. marts 2004 - 19:53 #8
(det er ikke p.g.a. for få point at jeg ikke har svaret før, men jeg har også
andre ting at lave end svare her)

Jeg kan ike forstå hvorfor det ikke virker.

Jeg lavede lige et simpelt eksempel.

CREATE TABLE blobtest (
  ID INTEGER(11),
  Picture BLOB
);

import java.io.*;
import java.sql.*;

public class BlobTest {
    public static void main(String[] args) throws Exception {
        byte[] b = new byte[(int)(new File("C:\\elogo.png")).length()];
        InputStream is = new FileInputStream("C:\\elogo.png");
        is.read(b);
        is.close();
        Class.forName("com.mysql.jdbc.Driver");
        Connection con = DriverManager.getConnection("jdbc:mysql://localhost/Test", "", "");
        PreparedStatement ins = con.prepareStatement("INSERT INTO BlobTest VALUES (?,?)");
        ins.setInt(1, 123);
        ins.setBytes(2, b);
        ins.executeUpdate();
        PreparedStatement sel = con.prepareStatement("SELECT Picture FROM BlobTest WHERE ID=?");
        sel.setInt(1, 123);
        ResultSet rs = sel.executeQuery();
        rs.next();
        byte[] b2 = rs.getBytes(1);
        con.close();
        OutputStream os = new FileOutputStream("C:\\elogo2.png");
        os.write(b2);
        os.close();
    }
}

og det virker perfekt !

elogo2.png er en perfekt kopi af elogo.png ...
Avatar billede arne_v Ekspert
22. marts 2004 - 19:57 #9
Jeg bruger executeUpdate og ikke execute til at udføre INSERT med, men
jeg ved ike om det gør en forskel.

Hvad er forskel på fil1 og fil2 hos dig ?

(PNG er noget ulæseligt binært grafik)
Avatar billede petersss Nybegynder
22. marts 2004 - 20:10 #10
ok, executeUpdate gjorde ikke forskel. Her er udsnit af første par linjer af den oprindelige png:
‰PNG

 
IHDR  b
og udsnit af nye png:
顢�悗끯論碧㶱燖⢰׵퐯ᠺ㤫ኮ崀�気ꍏꗴꔂ쏿攃㾰ϔ赼䰥纽
Avatar billede petersss Nybegynder
22. marts 2004 - 20:13 #11
har du i øvrigt givet blob feltet attributen BINARY ?
Avatar billede arne_v Ekspert
22. marts 2004 - 20:20 #12
Nej.

Det første B i BLOB står for binary.

Hvis det ikke er binary så er det en CLOB.

Som hedder TEXT og ikke CLOB i MySQL.
Avatar billede arne_v Ekspert
22. marts 2004 - 20:21 #13
Det ser meget ud som om den udskrives som noget UTF-16 eller lignende ...
Avatar billede arne_v Ekspert
22. marts 2004 - 20:24 #14
Har du prøvet at tage mit program og rette til med navne og køre ?
Avatar billede petersss Nybegynder
22. marts 2004 - 20:48 #15
hey arne, skriv et svar så får du de 100 point. Tak for hjælpen!
Jeg fandt ud af at problemet var at byte[] ikke havde filens længde når jeg hentede den fra inputstreamet. (Jeg satte selv en længde på 15kb) Af en eller anden grund ødelagde det hele byte arrayet. Er der nogen hurtig metode at kende længden på inputtet af et inputstream?
Avatar billede arne_v Ekspert
22. marts 2004 - 20:51 #16
svar
Avatar billede arne_v Ekspert
22. marts 2004 - 20:51 #17
Jeg brugte:

byte[] b = new byte[(int)(new File("C:\\elogo.png")).length()];

i mit eksempel.
Avatar billede arne_v Ekspert
22. marts 2004 - 20:52 #18
int n = is.read(b);

er måske også en mulighed hvis du kan bruge n senere.
Avatar billede petersss Nybegynder
22. marts 2004 - 20:54 #19
så er problemet bare at man har hentet streamets indhold i et array der er større end n, skal jeg kopiere indholdet i dette array over i et med længde n?
Avatar billede arne_v Ekspert
22. marts 2004 - 21:08 #20
Hvis du skal kalde pstmt.setBytes (som i dit tilfælde) - ja.

Men med f.eks. OutputStream kan du:
  os.write(b, 0, n);
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester