23
File Handling & Data Persistence Storage Mechanisms: Windows Registry Part of the operating system (files owned by the O/S) Good for storing small amounts of data Files Standard way of persisting information Can be highly structured or very simple, depending on data being stored XML Files again, but based on standards that make it possible for different systems to share the data Databases Very structured and with a lot of program overhead, but very efficient for saving large amounts of data The Registry: The Windows Registry is a large text database, which stores data in a hierarchical structure Application data is stored in a tree structure– typically o The application name is the top level – e.g. MyProgram o A section name to group related items of data together – e.g. RecentFiles o A key name, that specifies a name and a single item of data – e.g. File1=“C:\MyData\Datafile1.dat” The registry is an operating-system wide resource, and so must be treated with care

09 - File Handling & Data Persistence · File Handling & Data Persistence ... CType(mvarType, Integer), mvarAmount, mvarDescription) W.WriteLine(Data) ... Databases in VB.NET

  • Upload
    tranthu

  • View
    242

  • Download
    0

Embed Size (px)

Citation preview

File Handling & Data Persistence Storage Mechanisms: • Windows Registry

• Part of the operating system (files owned by the O/S)

• Good for storing small amounts of data • Files

• Standard way of persisting information • Can be highly structured or very simple, depending

on data being stored • XML

• Files again, but based on standards that make it possible for different systems to share the data

• Databases • Very structured and with a lot of program overhead,

but very efficient for saving large amounts of data The Registry: • The Windows Registry is a large text database, which

stores data in a hierarchical structure • Application data is stored in a tree structure– typically

o The application name is the top level – e.g. MyProgram

o A section name to group related items of data together – e.g. RecentFiles

o A key name, that specifies a name and a single item of data – e.g. File1=“C:\MyData\Datafile1.dat”

• The registry is an operating-system wide resource, and so must be treated with care

o Not for storing large amounts of data, because potentially every program in windows will use the registry

o Use only the standard functions – GetSetting() and SaveSetting() for reading and writing

o SaveSetting takes 4 arguments: § App Name § Section Name § Key Name § Key Value (cast to String)

o GetSetting takes the same 4 arguments; the last one (Key Value) is the default value to use if the requested registry key does not exist

e.g. using the registry to store a form’s position and size when it is closed, and to restore that position and size when it is loaded the next time: Public Class Form1 Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing SaveSetting("RegDemo", "Position", "Left", CStr(Me.Left)) SaveSetting("RegDemo", "Position", "Top", CStr(Me.Top)) SaveSetting("RegDemo", "Size", "Width", CStr(Me.Width)) SaveSetting("RegDemo", "Size", "Height", CStr(Me.Height)) End Sub Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Me.Left = CInt(GetSetting("RegDemo", "Position", "Left", CStr(Me.Left))) Me.Top = CInt(GetSetting("RegDemo", "Position", "Top", CStr(Me.Top))) Me.Width = CInt(GetSetting("RegDemo", "Size", "Width", CStr(Me.Width))) Me.Height = CInt(GetSetting("RegDemo", "Size", "Height", CStr(Me.Height))) End Sub End Class You can find this data in the Registry using the regedit command from a DOS prompt:

File Handling o All computer data (including registry data, database

data) is ultimately stored in files if it needs to be persisted

o Various device types (Disks, Hard Disks, CD-R/Ws, Mag-Tape, Flash cards etc.) have data stored in them by the OS/ File System, so that all appear the same to a program – simple File devices

o There are only 4 basic operations to worry about when using files o Opening a file – prepares it for Read and Write

operations

o Reading from a file – extracts an item of data and moves on to prepare to read the next item

o Writing to a file – inserts new data (typically at the end of the file)

o Closing a file – files that are open are vulnerable to corruption. Closing a file puts it into a safe state

To read from and write to a file, use the SteamReader and StreamWriter classes. E.g. simple loading/saving of text from a textbox, by opening a file for text-mode access:

Imports system.IO Imports Microsoft.VisualBasic.ControlChars Public Class Form1 Dim fileName As String = Application.StartupPath & "\myfile.txt" Private Sub btnLoad_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLoad.Click Dim instream As StreamReader Try instream = File.OpenText(fileName) Catch MsgBox("File does not exist! -- " & fileName, MsgBoxStyle.Critical) Return End Try Dim line As String line = instream.ReadLine() While line <> Nothing

