无法将图像保存为blob到sqlite

10

我正在使用SQLite,但无法将图像保存到数据库中。这是我的代码:

File file = new File(url);
  try {
    fis = new FileInputStream(file);
  } catch (FileNotFoundException e) {}
fileLenght = (int) file.length();

stat.executeUpdate("create table "+tableName+" (id int,name String ,image Blob, features String);");
prep = conn.prepareStatement("insert into "+tableName+" values (?, ?, ?, ?);");
prep.setBinaryStream(3, fis, fileLenght);

我遇到的错误是:

java.sql.SQLException: not implemented by SQLite JDBC driver
  at org.sqlite.Unused.unused(Unused.java:29)
  at org.sqlite.Unused.setBinaryStream(Unused.java:58)
我正在使用以下的jar包:sqlitejdbc-v056.jar。
有什么想法吗? 谢谢。
5个回答

17
您正在使用的SQLite JDBC实现没有实现setBinaryStream方法(因此会出现准确的 SQLite JDBC驱动程序未实现错误消息)。
您需要改用setBytes方法。

Golden: 完全没想到那会起作用,但很高兴它确实起了作用 :-) - Femi
1
很惊讶居然没有比那个更近/更完整的JDBC驱动程序。 - Femi
当使用setBytes而不是setBinaryStream时,是否存在可以保存的数据大小限制,或者只是不能使用流的事实? - Cristian Vrabie

