Linux C sqlite3操作二进制文件

1.前言

  默认读者对SQL操作有一定的了解。

  对于数值、字符串等数据的操作,用以下三个常用的接口就可以搞定。

#include "sqlite3.h"
// 打开数据库
SQLITE_API int sqlite3_open(
  const char *filename,   /* Database filename (UTF-8) */
  sqlite3 **ppDb          /* OUT: SQLite db handle */
);

// 执行SQL语句
SQLITE_API int sqlite3_exec(
  sqlite3*,                                  /* An open database */
  const char *sql,                           /* SQL to be evaluated */
  int (*callback)(void*,int,char**,char**),  /* Callback function */
  void *,                                    /* 1st argument to callback */
  char **errmsg                              /* Error msg written here */
);

// 关闭数据库
SQLITE_API int sqlite3_close(sqlite3*);

  如果想操作图片等二进制数据呢?上面这三个接口肯定可能就不够用了,当然也可以考虑使用base64编码。

  本文要介绍的是如何使用sqlite3操作二进制文件。


2.接口介绍

#include "sqlite3.h"
// SQL语句准备
SQLITE_API int sqlite3_prepare_v2(
  sqlite3 *db,            /* Database handle */
  const char *zSql,       /* SQL statement, UTF-8 encoded */
  int nByte,              /* Maximum length of zSql in bytes. */
  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
  const char **pzTail     /* OUT: Pointer to unused portion of zSql */
);

// 绑定二进制数据
SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));

// 执行
SQLITE_API int sqlite3_step(sqlite3_stmt*);

// 释放
SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt);



3.demo

将一张图片保存到数据库中,再读取数据库中的图片,存到另一个文件中。
git地址: https://gitee.com/yu-jiahang/sqlite3

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdarg.h>
#include "sqlite3.h"

// 带文件名与行号log输出
#define LOG(...) printf("%s-%d: ",__FILE__, __LINE__);printf(__VA_ARGS__)

// 查询回调函数
int callback(void *data, int argc, char **argv, char **azColName);

int main(int argc, char* argv[])
{
    
    
   sqlite3_stmt * stmt;                     
   sqlite3 *db;           
   char *zErrMsg = 0;   //记录返回的错误信息
   char *sql_str;       //存sql语句
   char SQL[100] = {
    
    0};
   int sql_data = 0;    //其作为回调函数的第一个参数,可在回调函数中改变其值。
   int res;
   int fd;
   off_t fd_len;
   void *data_p;        
   int data_len;
   void *column_p;
   int column_len;

   // 打开文件
   fd = open("test.jpg", O_RDONLY);
   if(fd == -1)
   {
    
    
      LOG("Fail to open file.\r\n");
      exit(EXIT_FAILURE);
   }

   // 获取文件大小
   fd_len = lseek(fd, 0, SEEK_END);
   LOG("The file size is %ld byte.\r\n", fd_len);

   // 读取文件到内存 pread为指定光标位置读取 不改变当前光标位置
   data_p = malloc(fd_len);
   data_len = pread(fd, data_p, fd_len, 0);
   if (data_len != fd_len)
   {
    
    
      LOG("Fail to read file.\r\n");
      exit(EXIT_FAILURE);
   }
   close(fd);

   // 打开数据库
   res = sqlite3_open("test.db", &db);     
   if( res != SQLITE_OK )
   {
    
    
      LOG("Fail to open database.\r\n");
      exit(EXIT_FAILURE);
   }

   // 查询表是否存在
   sql_str = "SELECT COUNT(*) FROM sqlite_master WHERE name=='my_table';";
   res = sqlite3_exec(db, sql_str, callback, &sql_data, &zErrMsg);
   if( res != SQLITE_OK )
   {
    
    
      LOG("Select failed: %s.\r\n", zErrMsg);
      sqlite3_free(zErrMsg);
   }

   LOG("The number of tables is %d.\r\n", sql_data);

   // 表中无数据则创建
   if(sql_data == 0)
   {
    
    
      sql_str = "create table my_table( \
                  key       int   primary key   not null, \
                  data      blob                not null);"; 

      res = sqlite3_exec(db, sql_str, callback, &sql_data, &zErrMsg);
      if( res != SQLITE_OK )
      {
    
    
         LOG("Fail to create table: %s.\r\n", zErrMsg);
         sqlite3_free(zErrMsg);
      }
 
      /****************************************写二进制值****************************************/
      memset(SQL, 0, 100);
      sprintf(SQL, "insert into my_table(key, data) values(1,?)");

      // 把sql语句解析到stmt中去
      res = sqlite3_prepare_v2( db, SQL, -1, &stmt, NULL);
      if( res != SQLITE_OK )
      {
    
    
         LOG("Stmt preparation failed.\r\n");
      }
 
      // 绑定二进制数据
      res = sqlite3_bind_blob( stmt, 1, data_p, data_len, NULL); 
      if( res != SQLITE_OK )
      {
    
    
         LOG("Stmt binding failed.\r\n");
      }

      // 写入数据库
      res = sqlite3_step(stmt);
      if( res != SQLITE_DONE )
      {
    
    
         LOG("Stmt executed failed.\r\n");
      }

      // 释放资源
      free(data_p);
      res = sqlite3_finalize(stmt);
      if( res != SQLITE_OK )
      {
    
    
         LOG("Stmt released failed.\r\n");
      }

   }

   /****************************************读二进制值****************************************/
   res = sqlite3_prepare_v2( db, "select * from my_table", -1, &stmt, NULL);
   if( res != SQLITE_OK )
   {
    
    
      LOG("Stmt preparation failed.\r\n");
   }
 
   // 读数据 每循环一遍就是获取一行数据
   while(1)
   {
    
    
      res = sqlite3_step(stmt);
      if( res == SQLITE_DONE )
      {
    
    
         LOG("Stmt executed successfully.\r\n");
         break;
      }
      else if( res != SQLITE_ROW )
      {
    
    
         LOG("Stmt executed failed.\r\n");
         break;
      } 
      else
      {
    
    
         // 获取第1列的文件大小
         column_len = sqlite3_column_bytes(stmt, 1);

         // 获取第1列内容的首地址 不需要释放内存
         column_p =  (char *)sqlite3_column_blob(stmt, 1); 

         // 创建并写入文件
         fd = open("test2.jpg", O_RDWR|O_CREAT|O_TRUNC, S_IRWXU);
         if(fd == -1)
         {
    
    
            LOG("Fail to open file.\r\n");
            exit(EXIT_FAILURE);
         }

         fd_len = write(fd, column_p, column_len);
         if (fd_len != column_len)
         {
    
    
            LOG("Fail to write file.\r\n");
            exit(EXIT_FAILURE);
         }
         close(fd);
      }
   }

   res = sqlite3_finalize(stmt);
   if( res != SQLITE_OK )
   {
    
    
      LOG("Stmt released failed.\r\n");
   }

   sqlite3_close(db);

   return 0;
}


// 回调函数  打印查询的信息
int callback(void *data, int argc, char **argv, char **azColName)
{
    
    
   int i;

   *(int *)data = atoi(argv[0]);

   for(i = 0; i < argc; i++)
   {
    
    
      printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
   }

   printf("\n");
   return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36973838/article/details/114922810
今日推荐