TextBox1.AppendText(line & NewLine) line = instream.ReadLine() End While instream.Close() End Sub Private Sub btnSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSave.Click Dim outstream As StreamWriter Try outstream = File.CreateText(fileName) Catch MsgBox("Cannot open file for output! -- " & fileName, MsgBoxStyle.Critical) Return End Try outstream.WriteLine(TextBox1.Text) outstream.Close() End Sub End Class

A larger example that stores information about a bank account and its transactions: (bank.sln) o The components of data in a transaction line are

stored using comma-delimited formatting o Also illustrates user-defined classes and

enumerations

(1) frmBank.vb:

Imports System.IO Public Class frmBank Inherits System.Windows.Forms.Form Private Account As BankAccount Private Sub UpdateDisplay() lblBalance.Text = "Balance = €" & Format(Account.GetBalance(), "0.00") txtStmt.Text = Account.GetStatement() End Sub Private Sub frmBank_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load If File.Exists(CurDir() & "\Account.dat") Then Account = New BankAccount(CurDir() & "\Account.dat") Else Account = New BankAccount("Fred Bloggs", 1234) End If UpdateDisplay() End Sub Private Sub btnDeposit_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDeposit.Click Account.Deposit(CDec(InputBox("Enter amount")), InputBox("Enter description")) UpdateDisplay() End Sub Private Sub btnWithdraw_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnWithdraw.Click Account.Withdraw(CDec(InputBox("Enter amount")), InputBox("Enter description")) UpdateDisplay() End Sub Private Sub btnInterest_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnInterest.Click Account.AddInterest(CDec(InputBox("Enter amount"))) UpdateDisplay() End Sub Private Sub btnCharges_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCharges.Click Account.MakeCharges(CDec(InputBox("Enter amount")), InputBox("Enter description")) UpdateDisplay() End Sub Private Sub frmBank_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing Account.Store(CurDir() & "\Account.dat") End Sub End Class

(2): BankAccount.vb:

o The BankAccount Class has as member data an

account name, account number, and an ArrayList which will store a set of transactions

o The Transaction Class stores information on a single transaction, and has as member data: Date, Transaction Type (defined using enumerators), Amount, and Description.

o The Load method of the BankAccount class opens a file and reads the bank account’s name, account number, and transaction count. It then loops the correct number of times, creating a transaction object on each iteration. The transaction class Constructor receives a reference to the StreamReader that has been opened for the file

o The Save method of the BankAccount operates similarly

o We also see the use of the StringBuilder class and the String.Format( ) function which is useful for formatting strings

Imports System.Text, System.IO Friend Class Transaction ' This enumeration will allow us to specify the type of transaction Public Enum TransactionType Deposit = 0 Withdrawal Interest Charges End Enum ' Member data Private mvarDate As Date Private mvarType As TransactionType Private mvarAmount As Decimal Private mvarDescription As String ' Constructors Public Sub New(ByVal TrDate As Date, ByVal Type As TransactionType, ByVal Amount As Decimal, ByVal Description As String) mvarDate = TrDate mvarType = Type mvarAmount = Amount

mvarDescription = Description End Sub Public Sub New(ByRef R As StreamReader) Load(R) End Sub 'All of the properties can be readonly Public ReadOnly Property TrDate() As Date Get Return mvarDate End Get End Property Public ReadOnly Property Type() As TransactionType Get Return mvarType End Get End Property Public ReadOnly Property Amount() As Decimal Get Return mvarAmount End Get End Property Public ReadOnly Property Description() As String Get Return mvarDescription End Get End Property 'Finally a function to format the transaction for a statement Public Function GetStatementLine() As String Dim trType As String = "" ' Specify the transaction type in a string Select Case mvarType Case TransactionType.Deposit trType = "Deposit " Case TransactionType.Withdrawal trType = "Withdrawal " Case TransactionType.Interest trType = "Interest " Case TransactionType.Charges trType = "Charges " End Select ' Add all the transaction data into one big formatted string.. Return String.Format("{0} {1} {2,8:€0.00} {3}", mvarDate.ToShortDateString, trType, mvarAmount, Trim(mvarDescription)) End Function Public Sub Save(ByRef W As StreamWriter) Dim Data As String Data = String.Format("{0}, {1}, {2}, {3}", mvarDate, CType(mvarType, Integer), mvarAmount, mvarDescription) W.WriteLine(Data) End Sub Public Sub Load(ByRef R As StreamReader) Dim Data As String Dim members() As String Data = R.ReadLine()

