2009-03-09 11 views

Odpowiedz

7

Musisz użyć interfejsu przygotowanych oświadczeń sqlite. Zasadniczo chodzi o to, że przygotowuje oświadczenie o zastępczy dla blob, a następnie użyć jednego z wiążą wzywa do „bind” dane ...

SQLite Prepared Statements

+0

czekałem na ekwiwalent wstawki 'getBytes 'ale wygląda na to, że ani dostawca phxsoftware, ani devart.com nie mają sposobu na wstawienie danych bez posiadania pierwszego pliku w pamięci (devart.com's' SQLiteBlob' wyglądał obiecująco, ale nie obsługuje tego). –

73

Oto jak można to zrobić w 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(); 
     } 
    } 
} 
+1

Dziękujemy! : D (znaki zaakceptowane rano po wypróbowaniu kodu testowego) –

+0

Jak używasz tego w C#? i DLed http://www.codeproject.com/KB/database/cs_sqlitewrapper.aspx i dodał źródło do mojej klasy i użył przestrzeni nazw. Ale wydaje się, że używasz http://sqlite.phxsoftware.com/, więc próbowałem to zainstalować, ale nie miałem szczęścia (designer/install.exe). Sprawdziłem również w pliku .chm –

+4

Pobrałem System.Data.SQLite.dll z http://sqlite.phxsoftware.com/ i dodałem go do odniesień projektu. Nie ma potrzeby instalowania czegokolwiek. –

6

skończyło się z tego sposobu wstawiania blob:

protected Boolean updateByteArrayInTable(String table, String value, byte[] byteArray, String expr) 
    { 
     try 
     { 
     SQLiteCommand mycommand = new SQLiteCommand(connection); 
     mycommand.CommandText = "update " + table + " set " + value + "[email protected]" + " 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; 
     } 
    } 

do czytania go z powrotem kod jest:

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

+1 dla tablicy bajtów rzucanych w 'getImage'. Ratownik! – DanM7

+0

w którym języku powinno to być? – user5359531

+0

java jest tym, czego używałem w tym czasie – cdavidyoung

2

W C++ (bez sprawdzania błędów):

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

To może być SQLITE_STATICif the query will be executed before blob gets destructed.

4

To działało w porządku dla mnie (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(); 
    } 
} 

ma potrzeby wyrwy. Wystarczy rzutować na tablicę bajtów.

+0

w którym języku powinno to być? – user5359531

+1

C#. Dodałem to w komentarzu. – breez

+0

Jako ktoś nowy w SQLite, ta odpowiedź jest niesamowita! – JNW

0

Ponieważ nie istnieje kompletny przykład dla C++ jeszcze, to jak można wstawić i odzyskać tablicę/wektor danych zmiennoprzecinkowych bez sprawdzania błędów:

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