如何验证/检查数据库中是否已存在图像?

时间:2018-09-15 13:52:51

标签: c# sql-server winforms

我使用显示的代码来尝试验证我的图像。
不幸的是,我没有这样做,这是我第一次进行图像验证。

我的逻辑有什么问题吗?我在这里忘记了什么吗?做这些的正确方法是什么。

注意:
我将图像保存为图像而不是路径,并且数据库中的数据类型为Varbinary(MAX)

  

System.IO.FileNotFoundException:'找不到文件   'C:\ Users \ Andrea \ source \ repos \ CapstoneSIMS \ CapstoneSIMS \ bin \ Debug \ 72EF99A3668CF13820B113EB2E090C37716C9742'。

(尝试插入图像时出现这些错误)

public partial class ADDProduct : MetroForm
{
    SIMSProduct _view;

    public ADDProduct(SIMSProduct _view)
    {
        InitializeComponent();
        this._view = _view;                  
    }

    DataSet ds = new DataSet();
    DataTable dt = new DataTable();
    byte[] photobyte;

    public string CalculateHash(string filename)
    {
        SHA1CryptoServiceProvider crypt = new SHA1CryptoServiceProvider();
        //MD5CryptoServiceProvider crypt = new MD5CryptoServiceProvider();
        string hash = string.Empty;
        using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
        {
            byte[] checksum = crypt.ComputeHash(fs);
            foreach (byte b in checksum)
                hash += b.ToString("X2");
        }
        return (hash);
    }

    public static bool ImageExists(string filehash)
    {
        bool result = false;
        using (var connection = SQLConnection.GetConnection())
        {
            using (SqlCommand cmd = new SqlCommand("SELECT COUNT(0) FROM employee_product WHERE ImageHash = @ImageHash", connection))
            {
                connection.Open();
                int imagecount = (int)cmd.ExecuteScalar();
                result = imagecount == 0;
                connection.Close();
            }
        }
        return (result);
    }

    private void btn_add_Click(object sender, EventArgs e)
    {
        _view.ID = txt_id.Text;
        filehash = CalculateHash(@"C:\myimagefile.jpg");
        using (var con = SQLConnection.GetConnection())
        {
            if (string.IsNullOrEmpty(cbox_supplier.Text) || string.IsNullOrEmpty(txt_code.Text) || string.IsNullOrEmpty(txt_item.Text) || string.IsNullOrEmpty(txt_quantity.Text) || string.IsNullOrEmpty(txt_cost.Text) || pictureBox1.Image == null )
            {
                CustomNotifcation.Show("Please input the required fields", CustomNotifcation.AlertType.warning);
            }
            else
            {          
                ValidateCode.IsValidCode(txt_code,lbl_code,ds);
                string filehash = CalculateHash(pictureBox1.Tag.ToString());

                if (lbl_code.Visible == true)
                {
                    CustomNotifcation.Show("CODE ALREADY EXIST", CustomNotifcation.AlertType.error);
                    lbl_code.Visible = false;                      
                }
                else if (ImageExists(pictureBox1.Tag.ToString()))
                {
                    MessageBox.Show("image exists");
                    return;
                }
                else
                {
                    using (var select = new SqlCommand("Insert into employee_product (Image, ImageHash, ID, Supplier, Codeitem, Itemdescription, Date, Quantity, Unitcost) Values (@Image, @ID, @Supplier, @Codeitem, @Itemdescription, @Date, @Quantity, @Unitcost)", con))
                    {
                        var ms = new MemoryStream();
                        pictureBox1.Image.Save(ms, pictureBox1.Image.RawFormat);
                        photobyte = ms.GetBuffer();
                        select.Parameters.Add("@Image", SqlDbType.VarBinary).Value = photobyte;
                        select.Parameters.Add("@ImageHash", SqlDbType.VarChar, 50);
                        select.Parameters["@ImageHash"].Value = filehash;
                        select.Parameters.Add("@Supplier", SqlDbType.VarChar).Value = cbox_supplier.Text;
                        select.Parameters.Add("@Codeitem", SqlDbType.VarChar).Value = txt_code.Text.Trim();
                        select.Parameters.Add("@Itemdescription", SqlDbType.VarChar).Value = txt_item.Text.Trim();
                        select.Parameters.Add("@Date", SqlDbType.VarChar).Value = date;
                        select.Parameters.Add("@Quantity", SqlDbType.Int).Value = txt_quantity.Text.Trim();
                        select.Parameters.Add("@Unitcost", SqlDbType.Int).Value = txt_cost.Text.Trim();
                        select.ExecuteNonQuery();
                        CustomMessage.Show("Message: Item successfully added!",CustomMessage.Messagetype.Success);
                        pictureBox1.Image = null;
                        cbox_supplier.Items.Clear();
                        txt_code.Clear();
                        txt_item.Clear();
                        txt_quantity.Clear();
                        txt_cost.Clear();
                        _view.btn_update.Enabled = false;
                        _view.AddingProduct();
                        this.Close();
                    }
                }
            }
        }
    }