members = Split(Data, ",") mvarDate = members(0) mvarType = CType(members(1), TransactionType) mvarAmount = CType(members(2), Decimal) mvarDescription = members(3) End Sub End Class Public Class BankAccount Private mvarTransactions As ArrayList Private mvarAccountName As String Private mvarAccountNumber As Long Public Sub New(ByVal name As String, ByVal number As Long) mvarAccountName = name mvarAccountNumber = number mvarTransactions = New ArrayList() End Sub Public Sub New(ByVal FileName As String) If File.Exists(FileName) Then Dim R As StreamReader = New StreamReader(FileName) mvarTransactions = New ArrayList() Load(R) R.Close() End If End Sub Public Sub Store(ByVal FileName As String) Dim W As StreamWriter = New StreamWriter(FileName) Save(W) W.Close() End Sub Public ReadOnly Property AccountName() As String Get Return mvarAccountName End Get End Property Public ReadOnly Property accountnumber() As String Get Return Format(mvarAccountNumber, "0000000000") End Get End Property Public Overloads Sub Deposit(ByVal TrDate As Date, ByVal Amount As Decimal, ByVal Description As String) Dim T As Transaction T = New Transaction(TrDate, Transaction.TransactionType.Deposit, Amount, Description) mvarTransactions.Add(T) End Sub Public Overloads Sub Deposit(ByVal Amount As Decimal, ByVal Description As String) Dim T As Transaction T = New Transaction(Now, Transaction.TransactionType.Deposit, Amount, Description) mvarTransactions.Add(T) End Sub

Public Overloads Sub Withdraw(ByVal TrDate As Date, ByVal Amount As Decimal, ByVal Description As String) Dim T As Transaction T = New Transaction(TrDate, Transaction.TransactionType.Withdrawal, Amount, Description) mvarTransactions.Add(T) End Sub Public Overloads Sub Withdraw(ByVal Amount As Decimal, ByVal Description As String) Dim T As Transaction T = New Transaction(Now, Transaction.TransactionType.Withdrawal, Amount, Description) mvarTransactions.Add(T) End Sub Public Overloads Sub AddInterest(ByVal TrDate As Date, ByVal Amount As Decimal) Dim T As Transaction T = New Transaction(TrDate, Transaction.TransactionType.Interest, Amount, "") mvarTransactions.Add(T) End Sub Public Overloads Sub AddInterest(ByVal Amount As Decimal) Dim T As Transaction T = New Transaction(Now, Transaction.TransactionType.Interest, Amount, "") mvarTransactions.Add(T) End Sub Public Overloads Sub MakeCharges(ByVal TrDate As Date, ByVal Amount As Decimal, ByVal Description As String) Dim T As Transaction T = New Transaction(TrDate, Transaction.TransactionType.Charges, Amount, Description) mvarTransactions.Add(T) End Sub Public Overloads Sub MakeCharges(ByVal Amount As Decimal, ByVal Description As String) Dim T As Transaction T = New Transaction(Now, Transaction.TransactionType.Charges, Amount, Description) mvarTransactions.Add(T) End Sub Public Function GetBalance() As Decimal Dim T As Transaction Dim Bal As Decimal = 0 For Each T In mvarTransactions If T.Type = Transaction.TransactionType.Deposit Or T.Type = Transaction.TransactionType.Interest Then Bal += T.Amount Else Bal -= T.Amount End If Next Return Bal End Function

