ผู้เขียน หัวข้อ: [VB.Net] การโหลดและบันทึกชื่อไฟล์รูปภาพเข้าสู่ฐานข้อมูล MS Access 2003  (อ่าน 314 ครั้ง)

ออฟไลน์ ทองก้อน ทับทิมกรอบ

  • Administrator
  • *****
  • กระทู้: 245
  • เพศ: ชาย
  • Webmaster G2GNet
[VB.Net] การโหลดและบันทึกชื่อไฟล์รูปภาพเข้าสู่ฐานข้อมูล MS Access 2003

จากตอนที่แล้วผมก็ได้อธิบายขั้นตอนการออกแบบโปรแกรมไปบางส่วนแล้ว ก็คือออกแบบตารางข้อมูล จากนั้นใส่ข้อมูลทดสอบก่อน เพื่อนำมาแสดงผลให้ได้ แล้วค่อยไปต่อ ...

โค้ดนี้ทำอะไร???
เป็นการบันทึกเฉพาะชื่อไฟล์ลงฐานข้อมูลเท่านั้น ไม่เอา Path มาด้วยน่ะครับ เพราะเราจะกำหนด Path เอาเอง และยังสามารถ Copy รูปภาพลงตำแหน่งหรือโฟลเดอร์ที่เราต้องการได้ ทำให้รวบรวมภาพต่างๆให้อยู่ในที่เดียวกัน รวมไปถึงหากภาพเดิมนั้นไม่ได้ใช้งาน จะเกิดการแทนที่ด้วยภาพใหม่ ก็จะทำการ Delete ลบภาพเก่าออกไปได้อีกต่างหาก จะได้ไม่รกรุงรังโฟลเดอร์ ... โค้ดนี้เป็นการนำทางให้มือใหม่สาย VB.NET ได้เข้าใจ กระบวนการของฐานข้อมูลในความสัมพันธ์แบบ One To One ด้วย ลองศึกษากันดูให้ดีๆน่ะครับ ...

เทคนิค: ผมไม่ใช้ Image.FromFile เพราะตอนลบไฟล์ ภาพจะถูกล็อคทำให้ลบออกไม่ได้น่ะครับ ทางแก้โดยการใช้ Stream แทน



โค้ดส่วนโมดูลการเชื่อมต่อไฟล์ฐานข้อมูล MS Access 2003 และฟังค์ชั่นการกำหนดตำแหน่ง
โค๊ด: [Select]
Imports System.Data.OleDb