    private void pictureBox1_Click(object sender, EventArgs e)
    {
         var opnfd    = new OpenFileDialog();
        opnfd.Filter            = "Image Files (*.jpg;*.jpeg;.*.png;)|*.jpg;*.jpeg;.*.png;";
        opnfd.Title             = "Select Item";

        if (opnfd.ShowDialog() == DialogResult.OK)
        {
            pictureBox1.SizeMode    = PictureBoxSizeMode.StretchImage;
            pictureBox1.Image       = Image.FromFile(opnfd.FileName);
            CalculateHash(opnfd.FileName);
        }
    }
}


My DATABASE

4 个答案:

答案 0 :(得分:2)

ExecuteNonQuery()用于INSERT,UPDATE,DELETE和DDL语句,即命令不返回行。您应该使用ExecuteReader()并使用返回的读取器来读取返回的数据,而不要使用SqlDataAdapter。或者,甚至更好的是使用类似

的语句
SELECT COUNT(*) FROM employee_product WHERE Image = @Image

然后使用ExecuteScalar()获取计数:

using (var con = SQLConnection.GetConnection())
using (var cmd = new SqlCommand(sql, con)) {
    cmd.Parameters.Add("@Image", SqlDbType.VarBinary).Value = PhotoByte;
    con.Open();
    int count = (int)cmd.ExecuteScalar();
    if (count > 0 ) {
        ...
    }
}

ExecuteScalar()返回结果集第一行的第一列。

但是将散列码与图像存储在一起并比较散列而不是比较整个图像数据可能会更有效。甚至可以为哈希码建立索引,以加快访问速度。

答案 1 :(得分:2)

您可以计算图像的MD5 / SHA1并将其存储在表中的单独列中,然后在检查图像是否存在时,请计算当前图像的MD5 / SHA1,然后检查其是否匹配在数据库中。 MD5 / SHA1的最大长度约为50个字符,并且每个图像应该唯一(已观察到MD5冲突,并且我认为SHA1也存在冲突,但是您不太可能在数据库中插入数百万个图像)。

您的表格如下:

ID INT
Image VARBINARY(MAX)
ImageHash VARCHAR(50)

加上您需要的其他任何列。

要为图像计算MD5 / SHA1,您将使用以下方法:

public string CalculateHash(string filename)
{
    SHA1CryptoServiceProvider crypt = new SHA1CryptoServiceProvider();
    //MD5CryptoServiceProvider crypt = new MD5CryptoServiceProvider();
    string hash = string.Empty;
    using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
    {
        byte[] checksum = crypt.ComputeHash(fs);
        foreach (byte b in checksum)
            hash += b.ToString("X2");
    }

    return(hash);
}

以上方法使用SHA1加密计算。如果您想使用MD5(快一点),请注释掉SHA1行,并取消注释MD5行。