Public Function GetStatement() As String Dim T As Transaction Dim stmt As StringBuilder = New StringBuilder() stmt.Append("Bank Account Statement" & Environment.NewLine) stmt.Append("Account Name: " & mvarAccountName & Environment.NewLine) stmt.Append("Account Number: " & mvarAccountNumber & Environment.NewLine) For Each T In mvarTransactions stmt.Append(T.GetStatementLine() & Environment.NewLine) Next Return stmt.ToString() End Function Public Sub Save(ByRef W As StreamWriter) Dim T As Transaction W.WriteLine(mvarAccountName) W.WriteLine(mvarAccountNumber) W.WriteLine(mvarTransactions.Count) For Each T In mvarTransactions T.Save(W) Next End Sub Public Sub Load(ByRef R As StreamReader) Dim T As Transaction Dim Count, Index As Integer mvarAccountName = R.ReadLine() mvarAccountNumber = R.ReadLine() Count = R.ReadLine For Index = 1 To Count T = New Transaction(R) mvarTransactions.Add(T) Next End Sub End Class

Databases in VB.NET o Low level file operations are efficient for small

amounts of data o We need a mechanism for extracting (and

manipulating) small amounts of data from a much larger store

o Binary files can do this, but building an information system from the ground up using this mechanism is complex (and error prone)

o Relational Databases are based on tables of data items, which are interconnected according to the relationships between the entities whose data is stored in the tables

o There are many relational database products from numerous vendors

o The .NET Framework contains a set of classes for accessing relational database systems

o These are in the System.Data namespace Relational Databases: o A Relational Database contains several tables, each

storing data on one type of entity (e.g Customers, Products and Orders, OrderLines)

o Relations between records (e.g. the Product sold in an Order) are recorded by simple cross references

o The Orders table would contain a ProductCode field, that can reference a specific Product record

o Central to the idea of relationships between tables is

the notion of a Key field. o A single value in a row in a table is used as an

identifying value, unique to that row – this is the Primary Key field of the table

o E.g. a person’s social security number, a car’s licence number, a student’s matriculation number

o A row in another table relates to a row by storing its primary key value – in the other table it is referred to as a Secondary Key or Foreign Key

Relational Operations: o Only a few types of operation are necessary

1. Retrieve data from tables 2. Insert a row into a table 3. Delete a row from a table 4. Alter the contents of a row in a table

o The complex operation here is retrieving data for an entity: if the data is stored in a combination of tables, the appropriate rows of the table must be extracted and joined together

Structured Query Language: o SQL is a language specifically designed for

database operations o Facilities for retrieving, adding, deleting and

altering data in tables o Facilities for creating tables, relating tables,

amending tables o Complex stuff, like joining together rows from

multiple tables based on matching fields (used in the cross referencing of tables) is dealt with automatically

o Within .NET, SQL is used as an embedded language to specify database operations

o SQL Commands are passed to the database objects in String variables

SQL Commands: o SELECT

o Used to retrieve data from one or more tables, according to certain criteria.

e.g. to select all the rows in a table of invoices that are for customer number 1012, SQL is : SELECT * FROM ORDERS WHERE Cust_ID=1012

o INSERT o Used to add a row to a table

e.g. INSERT INTO Customers FIELDS(ID, Name, Tel) VALUES(1200, “Fred Bloggs”, “555 1234”)

o DELETE o Used to remove one or more rows from a table

DELETE FROM Customers WHERE Name=“Joe Green”

o UPDATE o Used to alter data in one or more row of a table

UPDATE Customers SET Tel=“555 9899” WHERE ID=1200

o Other (less commonly needed) commands are used to create tables, remove tables, change the structure of a table etc.

Databases with .NET o In .NET, the System.Data namespace contains a set

of classes designed to work with relational databases

o 2 Specific families for managing connections and data retrieval: o SqlXXX classes for working with SQL Server

and MSDE – most efficient o OleDb classes for working with all others

(including MS Access) – uses ODBC layer, so less efficient

o These classes manage the acts of getting data from and sending data to the database

System.Data Classes: o Connection class (SqlConnection,

OleDbConnection) form a bridge between a program and the database

o Command class (SqlCommand, OleDbCommand) wraps a SQL statement or names a stored procedure in the database to execute

o DataReader classes (Sql and OleDb) give efficient read-only access to data in a database

