C# 如何验证/检查数据库中是否已存在图像?
我使用显示的代码尝试验证我的图像。C# 如何验证/检查数据库中是否已存在图像?,c#,sql-server,winforms,C#,Sql Server,Winforms,我使用显示的代码尝试验证我的图像。 不幸的是,我没有做到这一点,这是我第一次对图像进行验证。 我的逻辑有什么错误吗?我忘了什么吗?做这些的正确方法是什么 注意: 我正在将图像保存为图像而不是路径,并且在我的数据库中数据类型是Varbinary(MAX)。 System.IO.FileNotFoundException:'找不到文件 “C:\Users\Andrea\source\repos\CapstoneSIMS\CapstoneSIMS\bin\Debug\72EF99A3668CF1382
不幸的是,我没有做到这一点,这是我第一次对图像进行验证。
我的逻辑有什么错误吗?我忘了什么吗?做这些的正确方法是什么 注意:
我正在将图像保存为图像而不是路径,并且在我的数据库中数据类型是
Varbinary(MAX)
。System.IO.FileNotFoundException:'找不到文件 “C:\Users\Andrea\source\repos\CapstoneSIMS\CapstoneSIMS\bin\Debug\72EF99A3668CF13820B113EB2E090C37716C9742。” (我在尝试插入图像时遇到这些错误)
用于INSERT、UPDATE、DELETE和DDL语句,即不返回行的命令。您应该使用并使用返回的读取器来读取返回的数据,而不是使用
SqlDataAdapter
。或者,更好的是,使用这样的语句
SELECT COUNT(*) FROM employee_product WHERE Image = @Image
然后使用ExecuteScalar()
获取计数:
返回结果集第一行的第一列
但是,将哈希代码与图像一起存储并比较哈希而不是比较整个图像数据可能更有效。散列代码甚至可以被编入索引以便更快地访问。用于INSERT、UPDATE、DELETE和DDL语句,即不返回行的命令。您应该使用并使用返回的读取器来读取返回的数据,而不是使用SqlDataAdapter
。或者,更好的是,使用这样的语句
SELECT COUNT(*) FROM employee_product WHERE Image = @Image
然后使用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());
要将文件名放入picturebox,请使用:
using(OpenFileDialog ofd = new OpenFileDialog())
{
if (ofd.ShowDialog() == DialogResult.OK)
{
pictureBox1.Image = Image.FromFile(ofd.FileName);
pictureBox1.Tag = ofd.FileName;
}
}
或者,您可以在用户加载图像时执行哈希计算,并将其存储在标记中:
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;
}
您可以计算映像的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());
要将文件名放入picturebox,请使用:
using(OpenFileDialog ofd = new OpenFileDialog())
{
if (ofd.ShowDialog() == DialogResult.OK)
{
pictureBox1.Image = Image.FromFile(ofd.FileName);
pictureBox1.Tag = ofd.FileName;
}
}
或者,您可以在用户加载图像时执行哈希计算,并将其存储在标记中:
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具有默认长度
- 第二件事是更改[ExecuteOnQuery]并使用其他东西,如[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();
}
}
}
select.Parameters.Add("@Image", SqlDbType.VarBinary,[Length VarBinary Column in database ]).Value = PhotoByte;