Call it with:

string filehash = CalculateHash(@"C:\myimagefile.jpg");

然后,当您要检查是否已插入图像时,可以使用查询:

SELECT COUNT(0) FROM employee_product WHERE ImageHash = @ImageHash

将查询的参数设置为:

cmd.Parameters.Add("@ImageHash", SqlDbType.Varchar, 50);
cmd.Parameters["@ImageHash"].Value = filehash;

然后致电:

int result = (int)cmd.ExecuteScalar();
if (result == 0)
{
    // Insert your image, don't forget to insert the filehash into the ImageHash column or subsequent checks will always fail.
}

这是一种检查图像是否存在的更快方法,因为您只向数据库发送50个字符而不是整个图像来进行检查。

因此,您将创建一个新方法来搜索数据库中图像的存在:

public bool ImageExists(string filehash)
{
    bool result = false;
    using (SqlConnection connection = SQLConnection.GetConnection())
    {
        using (SqlCommand cmd = new SqlCommand("SELECT COUNT(0) FROM employee_product WHERE ImageHash = @ImageHash", connection))
        {
            connection.Open();
            int imagecount = (int)cmd.ExecuteScalar();
            result = imagecount == 0;
            connection.Close();
        }
    }

    return(result);
}

然后在此行之前的AddProduct方法中:

using (var select = new SqlCommand("Insert into employee_product (Image, ID, Supplier, Codeitem, Itemdescription, Date, Quantity, Unitcost) Values (@Image, @ID, @Supplier, @Codeitem, @Itemdescription, @Date, @Quantity, @Unitcost)", con))

您可以插入:

string filehash = CalculateHash(imagefilename);
if (ImageExists(filehash)
{
    MessageBox.Show("Image already exists");
    return;
}

// the rest of your code goes here including adding a parameter to take the ImageHash.

当您从磁盘读取图像文件时(我假设这是从中获取图像的位置),则可以将文件名存储在PictureBox.Tag对象中。然后从PictureBox.Tag中提取该文件名(包括路径),并将其传递给ImageExists:

string filehash = CalculateHash(pictureBox1.Tag.ToString());

要将文件名放在图片框中,请使用:

using(OpenFileDialog ofd = new OpenFileDialog())
{
    if (ofd.ShowDialog() == DialogResult.OK)
    {
        pictureBox1.Image = Image.FromFile(ofd.FileName);
        pictureBox1.Tag = ofd.FileName;
    }
}

或者,当用户加载图像并将其存储在Tag中时,您可以进行哈希计算:

using(OpenFileDialog ofd = new OpenFileDialog())
{
    if (ofd.ShowDialog() == DialogResult.OK)
    {
        pictureBox1.Image = Image.FromFile(ofd.FileName);
        pictureBox1.Tag = CalculateHash(ofd.FileName);
    }
}

然后,当您致电ImageExists时,请使用:

if (ImageExists(pictureBox1.Tag.ToString()))
{
    MessageBox.Show("image exists");
    return;
}

答案 2 :(得分:0)

  • 第一件事是输入VarBinary的长度,因为没有特定长度的VarBinary具有默认长度
  • 第二件事更改[ExecuteNonQuery]并使用[ExecuteReader]或[sqldataAdapter]或[SqlScalar]之类的其他东西

     select.Parameters.Add("@Image", SqlDbType.VarBinary,[Length   VarBinary Column in database ]).Value = PhotoByte;
    

祝你有美好的一天

答案 3 :(得分:0)

using (var con = SQLConnection.GetConnection())
{
    using (var select = new SqlCommand(SELECT COUNT(0) FROM employee_product WHERE Image = @Image, con))
    {
        cmd.Parameters.Add("@Image", SqlDbType.VarBinary).Value = PhotoByte;
        int count = (int)select.ExecuteScalar();
        if (count > 0 ) 
        {
            lbl.Show();
        }
    }
}