65.9K
CodeProject 正在变化。 阅读更多。
Home

C# & SQLite - 存储图像

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.77/5 (11投票s)

2011 年 5 月 15 日

CPOL

5分钟阅读

viewsIcon

127396

downloadIcon

9782

如何将图像/二进制数据插入数据库。

引言

本文旨在演示如何将图像加载到 SQLite 数据库中并检索它们进行查看。它使用 VS2010、C#、.NET4.0 编写,并使用 ADO.NET 提供程序 System.Data.SQLite 连接到 SQLite 数据库。所有这些都在 Windows XP 环境中。

背景

首先,必须获取一些文件并按照规则安装它们

SQLite ADO.NET 提供程序:我将包安装到我的“C:\”目录中,并且选择不注册 DLL 文件,因为我只希望将 DLL 文件包含到我的项目中。

使用代码

SQLite

首先,我创建了一个名为 ImageLib.s3db 的新数据库,并添加了一个表和所需的字段。

CREATE TABLE [ImageStore] (
[ImageStore_Id] INTEGER  NOT NULL PRIMARY KEY AUTOINCREMENT,
[ImageFile] NVARCHAR(20)  NULL,
[ImageBlob] BLOB  NULL
);

VS2010 - C# - .NET 4.0

接下来,我创建了一个名为 StoringImages 的 VS2010 项目,更改了默认命名空间,并添加了一些文件夹和文件。

  • 文件夹:Database
    • 文件:StoringImages.s3db
      • 属性:复制到输出目录 => 始终复制
  • 文件夹:Model
    • dBFunctions.cs
    • dBHelper.cs
    • Image.cs
    • ImageHelper.cs
  • 文件:System.Data.SQLite.dll
    • 属性:复制到输出目录 => 始终复制
  • 文件:SQLite.Interop.dll
    • 属性:复制到输出目录 => 始终复制
  • 表单:DisplayImages
    • 这是项目的启动表单

System.Data.SQLite.dllSQLite.Interop.dll 都需要放置在根(项目)StoringImages 的正下方。这确保这两个文件都安装在与项目“*.exe”文件相同的目录中。

SolutionExplore.PNG

解决方案资源管理器

模型

Model 文件夹中,有几个类,两个用于处理所有数据库事务,两个用于处理图像事务。处理数据库事务的两个类 dBFunctionsdBHelper,我之前在我的上一篇文章 C# & SQLite 中使用过。所以接下来,我将解释如何使用剩下的两个类:ImageImageHelper

我将使用 Image 类作为自定义变量,它将用于存储导入图像文件的数据,以便在方法之间传递。

完成所有繁重工作的类是 ImageHelper。在这个类中,你会找到各种处理图像的插入、删除和另存为的方法。Insert 使用另一个名为 LoadImage 的方法,该方法处理图像的二进制读取。Delete 用于从数据库中删除数据。SaveAs 用于将图像保存回所选目录。每次事务后,都会生成一个 事务状态,形式为 isSucces。视图(表单)DisplayImages 需要此状态才能更新或不更新自身。

ImageHelper - 引用赋值

我尽量不使用比所需更多的引用,但有时会忘记删除 VS2010 自动添加到每个新类中的引用。

using System;
using System.IO;
using System.Windows.Forms;
using System.Data;
using System.Data.SQLite;
ImageHelper - 变量声明

MaxImageSize 用于声明导入图像时允许的最大字节数,在此示例中,它在 LoadImage 方法中被覆盖。

private dBHelper helper = null;
private string fileLocation = string.Empty;
private bool isSucces = false;
private int maxImageSize = 2097152;

//2MB   - 2097152
//5MB   - 5242880
//10MB  - 10485760

/*  Conversion
 *  1 Byte = 8 Bit
 *  1 Kilobyte = 1024 Bytes
 *  1 Megabyte = 1048576 Bytes
 *  1 Gigabyte = 1073741824 Bytes
 * */

dBHelper 是处理数据库事务的类。maxImageSize 用于上传时允许的默认最大字节数。isSucces 告知视图事务 [插入、删除、另存为] 是否成功。

ImageHelper - 属性
private string FileLocation
{
    get { return fileLocation; }
    set
    {
        fileLocation = value;
    }
}
ImageHelper - GetSucces 方法

此方法由表单 DisplayImage 使用,以查找事务 [插入、删除、另存为] 是否成功。

public Boolean GetSucces()
{
    return isSucces;
}
ImageHelper - LoadImage 方法

首先,我们向用户询问所选图像文件的位置 [路径],以便我们可以在 FileStream 中使用它。一旦 Filestream 打开,我们将图像读取为二进制并将在 Image 类的实例中获取的数据存储起来,我们将把它发送给方法 LoadImage 的调用者,即 InsertImage 方法。

