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?
69
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();
}
}
}
actualRead
in diesem Code? Warum nicht einfach benutzenstream.Write(buffer, 0, bytesRead)
?CHUNK_SIZE
und die nächste Frage: was ist mit Vektor von float?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.
quelle
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
quelle
GetBytes
aber 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.comSQLiteBlob
sah vielversprechend aus, scheint dies jedoch nicht zu unterstützen). .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);
quelle
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; }
quelle
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 sieblob
zerstört wird .quelle