o Simple data updates by SQL statement (using Command classes)

o More complex data manipulation using the DataSet, which provides an in-memory relational model of a subset of a whole database o Retrieves data using a DataAdapter o Provides a ‘cursor’ for navigating through the

data o Allows changes to be returned to the database o Provides for ‘disconnection’ from the live

database so it can be used off-line – e.g. on a laptop

o A disconnected DataSet can be persisted to disk using XML

DataReader classes: o oleDbDataReader and sqlDataReader retrieve data

from a Command object (using ExecuteReader methods)

o DataReader’s Read() method reads a record and moves on to next

o DataReader’s Item() property gives access to fields (by ordinal number or name)

DatabaseExample.sln:

Imports System.Data Imports System.Data.OleDb Public Class Form1 Dim connString As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Users\sam\Desktop\VB.NET\Bookshop.mdb" Private Sub btnShowAuthors_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnShowAuthors.Click Dim dbConn As New OleDbConnection(connString) Dim SQLQuery As String = "Select * From Authors;" Dim dbCmd As New OleDbCommand(SQLQuery, dbConn) dbConn.Open() Dim reader As OleDbDataReader = dbCmd.ExecuteReader() With reader Do While .Read() TextBox1.Text &= .Item("Name") & " " & .Item("Address") & vbCrLf Loop End With End Sub End Class

Private Sub btnShowAuthors_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnShowAuthors.Click Dim dbConn As New OleDbConnection(connString) Dim SQLQuery As String = "SELECT Books.Title, Authors.Name, Books.Year FROM Books INNER JOIN Authors ON Books.FK_Author=Authors.PK_Author;" Dim dbCmd As New OleDbCommand(SQLQuery, dbConn) dbConn.Open() Dim reader As OleDbDataReader = dbCmd.ExecuteReader() With reader Do While .Read() TextBox1.Text &= String.Format("{0} by {1} ({2})", .Item("Title"), .Item("Name"), .Item("Year")) & vbCrLf Loop End With End Sub

Writing to a database: Private Sub btnAddBook_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAddBook.Click Dim title As String title = InputBox("Enter Title of Book") If title.Length() > 0 Then Dim dbConn As New OleDbConnection(connString) Dim SQLQuery As String Dim FK_Author As Integer = 1 Dim ISBN As Integer = 1232 Dim Yr As Integer = 2006 SQLQuery = String.Format("INSERT INTO BOOKS(FK_Author, Title, ISBN, Year) VALUES ({0},'{1}','{2}',{3});", FK_Author, title, ISBN, Yr) Dim dbCmd As New OleDbCommand(SQLQuery, dbConn) dbConn.Open() dbCmd.ExecuteNonQuery() End If End Sub

Defining a connection string:

• Use the Data > Add New Data Source menu

VB Controls for Database Connectivity: Text boxes and other control can be ‘bound’ to a dataset: The Properties (Data Bindings)(Advanced) section needs to be expanded:

Then you define the data set, table, and field to bind the text box to:

The ‘BindingSource’ objects that are created when you add a data connection to your project can be used to navigate through the records, or edit/delete etc.:

(project tray)

VBDataBindingsExample.sln:

Public Class Form1 Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing AuthorsBindingSource.EndEdit() AuthorsTableAdapter.Update(BookshopDataSet.Authors) End Sub Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'TODO: This line of code loads data into the 'BookshopDataSet.Authors' table. You can move, or remove it, as needed. AuthorsTableAdapter.Fill(Me.BookshopDataSet.Authors) End Sub Private Sub btnPrev_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPrev.Click AuthorsBindingSource.MovePrevious() End Sub Private Sub btnNext_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnNext.Click AuthorsBindingSource.EndEdit() AuthorsBindingSource.MoveNext() End Sub Private Sub btnFirst_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnFirst.Click AuthorsBindingSource.MoveFirst() End Sub Private Sub btnLast_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLast.Click

AuthorsBindingSource.MoveLast() End Sub Private Sub btnAdd_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAdd.Click AuthorsBindingSource.AddNew() End Sub Private Sub btnDelete_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDelete.Click AuthorsBindingSource.RemoveCurrent() End Sub End Class