簡體   English   中英

如何驗證/檢查數據庫中是否已存在圖像?

[英]How to validate/Check if an Image already exist in a DataBase?

我使用顯示的代碼來嘗試驗證我的圖像。
不幸的是,我沒有這樣做,這是我第一次進行圖像驗證。

我的邏輯有什么問題嗎? 我在這里忘記了什么嗎? 做這些的正確方法是什么。

注意:
我將圖像保存為圖像而不是路徑,並且數據庫中的數據類型為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);
        }
    }
}


我的數據庫

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()返回結果集第一行的第一列。

但是將哈希碼與圖像一起存儲並比較哈希而不是比較整個圖像數據可能會更有效。 甚至可以為哈希碼建立索引,以加快訪問速度。

您可以計算圖像的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;
}
  • 第一件事放了VarBinary的長度,因為沒有特定長度的VarBinary具有默認長度
  • 第二件事更改[ExecuteNonQuery]並使用[ExecuteReader]或[sqldataAdapter]或[SqlScalar]之類的其他東西

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

祝你今天愉快

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM