Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I store and retrieve a blob from sqlite?

Tags:

sqlite

blob

People also ask

Can SQLite store blobs?

A BLOB (large binary object) is an SQLite data type that stores large objects, typically large files such as images, music, videos, documents, pdf, etc. We need to convert our files and images into binary data (byte array in Python) to store it into SQLite database.

What is BLOB storage SQLite?

A blob is a SQLite datatype representing a sequence of bytes. It can be zero or more bytes in size. SQLite blobs have an absolute maximum size of 2GB and a default maximum size of 1GB. An alternate approach to using blobs is to store the data in files and store the filename in the database.

How do I store images in SQLite database?

Inorder to store images to android SQLite database, you need to convert the image uri to bitmap then to binary characters that is, bytes[] sequence. Then set the table column data type as BLOB data type. After retrieving the images from DB, convert the byte[] data type to bitmap in order to set it to imageview.

How does Python store images in SQLite?

1. Set the connection to the SQLite database using Python code. 2. We need to define an INSERT query for inserting the BLOB data into the table.


Here's how you can do it 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();
        }
    }
}

This worked fine for me (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();
    }
}

No need for chunking. Just cast to a byte array.


I ended up with this method for inserting a 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;
      }
   }

For reading it back the code is:

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

You need to use sqlite's prepared statements interface. Basically, the idea is that you prepare a statement with a placeholder for your blob, then use one of the bind calls to "bind" your data...

SQLite Prepared Statements