【问题标题】:How do I store and retrieve a blob from sqlite?如何从 sqlite 存储和检索 blob?
【发布时间】:2010-10-12 02:54:16
【问题描述】:

我在 c++、python 和现在(也许)在 C# 中使用了 sqlite。在所有这些中,我不知道如何将 blob 插入表中。如何在 sqlite 中存储和检索 blob?

【问题讨论】:

    标签: sqlite blob


    【解决方案1】:

    在 C# 中你可以这样做:

    class Program
    {
        static void Main(string[] args)
        {
            if (File.Exists("test.db3"))
            {
                File.Delete("test.db3");
            }
            using (var connection = new SQLiteConnection("Data Source=test.db3;Version=3"))
            using (var command = new SQLiteCommand("CREATE TABLE PHOTOS(ID INTEGER PRIMARY KEY AUTOINCREMENT, PHOTO BLOB)", connection))
            {
                connection.Open();
                command.ExecuteNonQuery();
    
                byte[] photo = new byte[] { 1, 2, 3, 4, 5 };
    
                command.CommandText = "INSERT INTO PHOTOS (PHOTO) VALUES (@photo)";
                command.Parameters.Add("@photo", DbType.Binary, 20).Value = photo;
                command.ExecuteNonQuery();
    
                command.CommandText = "SELECT PHOTO FROM PHOTOS WHERE ID = 1";
                using (var reader = command.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        byte[] buffer = GetBytes(reader);
                    }
                }
    
            }
        }
    
        static byte[] GetBytes(SQLiteDataReader reader)
        {
            const int CHUNK_SIZE = 2 * 1024;
            byte[] buffer = new byte[CHUNK_SIZE];
            long bytesRead;
            long fieldOffset = 0;
            using (MemoryStream stream = new MemoryStream())
            {
                while ((bytesRead = reader.GetBytes(0, fieldOffset, buffer, 0, buffer.Length)) > 0)
                {
                    stream.Write(buffer, 0, (int)bytesRead);
                    fieldOffset += bytesRead;
                }
                return stream.ToArray();
            }
        }
    }
    

    【讨论】:

    • 如何在 C# 中使用它?我 DLed codeproject.com/KB/database/cs_sqlitewrapper.aspx 并将源代码添加到我的班级并使用了命名空间。但是您似乎使用sqlite.phxsoftware.com,所以我尝试安装它但没有运气(设计师/install.exe)。我还查看了 .chm 文件
    • 我从sqlite.phxsoftware.com 下载了 System.Data.SQLite.dll 并将其添加到项目引用中。无需安装任何东西。
    • 好的,三年后...但是这段代码中actualRead 的意义何在?为什么不直接使用stream.Write(buffer, 0, bytesRead)
    • @Jon,关键是我的愚蠢。感谢您的关注。立即修复。
    • @DarinDimitrov TNX,但是CHUNK_SIZE 是什么,下一个问题是:浮点向量呢?
    【解决方案2】:

    这对我来说很好用(C#):

    byte[] iconBytes = null;
    using (var dbConnection = new SQLiteConnection(DataSource))
    {
        dbConnection.Open();
        using (var transaction = dbConnection.BeginTransaction())
        {
            using (var command = new SQLiteCommand(dbConnection))
            {
                command.CommandText = "SELECT icon FROM my_table";
    
                using (var reader = command.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        if (reader["icon"] != null && !Convert.IsDBNull(reader["icon"]))
                        {
                            iconBytes = (byte[]) reader["icon"];
                        }
                    }
                }
            }
            transaction.Commit();
        }
    }
    

    不需要分块。只需转换为字节数组即可。

    【讨论】:

    • 这应该是哪种语言?
    • C#。我已经在评论中添加了这个。
    • 作为 SQLite 新手,这个答案太棒了!
    • 快速问题:既然这是一个只读操作,是否需要/将其包含在事务中并提交它有什么好处?
    • 老实说,我认为事务与 select 语句结合起来没有多大意义,但这本身就是一个话题。
    【解决方案3】:

    我最终使用了这种插入 blob 的方法:

       protected Boolean updateByteArrayInTable(String table, String value, byte[] byteArray, String expr)
       {
          try
          {
             SQLiteCommand mycommand = new SQLiteCommand(connection);
             mycommand.CommandText = "update " + table + " set " + value + "=@image" + " where " + expr;
             SQLiteParameter parameter = new SQLiteParameter("@image", System.Data.DbType.Binary);
             parameter.Value = byteArray;
             mycommand.Parameters.Add(parameter);
    
             int rowsUpdated = mycommand.ExecuteNonQuery();
             return (rowsUpdated>0);
          }
          catch (Exception)
          {
             return false;
          }
       }
    

    回读代码是:

       protected DataTable executeQuery(String command)
       {
          DataTable dt = new DataTable();
          try
          {
             SQLiteCommand mycommand = new SQLiteCommand(connection);
             mycommand.CommandText = command;
             SQLiteDataReader reader = mycommand.ExecuteReader();
             dt.Load(reader);
             reader.Close();
             return dt;
          }
          catch (Exception)
          {
             return null;
          }
       }
    
       protected DataTable getAllWhere(String table, String sort, String expr)
       {
          String cmd = "select * from " + table;
          if (sort != null)
             cmd += " order by " + sort;
          if (expr != null)
             cmd += " where " + expr;
          DataTable dt = executeQuery(cmd);
          return dt;
       }
    
       public DataRow getImage(long rowId) {
          String where = KEY_ROWID_IMAGE + " = " + Convert.ToString(rowId);
          DataTable dt = getAllWhere(DATABASE_TABLE_IMAGES, null, where);
          DataRow dr = null;
          if (dt.Rows.Count > 0) // should be just 1 row
             dr = dt.Rows[0];
          return dr;
       }
    
       public byte[] getImage(DataRow dr) {
          try
          {
             object image = dr[KEY_IMAGE];
             if (!Convert.IsDBNull(image))
                return (byte[])image;
             else
                return null;
          } catch(Exception) {
             return null;
          }
       }
    
       DataRow dri = getImage(rowId);
       byte[] image = getImage(dri);
    

    【讨论】:

    • 这应该是哪种语言?
    • java是我当时用的
    【解决方案4】:

    您需要使用 sqlite 的预处理语句接口。基本上,这个想法是你为你的 blob 准备一个带有占位符的语句,然后使用一个绑定调用来“绑定”你的数据......

    SQLite Prepared Statements

    【讨论】:

    • 我一直在寻找与 GetBytes 等效的 INSERT 但似乎 phxsoftware 的提供者和 devart.com 都没有办法在不先将整个文件放入内存的情况下插入数据(devart.com 的 @ 987654323@ 看起来很有希望,但似乎不支持这一点)。
    【解决方案5】:

    由于尚无 C++ 的完整示例,因此您可以通过以下方式插入和检索浮点数据的数组/向量,而无需进行错误检查:

    #include <sqlite3.h>
    
    #include <iostream>
    #include <vector>
    
    int main()
    {
        // open sqlite3 database connection
        sqlite3* db;
        sqlite3_open("path/to/database.db", &db);
    
        // insert blob
        {
            sqlite3_stmt* stmtInsert = nullptr;
            sqlite3_prepare_v2(db, "INSERT INTO table_name (vector_blob) VALUES (?)", -1, &stmtInsert, nullptr);
    
            std::vector<float> blobData(128); // your data
            sqlite3_bind_blob(stmtInsertFace, 1, blobData.data(), static_cast<int>(blobData.size() * sizeof(float)), SQLITE_STATIC);
    
            if (sqlite3_step(stmtInsert) == SQLITE_DONE)
                std::cout << "Insert successful" << std::endl;
            else
                std::cout << "Insert failed" << std::endl;
    
            sqlite3_finalize(stmtInsert);
        }
    
        // retrieve blob
        {
            sqlite3_stmt* stmtRetrieve = nullptr;
            sqlite3_prepare_v2(db, "SELECT vector_blob FROM table_name WHERE id = ?", -1, &stmtRetrieve, nullptr);
    
            int id = 1; // your id
            sqlite3_bind_int(stmtRetrieve, 1, id);
    
            std::vector<float> blobData;
            if (sqlite3_step(stmtRetrieve) == SQLITE_ROW)
            {
                // retrieve blob data
                const float* pdata = reinterpret_cast<const float*>(sqlite3_column_blob(stmtRetrieve, 0));
                // query blob data size
                blobData.resize(sqlite3_column_bytes(stmtRetrieve, 0) / static_cast<int>(sizeof(float)));
                // copy to data vector
                std::copy(pdata, pdata + static_cast<int>(blobData.size()), blobData.data());
            }
    
            sqlite3_finalize(stmtRetrieve);
        }
    
        sqlite3_close(db);
    
        return 0;
    }
    

    【讨论】:

    • blobData.data() 是用于访问底层数组的 C++11 函数
    【解决方案6】:

    在 C++ 中(没有错误检查):

    std::string blob = ...; // assume blob is in the string
    
    
    std::string query = "INSERT INTO foo (blob_column) VALUES (?);";
    
    sqlite3_stmt *stmt;
    sqlite3_prepare_v2(db, query, query.size(), &stmt, nullptr);
    sqlite3_bind_blob(stmt, 1, blob.data(), blob.size(), 
                      SQLITE_TRANSIENT);
    

    可以是SQLITE_STATIC if the query will be executed before blob gets destructed

    【讨论】:

      猜你喜欢
      • 2015-11-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-28
      • 2013-07-21
      • 2016-08-23
      相关资源
      最近更新 更多