Module modDataBase
    Public ConnDB As New OleDb.OleDbConnection
    Public Comm As OleDbCommand
    Public DR As OleDbDataReader
    Public DAP1 As New OleDb.OleDbDataAdapter()
    Public DAS1 As New DataSet()
    Public strSQL As String

    ' / ------------------------------------------------------------------
    Public Sub ConnectDataBase()
        Dim strPath As String = MyPath(Application.StartupPath)
        Dim strConn As String = _
            " Provider = Microsoft.Jet.OLEDB.4.0; " & _
            " Data Source = " & strPath & "Data\MyDB.mdb;"

        ConnDB = New OleDb.OleDbConnection(strConn)
    End Sub

    ' / ------------------------------------------------------------------
    ' / Get my project path
    ' / Ex.
    ' / AppPath = C:\My Project\bin\debug
    ' / Replace "\bin\debug" with "\"
    ' / Return : C:\My Project\
    Function MyPath(AppPath As String) As String
        AppPath = AppPath.ToLower()
        MyPath = AppPath.Replace("\bin\debug", "\")
    End Function

End Module

โค้ดส่วนฟอร์มหลัก

โค๊ด: [Select]
' / -----------------------------------------------------------------------------
' / Developer : Mr.Surapon Yodsanga (Thongkorn Tubtimkrob)
' / eMail : thongkorn@hotmail.com
' / URL: http://www.g2gnet.com (Khon Kaen - Thailand)
' / Facebook: www.facebook.com/g2gnet
' / Purpose: Load/Save images filename from/to MS Access.
' / Microsoft Visual Basic .NET (2010) and MS Access 2003
' / -----------------------------------------------------------------------------

Imports System.Data.OleDb
Imports System.Drawing
Imports System.IO

Public Class frmMain
    Dim PK As Long
    Dim newFileName As String
    Dim oldFileName As String
    Dim streamPic As Stream

    ' / -----------------------------------------------------------------------------
    Private Sub frmSaveImgPath_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        Me.CenterToScreen()
        lblMessage.Text = ""
        ' / เชื่อมต่อไฟล์ฐานข้อมูล
        Call ConnectDataBase()
        ' / โหลดข้อมูลตัวอย่างจากตารางลูกค้า
        Call LoadDataCustomer()
        'dgvCustomer.Focus()
    End Sub

    ' / -----------------------------------------------------------------------------
    Sub LoadDataCustomer()
        strSQL = _
            " SELECT Customer.CustomerPK, Customer.CustomerID, Customer.FirstName, Customer.LastName, Customer.Picture " & _
            " FROM Customer " & _
            " ORDER BY CustomerPK "

        ' Put recordset into DataAdapter
        DAP1 = New OleDb.OleDbDataAdapter(strSQL, ConnDB)
        DAP1.Fill(DAS1, "dbCustomers")
        dgvCustomer.DataSource = DAS1.Tables("dbCustomers")
        With dgvCustomer
            .RowHeadersVisible = False
            .AllowUserToAddRows = False
            .AllowUserToDeleteRows = False
            .AllowUserToResizeRows = False
            .MultiSelect = False
            .SelectionMode = DataGridViewSelectionMode.FullRowSelect
            .ReadOnly = True
            .TabStop = False
            ' ----------------- Bound Data ------------------
            .DataSource = DAS1.Tables("dbCustomers")
            ' Adjust Column width
            .Columns(1).Width = dgvCustomer.Width \ 4 - 1
            .Columns(2).Width = dgvCustomer.Width \ 4 - 2
            .Columns(3).Width = dgvCustomer.Width \ 4 - 2
            .Columns(4).Width = dgvCustomer.Width \ 4
            ' Hidden column index 0 ... It's Primary Key
            .Columns("CustomerPK").Visible = False
            .Columns("CustomerID").HeaderText = "Customer ID"
            .Columns("FirstName").HeaderText = "First Name"
            .Columns("LastName").HeaderText = "Last Name"
            .Columns("Picture").HeaderText = "Picture"
        End With
        DAS1.Dispose()
        DAP1.Dispose()
    End Sub

    ' / -----------------------------------------------------------------------------
    ' / เหตุการณ์คลิ๊กเมาส์ ก็แสดงรูปภาพออกมาตามค่า Primary key ที่ถูกซ่อนเอาไว้ในหลักแรกของ DataGridView
    Private Sub dgvCustomer_Click(sender As Object, e As System.EventArgs) Handles dgvCustomer.Click
        If dgvCustomer.RowCount = 0 Then Exit Sub

        ' Get value from column 0 for which it's Primary Key and to edit data next form.
        PK = dgvCustomer.Item(0, dgvCustomer.CurrentRow.Index).Value
        ShowPicture(PK)
    End Sub

    Private Sub dgvCustomer_KeyDown(sender As Object, e As System.Windows.Forms.KeyEventArgs) Handles dgvCustomer.KeyDown
        If dgvCustomer.RowCount = 0 Then Exit Sub
        PK = dgvCustomer.Item(0, dgvCustomer.CurrentRow.Index).Value
        If e.KeyCode = Keys.Enter Then
            ' ไม่ให้ Selection เลื่อนแถว
            e.Handled = True
            ShowPicture(PK)
        End If
    End Sub

    ' / -----------------------------------------------------------------------------
    Sub ShowPicture(PK As Long)
        ' / ตัวอย่างในการเลือกรายการข้อมูลมาแสดงผล ใช้ CustomerID
        strSQL = "SELECT CustomerPK, Picture FROM Customer " & _
            " WHERE CustomerPK = " & PK
        Comm = New OleDbCommand(strSQL, ConnDB)

        ConnDB.Open()
        DR = Comm.ExecuteReader
        ' Get owner path ex. C:\My Project\ ... (See modDataBase.vb)
        Dim strPath As String = MyPath(Application.StartupPath) & "Images\"
        Dim imgDB As Image

        While DR.Read()
            ' รับค่าชื่อไฟล์ภาพมาจากฐานข้อมูล
            If DR.Item("Picture").ToString <> "" Then
                ' ตรวจสอบว่ามีไฟล์ภาพอยู่ตรงตามตำแหน่งที่กำหนดหรือไม่
                If System.IO.File.Exists(strPath & DR.Item("Picture").ToString) Then
                    ' ไม่ใช้ Image.FromFile เพราะตอนลบไฟล์ภาพจะถูกล็อคทำให้ลบออกไม่ได้
                    ' The file is closed after the image is loaded, so you can delete the file if you need to
                    streamPic = File.OpenRead(strPath & DR.Item("Picture").ToString)
                    imgDB = Image.FromStream(streamPic)
                    picData.Image = imgDB
                    ' เก็บชื่อไฟล์ภาพเดิมไว้ก่อน หากมีการบันทึกก็จะได้ลบออกไป
                    oldFileName = strPath & DR.Item("Picture").ToString
                    newFileName = oldFileName
                    ' แสดงชื่อไฟล์ให้เห็น
                    lblMessage.Text = strPath & DR.Item("Picture").ToString
                Else
                    ' ไม่เจอภาพที่รับมาจากฐานข้อมูล
                    streamPic = File.OpenRead(strPath & "NoImage.png")
                    imgDB = Image.FromStream(streamPic)
                    picData.Image = imgDB
                    lblMessage.Text = "ไม่พบไฟล์ภาพตามที่กำหนดไว้."
                    ' เก็บค่าชื่อไฟล์ภาพเป็นค่าว่าง
                    newFileName = ""
                End If
                ' Is null
            Else
                streamPic = File.OpenRead(strPath & "NoImage.jpg")
                imgDB = Image.FromStream(streamPic)
                picData.Image = imgDB
                lblMessage.Text = "No data."
                ' No image is null
                newFileName = ""
            End If
        End While
        streamPic.Dispose()
        DR.Close()
        Comm.Dispose()
        ConnDB.Close()
    End Sub

    ' / -----------------------------------------------------------------------------
    Private Sub btnBrowse_Click(sender As System.Object, e As System.EventArgs) Handles btnBrowse.Click
        ' ประกาศใช้งาน Open File Dialog ในแบบ Run Time
        Dim dlgImage As OpenFileDialog = New OpenFileDialog()

        ' / ตั้งค่าการใช้งาน Open File Dialog
        With dlgImage
            .InitialDirectory = strPath & "Images\"
            .Title = "เลือกไฟล์ภาพ - Images File Format"
            .Filter = "ไฟล์ภาพ (*.jpg;*.png;*.gif;*.bmp)|*.jpg;*.png;*.gif;*.bmp"
            .FilterIndex = 1
            .RestoreDirectory = True
        End With
        ' หากเลือกปุ่ม OK หลังจากการ Browse ...
        If dlgImage.ShowDialog() = DialogResult.OK Then
            ' นำชื่อไฟล์ปัจจุบันไปใส่ไว้ใน oldFileName ก่อนนำชื่อไฟล์ใหม่มาแทน (ใช้ในตอนลบไฟล์)
            oldFileName = newFileName
            newFileName = dlgImage.FileName
            picData.Image = Image.FromFile(newFileName)
            lblMessage.Text = newFileName
        End If
    End Sub

    ' / -----------------------------------------------------------------------------
    Private Sub btnDelete_Click(sender As System.Object, e As System.EventArgs) Handles btnDelete.Click
        Dim strPath As String = MyPath(Application.StartupPath) & "Images\"
        picData.Image = Image.FromFile(strPath & "NoImage.jpg")
        lblMessage.Text = "ไม่มีข้อมูล."
        newFileName = ""
    End Sub

    ' / -----------------------------------------------------------------------------
    Private Sub btnSave_Click(sender As System.Object, e As System.EventArgs) Handles btnSave.Click
        ' ลบไฟล์ภาพเดิมออกไป
        Call FileDelete(oldFileName)
        ' ตรวจสอบว่าเลือกภาพไว้หรือไม่ หากมีก็คัดลอกไฟล์ใหม่ไปยังโฟลเดอร์ที่เราเก็บภาพ
        If newFileName <> "" Then Call FileCopy(newFileName)

        ' แยกไปโปรแกรมย่อยเพื่อทำการบันทึกข้อมูล โดยยึดค่า PK ที่เป็นตัวแปรแบบ Public (ทุกโปรแกรมย่อยมองเห็นหมด สำหรับฟอร์มนี้เท่านั้น)
        If PK > 0 Then
            Call SaveData(PK)
            ' เคลียร์ค่าใน DataGrid (กรณี Bound Control แต่หาก Unbound ต้องใช้ dgvCustomer.Rows.Clear)
            DAS1.Clear()
            ' Refresh หรือแสดงผลใหม่ (ปกติเราไม่นิยมทำ แต่นี่คือตัวอย่างเพื่อให้เห็นถึงการเปลี่ยนแปลงข้อมูลครับ)
            Call LoadDataCustomer()
        End If
    End Sub

    ' / -----------------------------------------------------------------------------
    ' / โปรแกรมย่อยในการบันทึกข้อมูล
    ' / โดยใช้ค่า PK จากการคลิ๊กที่ DataGridView (ยังไม่ได้ดัก Error น่ะครับ)
    Sub SaveData(PK As Long)
        If PK <= 0 Then Exit Sub
        ' *** ปกติเราจะใช้ Customer Primary Key ซึ่งเป็นตัวเลขมาใช้งานน่ะครับ ***
        strSQL = "UPDATE Customer SET Picture = " & "'" & newFileName & "'" & _
            " WHERE CustomerPK = " & PK

        Try
            ConnDB.Open()
            Comm = New OleDbCommand(strSQL, ConnDB)
            Comm.ExecuteNonQuery()
            MsgBox("Updated record successful.")
            ' แสดงรายชื่อไฟล์ให้เห็น
            If newFileName <> "" Then
                Dim strPath As String = MyPath(Application.StartupPath) & "Images\"
                lblMessage.Text = strPath & newFileName
            End If
        Catch ex As Exception
            MsgBox(ex.ToString)
        End Try
        Comm.Dispose()
        ConnDB.Close()
    End Sub
    ' / -----------------------------------------------------------------------------

    ' / -----------------------------------------------------------------------------
    ' / โปรแกรมย่อยในการคัดลอกไฟล์
    Private Sub FileCopy(SrcFile As String)
        Dim DestFile As String = MyPath(Application.StartupPath) & "Images\"
        Dim iArr() As String
        ' แยกชื่อไฟล์ออกจากโฟลเดอร์ ด้วยเครื่องหมาย \ แล้วเลือก UpperBound Index สูงสุด เพราะนั่นคือชื่อไฟล์+นามสกุล
        ' เช่น "C:\My Project\g2gnet.jpg"
        ' iArr(0) = C:
        ' iArr(1) = My Project
        ' iArr(2) = g2gnet.jpg <-- นี่คือคำตอบ
        iArr = Split(SrcFile, "\")
        DestFile = DestFile & iArr(UBound(iArr))
        ' กำหนดชื่อไฟล์ใหม่ด้วย เพื่อนำชื่อไฟล์+นามสกุลไป Save
        newFileName = iArr(UBound(iArr))

        ' ตรวจสอบก่อนว่าไฟล์ต้นทางมันมีอยู่จริงหรือไม่
        If System.IO.File.Exists(SrcFile) = True Then
            ' Trap Error กรณีที่ไฟล์ต้นทางและปลายทางตัวเดียวกัน
            If LCase(SrcFile) <> LCase(DestFile) Then
                ' คัดลอกไฟล์ต้นทาง (srcFile) ไปยังปลายทาง (DestFile) หากพบไฟล์ชื่อเดียวกันก็ให้เขียนทับ (OverWrite = True)
                ' งานจริงก็ควรตรวจสอบรายละเอียดก่อนน่ะครับ
                System.IO.File.Copy(SrcFile, DestFile, True)
            End If
        End If
    End Sub

    ' / -----------------------------------------------------------------------------
    ' / โปรแกรมย่อยในการลบไฟล์ (โค้ดตัวอย่างชุดนี้ยังไม่ได้นำมาใช้งานครับ ลองไปคิดเพิ่มเติมกันดู)
    Private Sub FileDelete(SrcFile As String)
        If System.IO.File.Exists(SrcFile) = True Then
            System.IO.File.Delete(SrcFile)
        End If
    End Sub

    Private Sub frmMain_FormClosed(sender As System.Object, e As System.Windows.Forms.FormClosedEventArgs) Handles MyBase.FormClosed
        ConnDB.Close()
        Me.Dispose()
        Application.Exit()
    End Sub

    Private Sub btnExit_Click(sender As System.Object, e As System.EventArgs) Handles btnExit.Click
        Me.Close()
    End Sub

End Class

ดาวน์โหลดโค้ดต้นฉบับ VB.Net (2010) ได้ที่นี่

บันทึกการเข้า
สิ่งที่ดีกว่าการให้ คือการให้แบบไม่มีที่สิ้นสุด

ออฟไลน์ Idear

  • Newbie
  • *
  • กระทู้: 2
ขอบคุณครับ

บันทึกการเข้า

ออฟไลน์ naien

  • Newbie
  • *
  • กระทู้: 36
ขอบคุณครับ

บันทึกการเข้า

ออฟไลน์ Mr.Den

  • Jr. Member
  • **
  • กระทู้: 73
  • เพศ: ชาย
ขอบคุณครับผม แข็งแรง แข็งแรงครับ..

บันทึกการเข้า