private Image LoadImage()
{
    //Create an instance of the Image Class/Object
    //so that we can store the information
    //about the picture an send it back for
    //processing into the database.
    Image image = null;

    //Ask user to select Image
    OpenFileDialog dlg = new OpenFileDialog();
    dlg.InitialDirectory = @"C:\\";
    dlg.Title = "Select Image File";
    //dlg.Filter = "Tag Image File Format (*.tiff)|*.tiff";
    //dlg.Filter += "|Graphics Interchange Format (*.gif)|*.gif";
    //dlg.Filter += "|Portable Network Graphic Format (*.png)|*.png";
    //dlg.Filter += "|Joint Photographic Experts Group Format (*.jpg)|*.jpg";
    //dlg.Filter += "|Joint Photographic Experts Group Format (*.jpeg)|*.jpeg";
    //dlg.Filter += "|Nikon Electronic Format (*.nef)|*.nef";
    //dlg.Filter += "|All files (*.*)|*.*";
    dlg.Filter = "Image Files  (*.jpg ; *.jpeg ; *.png ; *.gif ; *.tiff ; *.nef)
                                |*.jpg;*.jpeg;*.png;*.gif;*.tiff;*.nef";
    dlg.ShowDialog();

    this.FileLocation = dlg.FileName;

    if (fileLocation == null || fileLocation == string.Empty)
        return image;

    if (FileLocation != string.Empty && fileLocation != null)
    {
        Cursor.Current = Cursors.WaitCursor;

        //Get file information and calculate the filesize
        FileInfo info = new FileInfo(FileLocation);
        long fileSize = info.Length;

        //reasign the filesize to calculated filesize
        maxImageSize = (Int32)fileSize;

        if (File.Exists(FileLocation))
        {
            //Retreave image from file and binary it to Object image
            using (FileStream stream = File.Open(FileLocation, FileMode.Open))
            {
                BinaryReader br = new BinaryReader(stream);
                byte[] data = br.ReadBytes(maxImageSize);
                image = new Image(dlg.SafeFileName, data, fileSize);
            }
        }
        Cursor.Current = Cursors.Default;
    }
    return image;
}
ImageHelper - InsertImage 方法

InsertImage 通过 NewPicture 方法从视图(表单)DisplayImages 调用。一旦插入成功完成,它将把新获得的 image_id 返回给视图。

正如你所注意到的,在 InsertImageLoadImage 方法之间使用了 Image 类的一个实例。

public Int32 InsertImage()
{
    DataRow dataRow = null;
    isSucces = false;

    Image image = LoadImage();

    //if no file was selected and no image was created return 0
    if (image == null) return 0;

    if (image != null)
    {
        // Determin the ConnectionString
        string connectionString = dBFunctions.ConnectionStringSQLite;

        // Determin the DataAdapter = CommandText + Connection
        string commandText = "SELECT * FROM ImageStore WHERE 1=0";

        // Make a new object
        helper = new dBHelper(connectionString);
        {
            // Load Data
            if (helper.Load(commandText, "image_id") == true)
            {
                // Add a row and determin the row
                helper.DataSet.Tables[0].Rows.Add(
                                   helper.DataSet.Tables[0].NewRow());
                dataRow = helper.DataSet.Tables[0].Rows[0];

                // Enter the given values
                dataRow["imageFileName"] = image.FileName;
                dataRow["imageBlob"] = image.ImageData;
                dataRow["imageFileSizeBytes"] = image.FileSize;

                try
                {
                    // Save -> determin succes
                    if (helper.Save() == true)
                    {
                        isSucces = true;

                    }
                    else
                    {
                        isSucces = false;
                        MessageBox.Show("Error during Insertion");
                    }
                }
                catch (Exception ex)
                {
                    // Show the Exception --> Dubbel Id/Name ?
                    MessageBox.Show(ex.Message);
                }

            }//END IF
        }
    }
   //return the new image_id
   return Convert.ToInt32(dataRow[0].ToString());
}
ImageHelper - DeleteImage 方法

DeleteImage 执行从数据库中删除图像的操作。该方法需要一个整数,即数据集的行号,由视图(表单)DisplayImages 通过 DeletePicture 方法提供。处理后,DeleteImage 将“状态”返回给 DeletePicture

public void DeleteImage(Int32 imageID)
{
    //Set variables
    isSucces = false;

    // Determin the ConnectionString
    string connectionString = dBFunctions.ConnectionStringSQLite;

    // Determin the DataAdapter = CommandText + Connection
    string commandText = "SELECT * FROM ImageStore WHERE image_id=" + imageID;

    // Make a new object
    helper = new dBHelper(connectionString);
    {
        // Load Data
        if (helper.Load(commandText, "image_id") == true)
        {
            // Determin if the row was found
            if (helper.DataSet.Tables[0].Rows.Count == 1)
            {
                // Found, delete row
                helper.DataSet.Tables[0].Rows[0].Delete();
                try
                {
                    // Save -> determin succes
                    if (helper.Save() == true)
                    {
                        isSucces = true;
                    }
                    else
                    {
                        isSucces = false;
                        MessageBox.Show("Delete failed");
                    }
                }
                catch (Exception ex)
                {
                    // Show the Exception --> Dubbel ContactId/Name ?
                    MessageBox.Show(ex.Message);
                }
            }
        }
    }
}
ImageHelper - SaveAsImage 方法

