Võ Văn Hải's blog

Chỉ có một điều tuyệt đối đó là mọi thứ đều tương đối…

Lưu hình ảnh vào database

Trong bài viết này tôi sẽ hướng dẫn bạn cách chèn hình ảnh trực tiếp vào database. Cách này tuy làm cho database lớn/nặng nhưng nó cũng giải quyết rất nhiều vấn đề trong quá trình lập trình.
Ở đây, csdl tôi sử dụng là ms Access và MS SQLserver.
Cách 1: Database là Access
1. Bạn tạo 1 file access có tên TestDB.mdb nằm trong thư mục bin\debug của ứng dụng(chỗ khác cũng không sao, tùy).Tạo 1 bảng có tên tblSinhvien có cấu trúc như sau:

Tên field Kiểu dữ liệu
MSSV Text(15)
hinhAnh OLE Object

2. Tạo 1 Windows Form Application  Project có tên Store_Retrieve_Image_From_DB.

3. Tạo lớp có tên ConnectDB.cs với nội dung sau:

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.OleDb;namespace Store_Retrieve_Image_From_DB
{
public class ConnectDB
{
private OleDbConnection con;
private DataSet ds;
private OleDbDataAdapter daSV;
/// <summary>
/// Phương thức constructor khởi tạo kết nối đến database
/// </summary>
public ConnectDB()
{
try
{
con = new OleDbConnection();
con.ConnectionString = “Provider=microsoft.jet.OLEDB.4.0;Data Source=”+
System.Windows.Forms.Application.StartupPath+”\\TestDB.mdb”;
con.Open();
}
catch (Exception)
{
throw;
}
}
/// <summary>
/// Lấp về tất cả các mẫu tin trong bảng tblSinhvien
/// </summary>
/// <returns></returns>
public DataSet GetTable()
{
ds = new DataSet();
daSV = new OleDbDataAdapter(“select * from tblSinhvien”, con);
daSV.Fill(ds, “tblSinhvien”);
return ds;
}
/// <summary>
/// Cập nhật các thay đổi của người dùng
/// </summary>
public void UpdateSV()
{
try
{
OleDbCommandBuilder bd = new OleDbCommandBuilder(daSV);
daSV.Update(ds, “tblSinhvien”);
}
catch (Exception)
{

throw;
}
}
}
}

Lớp này dùng để đọc dữ liệu từ database cũng như cập nhật dữ liệu xuống database.