9
你可以很容易地将图像插入到数据库中,比如SQLite,请参考我的以下代码。 我使用了一个属性文件来进行数据库连接,你可以将其放在任何地方。
public class JDBCSqliteConn
{
    public static void main(String args[]) throws FileNotFoundException, IOException
    {
        Connection connection = null;
        //ResultSet resultSet = null;
        PreparedStatement ps = null;
        String file = "C:\\Fingerprint\\histoImg_med.png";
        Properties prop = new Properties();
        int s = 0;
        byte[] person_image = null;
        File image = new File(file);
        FileInputStream fis = new FileInputStream(image);
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        byte[] buf = new byte[1024];

        try {
            for (int readNum; (readNum = fis.read(buf)) != -1;)
            {
                bos.write(buf, 0, readNum);
                //no doubt here is 0
                /*Writes len bytes from the specified byte array starting at offset
                off to this byte array output stream.*/
                System.out.println("read " + readNum + " bytes,");
            }
        } catch (IOException ex) {
            System.err.println(ex.getMessage());
        }
        person_image = bos.toByteArray();

        try {
            prop.load(new FileInputStream("C:\\dbconfig.properties"));  
            Class.forName(prop.getProperty("driver"));
            connection = DriverManager.getConnection(prop.getProperty("url"));

            ps = connection.prepareStatement("INSERT INTO epmc_tbl_test_img (hhld_photo) VALUES (?)");
            ps.setBytes(1, person_image);
            s = ps.executeUpdate();
            if (s > 0)
            {
                System.out.println("Image Uploaded");
            }
            ps.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                ps.close();
                connection.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

我的逻辑是将图像转换为字节数组,然后存储到数据库中。SQLite接受Image类型的BLOB字节数组。

这是我的dbconfig.properties文件:

driver = org.sqlite.JDBC
url = jdbc:sqlite:C:\\Ronald\\Personal\\epmc\\JavaJ2EE\\EPMC.db

尝试使用这段代码。

3

如果要与Hibernate一起使用,必须使用适当的UserType:

public class PersistentFileAsBlob implements EnhancedUserType, Serializable {

    public static final PersistentFileAsBlob INSTANCE = new PersistentFileAsBlob();

    private static final int[] SQL_TYPES = new int[] { Types.BLOB };

    @Override
    public int[] sqlTypes() {
        return SQL_TYPES;
    }

    @Override
    public Class<?> returnedClass() {
        return File.class;
    }

    @Override
    public boolean equals(Object x, Object y) throws HibernateException {
        if (x == y) {
            return true;
        }
        if (x == null || y == null) {
            return false;
        }
        File dtx = (File) x;
        File dty = (File) y;
        return dtx.equals(dty);
    }

    @Override
    public int hashCode(Object x) throws HibernateException {
        return x.hashCode();
    }

    @Override
    public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
            throws HibernateException, SQLException {
        if (owner == null) {
            return null;
        }

        FileOutputStream fos = null;
        GzipCompressorInputStream cis = null;
        try {
            File file = File.createTempFile(String.valueOf(owner.hashCode()),
                    "");
            byte[] bytes = rs.getBytes(names[0]);
            System.out.println(bytes.length);
            fos = new FileOutputStream(file);
            cis = new GzipCompressorInputStream(new BufferedInputStream(
                    new ByteArrayInputStream(bytes)));
            int n = 0;
            final byte[] buffer = new byte[1024];
            while (-1 != (n = cis.read(buffer))) {
                fos.write(buffer, 0, n);
            }
            fos.close();
            return file;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        } finally {
            if (fos != null)
                try {
                    fos.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            if (cis != null)
                try {
                    cis.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
        }
    }

    @Override
    public void nullSafeSet(PreparedStatement st, Object value, int index)
            throws HibernateException, SQLException {
        if (value == null) {
            StandardBasicTypes.BINARY.nullSafeSet(st, null, index);
            return;
        }

        File file = (File) value;

        FileInputStream fis = null;
        ByteArrayOutputStream bos = null;
        GzipCompressorOutputStream cos = null;
        try {
            fis = new FileInputStream(file);
            bos = new ByteArrayOutputStream();
            cos = new GzipCompressorOutputStream(new BufferedOutputStream(bos));
            int n = 0;
            final byte[] buffer = new byte[1024];
            while (-1 != (n = fis.read(buffer))) {
                cos.write(buffer, 0, n);
            }
            cos.close();
            StandardBasicTypes.BINARY.nullSafeSet(st, bos.toByteArray(), index);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        } finally {
            if (fis != null)
                try {
                    fis.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            if (cos != null)
                try {
                    cos.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
        }
    }

    @Override
    public Object deepCopy(Object value) throws HibernateException {
        return value;
    }

    @Override
    public boolean isMutable() {
        return false;
    }

    @Override
    public Serializable disassemble(Object value) throws HibernateException {
        return (Serializable) value;
    }

    @Override
    public Object assemble(Serializable cached, Object owner)
            throws HibernateException {
        return cached;
    }

    @Override
    public Object replace(Object original, Object target, Object owner)
            throws HibernateException {
        return original;
    }

    @Override
    public String objectToSQLString(Object value) {
        throw new UnsupportedOperationException();
    }

    @Override
    public String toXMLString(Object value) {
        return value.toString();
    }

    @Override
    public Object fromXMLString(String xmlValue) {
        return new File(xmlValue);
    }

}

你需要注释你的类型,并引用这个UserType:

@Entity
public class Mensagem {

    @Column(nullable = false)
    @Type(type = "package.to.class.PersistentFileAsBlob")
    private File file;

}

从这里可以看出,我在保存数据之前进行压缩,并在检索之前进行解压缩。请查看此网站


1

已经提交了一个包含setBinaryStream实现的补丁到Xerial。

对我来说,使用setBytes不是一个选项,因为我正在使用Hibernate访问数据库。

diff -r 144ade82d1fe -r 5a141e1b82f0 src/main/java/org/sqlite/PrepStmt.java
--- a/src/main/java/org/sqlite/PrepStmt.java        Thu Jun 09 17:15:36 2011 +0900
+++ b/src/main/java/org/sqlite/PrepStmt.java        Wed Oct 26 11:02:15 2011 -0700
@@ -16,7 +16,9 @@

 package org.sqlite;

+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.Reader;
 import java.sql.Date;
 import java.sql.ParameterMetaData;
@@ -254,6 +256,38 @@
         batch(pos, value);
     }   

+    @Override
+    public void setBinaryStream(int pos, InputStream istream, int length) throws SQLException
+    {
+      ByteArrayOutputStream baos = new ByteArrayOutputStream();
+      try 
+      {
+        int bval = 0;
+   
+        while ((bval = istream.read()) != -1)
+        {   
+          baos.write(bval);
+        }   
+        baos.flush();
+        setBytes(pos, baos.toByteArray());
+      }   
+      catch (IOException e)
+      {
+        throw new SQLException("Cannot read from binary stream, exception message: " + e.getMessage());
+      }
+      finally
+      {
+        try 
+        {   
+          baos.close();
+        }   
+        catch (IOException e)
+        {   
+          throw new SQLException("Can't close stream");
+        }   
+      }
+    }
+   
     public void setCharacterStream(int pos, Reader reader, int length) throws SQLException {
         try {
             // copy chars from reader to StringBuffer

0

看起来你的语句没有绑定所有四个参数。


我在我的代码中做了这件事,但没有在这里写出来,因为我认为这不相关。当我尝试保存图像时出现了一些问题。 - Mara

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接