最后,我添加了一个 SaveAs 方法。将二进制数据保存回图像文件,保存到用户选择的分配目录。

再次,我们需要知道数据集的哪一行需要保存到文件,因此我们的方法需要一个整数作为参数。

首先,我们将局部变量设置为默认值,这是 C# - .NET 的要求和良好的标准编程实践。

然后,我们通过 SaveDialog 向用户询问新图像的目录位置和文件名。设置了 dialog.Filter 范围,我们允许,并相应执行检查。

二进制数据使用 dBHelper 从数据库中检索,再次使用 Image 类的一个实例。如果 dBHelper.Load 返回“true”值,则执行 FileStream 并处理将二进制写入图像。为了结束此过程,“状态”isSucces 将返回给视图(表单)DisplayImages

public void SaveAsImage(Int32 imageID)
{
    //set variables
    DataRow dataRow = null;
    Image image = null;
    isSucces = false;

    // Displays a SaveFileDialog so the user can save the Image
    SaveFileDialog dlg = new SaveFileDialog();
    dlg.InitialDirectory = @"C:\\";
    dlg.Title = "Save Image File";
    //1
    dlg.Filter = "Tag Image File Format (*.tiff)|*.tiff";
    //2
    dlg.Filter += "|Graphics Interchange Format (*.gif)|*.gif";
    //3
    dlg.Filter += "|Portable Network Graphic Format (*.png)|*.png";
    //4
    dlg.Filter += "|Joint Photographic Experts Group Format (*.jpg)|*.jpg";
    //5
    dlg.Filter += "|Joint Photographic Experts Group Format (*.jpeg)|*.jpeg";
    //6
    dlg.Filter += "|Bitmap Image File Format (*.bmp)|*.bmp";
    //7
    dlg.Filter += "|Nikon Electronic Format (*.nef)|*.nef";
    dlg.ShowDialog();

    // If the file name is not an empty string open it for saving.
    if (dlg.FileName != "")
    {
        Cursor.Current = Cursors.WaitCursor;
        //making shore only one of the 7 is being used.
        //if not added the default extention to the filename
        string defaultExt = ".png";
        int pos = -1;
        string[] ext = new string[7] {".tiff", ".gif", ".png",
                                      ".jpg", ".jpeg", ".bmp", ".nef"};
        string extFound = string.Empty;
        string filename = dlg.FileName.Trim();
        for (int i = 0; i < ext.Length; i++)
        {
            pos = filename.IndexOf(ext[i], pos + 1);
            if (pos > -1)
            {
                extFound = ext[i];
                break;
            }
        }
        if (extFound == string.Empty) filename = filename + defaultExt;

        // Determin the ConnectionString
        string connectionString = dBFunctions.ConnectionStringSQLite;

        // Determin the DataAdapter = CommandText + Connection
        string commandText = "SELECT * FROM ImageStore WHERE image_id=" + imageID;

        // Make a new object
        helper = new dBHelper(connectionString);

        // Load the data
        if (helper.Load(commandText, "") == true)
        {
            // Show the data in the datagridview
            dataRow = helper.DataSet.Tables[0].Rows[0];
            image = new Image(
                              (string)dataRow["imageFileName"],
                              (byte[])dataRow["imageBlob"],
                              (long)dataRow["imageFileSizeBytes"]
                              );

            // Saves the Image via a FileStream created by the OpenFile method.
            using (FileStream stream = new FileStream(filename, FileMode.Create))
            {
                BinaryWriter bw = new BinaryWriter(stream);
                bw.Write(image.ImageData);
                isSucces = true;
            }
        }
        Cursor.Current = Cursors.Default;
    }

    if (isSucces)
    {
        MessageBox.Show("Save succesfull");
    }
    else
    {
        MessageBox.Show("Save failed");
    }
}

视图 - (表单) DisplayImages

该表单包含一个 splitpanel,一侧(左侧)有一个图片框,另一侧(右侧)有一个 DataGridView 标签。它还包含一个链接到 DataGridViewContextMenuStripContextMenuStrip 包含此小项目的三个命令:NewDeleteSaveAs

表单本身包含一些额外的处理命令、从数据库检索数据和填充 DataGridView 的方法。填充 DataGridView 只在应用程序启动时以及每次命令成功执行后执行。

DisplayImages_2.png

备注

我知道 ImageHelper 类及其方法需要重构,但我特意保留了这种方式,以便它包含所有功能;这使得它更容易阅读。

我讨厌阅读关于代码的文章,它们到处都是,跳进跳出方法才能理解。

关注点

那些读过我上一篇文章 C# & SQLite 的人会认出处理所有数据库事务的两个数据库类。

© . All rights reserved.