3. Thiết kế MainForm như hình
dbimage_cs_01.png
4. Code cho Form:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Windows.Forms;namespace Store_Retrieve_Image_From_DB
{
public partial class MainForm : Form
{
private ConnectDB conDB;
private DataSet ds = new DataSet();
private BindingSource bs;
private DataTable dtSV;

public MainForm()
{
InitializeComponent();

}

private void MainForm_Load(object sender, EventArgs e)
{
try
{
conDB = new ConnectDB();
ds = conDB.GetTable();
dtSV = ds.Tables[“tblSinhvien”];
bs = new BindingSource(ds, “tblSinhvien”);
bs.CurrentItemChanged += new EventHandler(bs_CurrentItemChanged);
dataGridView1.DataSource = bs;
bindingNavigator1.BindingSource = bs;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
/// <summary>
/// Sự kiện xảy ra khi binding source có sự thay đổi do người
/// dùng chọn các dòng trên lưới hặc nhấn các nút di chuyển.
/// </summary>
/// <param name=”sender”></param>
/// <param name=”e”></param>
void bs_CurrentItemChanged(object sender, EventArgs e)
{
DataRowView row = (DataRowView)bs.Current;
try
{
Byte[] i = (byte[])row[“hinhAnh”];
MemoryStream stmBLOBData = new MemoryStream(i);
picHinhAnh.Image = Image.FromStream(stmBLOBData);
}
catch (Exception ex)
{
picHinhAnh.Image = null;
MessageBox.Show(ex.ToString());
}
}

private void btnLuu_Click(object sender, EventArgs e)
{
try
{
DataRow dr = dtSV.NewRow();
dr[“MSSV”] = txtMSSV.Text;
if (picHinhAnh.Image != null)
{
MemoryStream ms = new MemoryStream();
picHinhAnh.Image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);

Byte[] bytBLOBData = new Byte[ms.Length];
ms.Position = 0;
ms.Read(bytBLOBData, 0, Convert.ToInt32(ms.Length));
dr[“hinhAnh”] = bytBLOBData;
dtSV.Rows.Add(dr);

conDB.UpdateSV();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}

private void btnLoadHinh_Click(object sender, EventArgs e)
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.Filter = “JPG Files(*.JPG)|*.JPG|GIF Files(*.GIF)|*.GIF”;
if (dlg.ShowDialog(this) == DialogResult.OK)
{
picHinhAnh.Image = Image.FromFile(dlg.FileName);
}
}
}
}

Chú ý:

Để đọc dữ liệu hình ảnh ra ta dùng 1 mảng Byte để chứa giá trị của field hình ảnh. Sau đó muốn hiển thị nó lên PictureBox ta phải dùng MemoryStream để đưa ra:

Byte[] i = (byte[])row["hinhAnh"];
MemoryStream stmBLOBData = new MemoryStream(i);
picHinhAnh.Image = Image.FromStream(stmBLOBData);

Để cập nhật dữ liệu vào db, ta phải lấy ảnh từ  PictureBox vào 1 MemoryStream:

MemoryStream ms = new MemoryStream();
picHinhAnh.Image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);

Rồi sau đó mới chuyển nó thành mảng Byte rồi cung cấp cho 1 datarow để update xuống database.

Byte[] bytBLOBData = new Byte[ms.Length];
ms.Position = 0;
ms.Read(bytBLOBData, 0, Convert.ToInt32(ms.Length));
dr["hinhAnh"] = bytBLOBData;
dtSV.Rows.Add(dr);

Chạy ứng dụng, kết quả như hình sau:
dbimage_cs_02.png

Cách 2: Database là Microsoft SQL Server

1. Tạo database có tên: TestImageDB với 1 bảng có tên tblImages và có cấu trúc như hình sau:
dbimage_cs_03.png
2. Tạo stored project có tên InsertImage với sql script như sau:

CREATE PROCEDURE InsertImage
@filename nvarchar(250),
@blobdata image
AS
insert into tblImages values(
@filename, @blobdata
)

3. Tạo Windows Form Application Project có tên AnotherWay.

4. Tạo lớp ConnectDB.cs có nội dung như sau:

using System;
using System.Collections.Generic;
using System.IO;
using System.Data;
using System.Data.SqlClient;

namespace AnotherWay
{
class ConnectDB
{
private SqlConnection conn;
private string connectionString = “Server=.;UID=sa;PWD=;Initial Catalog=TestImageDB”;

public ConnectDB()
{
conn = new SqlConnection(connectionString);
}

public void StorePicture(string filename)
{
byte[] imageData = null;
// Read the file into a byte array
using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
imageData = new Byte[fs.Length];
fs.Read(imageData, 0, (int)fs.Length);
}
using (SqlConnection conn = new SqlConnection(connectionString))
{
SqlCommand cmd = new SqlCommand(“InsertImage”, conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue(“@filename”, filename);
cmd.Parameters[“@filename”].Direction = ParameterDirection.Input;
cmd.Parameters.Add(“@blobdata”, SqlDbType.Image);
cmd.Parameters[“@blobdata”].Direction = ParameterDirection.Input;
// Store the byte array within the image field
cmd.Parameters[“@blobdata”].Value = imageData;
conn.Open();
cmd.ExecuteNonQuery();
}
}

public byte[] RetrieveImage()
{
byte[] imageData = null;
conn.Open();
SqlCommand cmd = new SqlCommand(“select blobdata from tblImages”, conn);
// Assume previously established command and connection
// The command SELECTs the IMAGE column from the table

using (SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
{
reader.Read();
// Get size of image data – pass null as the byte array parameter
long bytesize = reader.GetBytes(0, 0, null, 0, 0);
// Allocate byte array to hold image data
imageData = new byte[bytesize];
long bytesread = 0;
int curpos = 0;
int chunkSize = 1;
while (bytesread < bytesize)
{
// chunkSize is an arbitrary application defined value
bytesread += reader.GetBytes(0, curpos, imageData, curpos, chunkSize);
curpos += chunkSize;
}
}
conn.Close();
// byte array ‘imageData’ now contains BLOB from database
return imageData;
}
}
}

5. Thiết kế Form như hình
dbimage_cs_04.png

6. Code cho Form:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Windows.Forms;

namespace AnotherWay
{
public partial class Form1 : Form
{
private ConnectDB conDB;
public Form1()
{
InitializeComponent();
conDB = new ConnectDB();
}

private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.Filter = “JPG Files(*.JPG)|*.JPG|GIF Files(*.GIF)|*.GIF”;
if (dlg.ShowDialog(this) == DialogResult.OK)
{
conDB.StorePicture(dlg.FileName);
}
}

private void button2_Click(object sender, EventArgs e)
{
byte[] img = conDB.RetrieveImage();
MemoryStream str = new MemoryStream(img);
pictureBox1.Image = Image.FromStream(str);
}
}
}

7. Thực thi

Trước hết nhấn nút Lưu, sau đó muốn xem lại mẫu tin đã lưu, nhấn nút load.
dbimage_cs_05.png

Chúc thành công!

36 Responses to “Lưu hình ảnh vào database”

  1. bini said

    Có thể cung cấp code của việc ứng dụng lưu ảnh vào cở sở dữ liệu nhnwg khi lấy ảnh ra ta nạp vào một ảnh mới và so sánh nó có giồng với ảnh cũ trong cở sở dữ liệu hay ko,hay nói cách khác là một dạng tìm kiếm ảnh vậy

  2. Bảo Trung said

    Thưa thầy, vấn đề thầy nói ở bài này đúng là vấn đề em cần. Nhưng khổ 1 nỗi là em không thể đưa hình trực tiếp vào DB được vì yêu cầu dung lượng DB phải bé thôi, thế nên em trong cột Images của DB em chỉ điền Path vào. Bây giờ làm thế nào để load động được lên picture box đây hả thầy. Vấn đề là không được dùng đường dẫn tuyệt đối được ạh. Thầy gỡ giúp em với được không ạh. Cám ơn thầy nhiều.

  3. Bao Trung said

    Sao thay ko tra loi thay oi

  4. vovanhai said

    cái này bạn tự tìm hiểu nhé. Tôi e rằng tôi k có thời gian! Sorry.

  5. vovanhai said

    Thì copy image vào thư mục chứa file exe của ứng dụng rồi dùng Application.getStartupPath().

  6. bao long said

    <%–
    using System;
    using System.Collections;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Web;
    using System.Web.SessionState;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.HtmlControls;
    using System.IO;

    namespace UploadFile
    {
    ///
    /// Summary description for WebForm1.
    ///
    public class WebForm1 : System.Web.UI.Page
    {
    protected System.Web.UI.WebControls.Button cmdUpload;
    protected System.Web.UI.WebControls.Label lblInfo;
    protected System.Web.UI.HtmlControls.HtmlInputFile FileInput;

    private void Page_Load(object sender, System.EventArgs e)
    {
    // Only accept image types.
    FileInput.Accept = “image/*”;
    }

    #region Web Form Designer generated code
    override protected void OnInit(EventArgs e)
    {
    //
    // CODEGEN: This call is required by the ASP.NET Web Form Designer.
    //
    InitializeComponent();
    base.OnInit(e);
    }

    ///
    /// Required method for Designer support – do not modify
    /// the contents of this method with the code editor.
    ///
    private void InitializeComponent()
    {
    this.cmdUpload.Click += new System.EventHandler(this.cmdUpload_Click);
    this.Load += new System.EventHandler(this.Page_Load);

    }
    #endregion

    private void cmdUpload_Click(object sender, System.EventArgs e)
    {
    if (FileInput.PostedFile.FileName == “”)
    {
    lblInfo.Text = “No file specified.”;
    }
    else
    {
    try
    {
    string serverFileName = Path.GetFileName(FileInput.PostedFile.FileName);
    //FileInput.PostedFile.SaveAs(@”c:\” + serverFileName);
    FileInput.PostedFile.SaveAs(MapPath(“.”) + serverFileName);
    lblInfo.Text = “File ” + serverFileName;
    lblInfo.Text += ” uploaded successfully.”;
    }
    catch (Exception err)
    {
    lblInfo.Text = err.Message;
    }
    }

    }
    }
    }

    –%>

  7. bao long said

    Bạn xem thử nhé!

  8. bao long said

    Nếu bạn cảm thấy chưa chi tiết thì bạn có thể xem tại đây nhé!
    http://vaolamgi.com/diendan/forum_posts.asp?TID=60

  9. Cuong Nguyen said

    Em đã làm theo hướng dẫn của thầy. Dịch không có lỗi. Nhưng khi chạy chương trình có thông báo lỗi sau, dù file ảnh <30KB:
    System.Data.SqlClient.SqlException: String or binary data would be truncated.
    Trước đó,em có làm một ví dụ nhỏ về lưu trữ ảnh và cũng xuất hiện thông báo trên.
    Thầy và các bạn có biết cách khắc phục chỉ giùm em nhé.

  10. bạn thử dùng đoạn này xem được ko nhé Cuong Nghuen

    string getimg()
    {

    try
    {
    //Thumbnail th = new Thumbnail();
    //RootPath = CSContext.SRootDir + "\\images\\adv";
    RootPath = HttpContext.Current.Request.PhysicalApplicationPath + "\\resource\\logonews";
    Log.info("RootPath:" + RootPath);
    //string spath = (string)Session["PATHTEMP"];
    if (imgAdv.PostedFile != null && imgAdv.PostedFile.FileName.Length != 0) //Checking for valid file
    {
    // Since the PostedFile.FileNameFileName gives the entire path we use Substring function to rip of the filename alone.
    string StrFileNameType = imgAdv.PostedFile.FileName.Substring(imgAdv.PostedFile.FileName.LastIndexOf(".") + 1);
    StrFileName = DateTime.Now.Ticks.ToString() + "." + StrFileNameType;
    string StrFileType = imgAdv.PostedFile.ContentType;
    int IntFileSize = imgAdv.PostedFile.ContentLength;
    if (IntFileSize 3145728)
    {
    return StrFileName = txtmn.Text;
    } //error.Text = "upload failed";
    else
    {
    imgAdv.PostedFile.SaveAs(RootPath + "\\" + StrFileName);
    //th.GenerateThumbnail(StrFileName, "~/resource/logonews/", "m" + StrFileName, 101);

    return StrFileName;
    }
    }
    else
    {
    return StrFileName = txtmn.Text;
    }

    }
    catch (Exception ex)
    {
    Log.info("KHONG LAY THU MUC NAY " + ex.Message);
    return StrFileName;
    }
    }

    chúc bạn thành công

  11. tinhspt said

    thầy có thể demo một bài bằng java được không thầy, chân thành cảm ơn thầy

  12. hoadienanh said

    e làm hoài lấy dữ liệu từ datetimepicker mãi mà toàn lỗi.

    //createDate lấy từ VO class (return và get)
    VO.createDate = Convert.ToDateTime(dtCrDate.Text.ToString());

    hoặc

    VO.createDate = dtCrDate.Value;

    trong CDQL e khai báo kiểu dateitme bình thường
    Mong thầy chỉ bảo!

  13. vovanhai said

    Em coi lại định dạng ngày tháng của em sao đã.

  14. Nguyen Duc Tung said

    Cảm ơn thầy nhiều.!

  15. Nguyen Van Sang said

    Đó là ngôn ngữ C#, còn lở là ngôn ngữ Java thì phải làm sao, thầy ơi hướng dẫn cho em với. Và hình như là Java không làm được chuyện này phải không thầy, em tìm khắp trên mạng chi toàn cho ngôn ngữ C# thôi chớ Java thì không thấy cái nào hết.

  16. Võ Văn Hải said

    Xem ở đây: Ví dụ

  17. Thanhle said

    Thầy cho em hỏi là muốn upload video thì như thế nào? Có giống với hình ảnh ko?
    Nếu ko anh cho em cơ chế mà người ta hay dùng như các trang facebook hay zing chẳng hạn.
    Em hỏi thêm câu nữa là cách lưu hình vào database này có phải là cách làm phổ biến không? Thông thường các website lưu hình ảnh làm theo cách nào !
    Thanks thầy !

  18. Võ Văn Hải said

    Về cơ bản thì giống nhau. Trong Facebook hay Zing hay các trang web, hình ảnh sẽ không được lưu vào DB, thay vào đó người ta lưu image path rồi load.

  19. Thanhle said

    Cám ơn thầy nhiều ạ !

  20. Phan Thanh Vũ said

    cảm ơn thầy

  21. cho em hỏi cái panel để load hình lên khi click vào datagridview là gì vậy.

  22. Võ Văn Hải said

    là picturebox.

  23. hi hi said

    String or binary data would be truncated.
    The statement has been terminated.

    nó báo lỗi như vậy giải quyết sao ạ?

  24. Võ Văn Hải said

    Chiều dài(độ lớn) của chuỗi hoặc dữ liệu dạng nhị phân bị cắt bớt(trường dữ liệu nhỏ quá, lưu không đủ).

  25. bin said

    cảm ơn anh nhiều. ^^

  26. xemnhadat said

    Cảm ơn anh rất nhiều, trước em nghĩ là chỉ nên lưu đường dẫn ảnh vào database mà thôi.

  27. Huỳnh Văn Thịnh said

    Thưa thầy, em chạy nó báo

    The name ‘stmBLOBData’ does not exist in the current context

    The type or namespace name ‘MemoryStream’ could not be found (are you missing a using directive or an assembly reference?)

    là thế nào vậy thầy. Mong thầy giúp em.

  28. Võ Văn Hải said

    “The name ‘stmBLOBData’ does not exist in the current context
    The type or namespace name ‘MemoryStream’ could not be found (are you missing a using directive or an assembly reference?)”

    Em có using thư viện System.IO chưa vậy? Thêm nữa, phiên bản thầy sử dụng là VS2008

  29. STYE4U said

    Sao lại lưu ảnh vào DB, tiện cho lập trình nhưng load rất nặng, nhỡ khi server có vấn đề mà backup chưa kịp thì tiêu file luôn. Nếu website nhỏ thì lưu hình ở webhos, nếu site lớn thì sử dụng dịch vụ lưu ảnh trugn gian hoặc thuê thêm host tạo subdomain mà chứa.

  30. Dương Tấn Biên said

    sao ko ai pót demo chuong trinh lên vậy

  31. do cong thang said

    thay oi Thay Code Load Image Len DataGridview Su dung Linq Va SQL 2005 ko thay neu co thay cho em xin hay ban demo thi cang tot <>

  32. ds said

    thầy ơi thầy làm thêm nút sửa và nút xóa đi. em không biết làm chác nào để có thể thay được cái ảnh khác

  33. Nguyễn Phạm Diễm Hằng said

    cảm ơn thầy nhìu ạ…

  34. caovantuan said

    Em chào thầy! Thầy ơi cho em hỏi với em muốn lưu đường dẫn hình xuống database sau đó em chỉ load lên vậy phải làm thế nào ah, em định lưu đường dẫn hình sử dụng LinQ và WCF mà 2 cái đó em chưa có rành lắm. Em mong thầy cố gắng chỉ giúp em với ạ. Em cám ơn Thầy nhiều nhiều

  35. Cho em hỏi với ạ ,em lại muốn gán ảnh động vào node trong cây treeview thì em phải làm thể nào ạ ,em lưu đc ảnh vào trong CSDL rồi ạ , có phải thông qua Imagelist ko ạ , em ko gán đc trực tiếp kiểu picturebox bởi nó ko có thuộc tính .Image . Vậy fai lsao ạ .

  36. thanh-kttv said

    Bây h em muốn hiển thị ảnh đã được lưu vào trong CSDL đó lên các node trong cây treeview thì em fai làm tnao ạ

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.