Wie speichere und rufe ich einen Blob von SQLite ab?

69

Ich habe SQLite in C ++, Python und jetzt (vielleicht) in C # verwendet. In all diesen Fällen habe ich keine Ahnung, wie ich einen Blob in eine Tabelle einfügen soll. Wie speichere und rufe ich einen Blob in SQLite ab?

Peter - Setzen Sie Monica wieder ein
quelle

Antworten:

92

So geht's in 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();
        }
    }
}
Darin Dimitrov
quelle
Wie benutzt man das in C #? i DLed codeproject.com/KB/database/cs_sqlitewrapper.aspx und fügte die Quelle meiner Klasse hinzu und verwendete den Namespace. Aber Sie scheinen sqlite.phxsoftware.com zu verwenden, also habe ich versucht, das zu installieren, hatte aber kein Glück (designer / install.exe). Ich habe auch in der .chm-Datei
4
Ich habe System.Data.SQLite.dll von sqlite.phxsoftware.com heruntergeladen und zu den Projektreferenzen hinzugefügt. Sie müssen nichts installieren.
Darin Dimitrov
8
Okay, es ist drei Jahre später ... aber worum geht es actualReadin diesem Code? Warum nicht einfach benutzen stream.Write(buffer, 0, bytesRead)?
Jon Skeet
2
@ Jon, der Punkt ist meine Dummheit. Danke fürs bemerken. Sofort beheben.
Darin Dimitrov
@DarinDimitrov TNX, aber was ist die CHUNK_SIZEund die nächste Frage: ‌ was ist mit Vektor von float?
Saeid
10

Das hat bei mir gut funktioniert (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();
    }
}

Kein Chunking nötig. Einfach in ein Byte-Array umwandeln.

Breez
quelle
In welcher Sprache soll das sein?
user5359531
1
C #. Ich habe dies im Kommentar hinzugefügt.
Breez
Als jemand, der neu in SQLite ist, ist diese Antwort erstaunlich!
JNW
kurze Frage: Da es sich um eine schreibgeschützte Operation handelt, wird sie benötigt / was bringt es, sie in eine Transaktion aufzunehmen und festzuschreiben?
Alexis Martial
Ich denke nicht, dass eine Transaktion in Kombination mit ausgewählten Aussagen viel Sinn macht, um ehrlich zu sein, aber das ist ein Thema für sich.
Breez
8

Sie müssen die vorbereitete Anweisungsschnittstelle von sqlite verwenden. Grundsätzlich besteht die Idee darin, dass Sie eine Anweisung mit einem Platzhalter für Ihren Blob vorbereiten und dann einen der Bindungsaufrufe verwenden, um Ihre Daten zu "binden" ...

Von SQLite vorbereitete Anweisungen

Dicroce
quelle
Ich habe nach einem INSERT-Äquivalent gesucht, GetBytesaber es scheint, dass weder der Anbieter der phxsoftware noch devart.com eine Möglichkeit haben, Daten einzufügen, ohne dass die gesamte Datei zuerst im Speicher gespeichert ist (devart.com SQLiteBlobsah vielversprechend aus, scheint dies jedoch nicht zu unterstützen). .
C.Evenhuis
8

Am Ende hatte ich folgende Methode zum Einfügen eines Blobs:

   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;
      }
   }

Zum Zurücklesen lautet der Code:

   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);
cdavidyoung
quelle
In welcher Sprache soll das sein?
user5359531
Java ist das, was ich zu der Zeit verwendet habe
cdavidyoung
6

Da es noch kein vollständiges Beispiel für C ++ gibt, können Sie auf diese Weise ein Array / einen Vektor von Float-Daten ohne Fehlerprüfung einfügen und abrufen:

#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;
}
Tjom
quelle
blobData.data () ist eine C ++ 11-Funktion, um Zugriff auf das zugrunde liegende Array zu erhalten
Benny
3

In C ++ (ohne Fehlerprüfung):

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);

Dies kann der Fall sein, SQLITE_STATIC wenn die Abfrage ausgeführt wird, bevor sie blobzerstört wird .

Claudiu
quelle