Sunday, December 25, 2016

Bab 4. Visual C# Untuk Programer



File






4.1 Pengantar

C# memandang setiap file sebagai aliran byte sekuensial. Setiap file diakhiri dengan penanda end-of-file. Ketika file dibuka, C# menciptakan sebuah objek dan kemudian mengaitkan sebuah aliran dengan objek tersebut. Ada tiga objek aliran, masing-masing dapat diakses lewat properti Console.Out, Console.In, dan Console.Error. Ketiga objek tersebut memfasilitasi komunikasi antara program dan file atau divais tertentu. Properti Console.In menghasilkan objek aliran masukan standar, yang memampukan sebuah program untuk membaca data dari keyboard. Properti Console.Out menghasilkan objek aliran keluaran standar, yang memampukan sebuah program untuk menampilkan data pada monitor. Properti Console.Error menghasilkan objek aliran error standard, yang memampukan sebuah program untuk menampilkan pesan error pada layar. Anda telah menggunakan Console.Out dan Console.In pada beberapa aplikasi konsol sebelumnya, dimana metode-metode Console, Write dan WriteLine menggunakan Console.Out dalam menampilkan keluaran, dan metode-metode Read dan ReadLine menggunakan Console.In dalam membaca masukan.

Untuk melakukan pemrosesan file dalam C#, namespace System.IO harus direferensi. Namespace ini mencakup beberapa definisi untuk kelas-kelas aliran seperti StreamReader (untuk membaca teks dari sebuah file), StreamWriter (untuk menulis teks ke dalam sebuah file), dan FileStream (untuk kedua pembacaan dan penulisan file). File dibuka dengan menciptakan objek dari kelas aliran tersebut, yang mewarisi kelas MustInherit TextReader, TextWriter, dan Stream. Sebenarnya, Console.In dan Console.Out merupakan properti dari kelas TextReader dan TextWriter. Kedua kelas tersebut adalah MustInherit; StreamReader dan StreamWriter adalah kelas yang diderivasi dari kelas TextReader dan TextWriter.

C# menyediakan kelas BinaryFormatter, yang digunakan dengan sebuah objek Stream untuk melakukan pembacaan dan penulisan objek. Serialisasi melibatkan konversi sebuah objek menjadi format yang dapat ditulis ke dalam sebuah file tanpa harus kehilangan data objek. Deserialisasi memuat pembacaan format tersebut dari sebuah file dan merekonstruksi objek asli darinya. Sebuah BinaryFormatter dapat menserialisasi objek dan mendeserialisasi objek. Kelas System.IO.Stream menyediakan fungsionalitas untuk merepresentasikan aliran sebagai byte. Kelas ini adalah MustInherit, jadi objek-objek kelas ini tidak dapat diinstansiasi. Kelas FileStream, MemoryStream, dan BufferedStream (semua dari namespace System.IO) mewarisi kelas Stream.


4.2 Kelas File dan Kelas Directory
Informasi pada komputer disimpan dalam file, yang diorganisasi dalam direktori. Kelas File disediakan untuk memanipulasi file, dan kelas Directory disediakan untuk memanipulasi direktori. Kelas File tidak dapat menulis ke atau membaca dari file secara langsung.

Perhatikan bahwa karakter separator \ memisahkan direktori dan file pada sebuah path. Pada sistem UNIX, karakter separator adalah /. Visual Basic dapat memproses kedua karakter tersebut. Ini berarti bahwa, jika Anda menspesifikasi path c:\C#/README, yang menggunakan kedua karakter separator tersebut, maka C# masih bisa memproses file itu secara benar.

Gambar 4.1 mencantumkan beberapa metode pada kelas File untuk memanipulasi dan menentukan informasi tentang file tertentu. Kelas File hanya memuat metode-metode static, jadi Anda tidak bisa menginstansiasi objek bertipe File. Beberapa dari metode tersebut akan dipakai dalam contoh pada Gambar 4.3.

Metode static
Penjelasan
AppendText



Copy

Create


CreateText


Delete

GetCreationTime


GetLastAccessTime


GetLastWriteTime


Move

Open


OpenRead


OpenText


OpenWrite
Menghasilkan sebuah StreamWriter yang dikaitkan pada sebuah file yang sudah ada atau menciptakan sebuah file jika file yang dimaksud belum ada.

Menyalin sebuah file ke dalam file baru.

Menghasilkan sebuah FileStream yang dikaitkan dengan file yang baru saja diciptakan.

Menghasilkan sebuah StreamWriter yang dikaitkan dengan file teks baru.

Menghapus file yang diinginkan.

Menghasilkan sebuah objek DateTime yang merepresentasikan waktu ketika file diciptakan.

Menghasilkan sebuah objek DateTime yang merepresentasikan waktu ketika file terakhir kali diakses.

Menghasilkan sebuah objek DateTime yang merepresentasikan waktu ketika file terakhir kali dimodifikasi.

Memindahkan file tertentu ke lokasi tertentu.

Menghasilkan sebuah FileStream yang dikaitkan dengan file tertentu dan dilengkapi dengan ijin pembacaan/penulisan.

Menghasilkan sebuah FileStream read-only yang dikaitkan dengan file tertentu.

Menghasilkan sebuah StreamReader yang dikaitkan dengan file tertentu.

Menghasilkan sebuah FileStream read/write yang dikaitkan dengan file tertentu.

Gambar 4.1 Beberapa metode static kelas File

Kelas Directory menyediakan beberapa kapabilitas untuk memanipulasi direktori dengan .NET Framework. Gambar 4.2 mencantumkan beberapa metode static yang dapat dipakai untuk manipulasi direktori. Beberapa dari metode tersebut dipakai dalam contoh pada Gambar 4.3.

Objek DirectoryInfo yang dijadikan nilai balik oleh metode CreateDirectory memuat informasi tentang sebuah direktori. Informasi yang dimuat pada kelas ini dapat pula diakses via metode-metode Directory.

Metode static
Penjelasan
CreateDirectory


Delete

Exists


GetLastWriteTime



GetDirectories


GetFiles


GetCreationTime


GetLastAccessTime


GetLastWriteTime



Move
Menghasilkan objek DirectoryInfo yang dikaitkan dengan direktori yang baru saja diciptakan.

Menghapus direktori tertentu.

Menghasilkan True jika direktori tertentu eksis; sebaliknya, ia menghasilkan False.

Menghasilkan sebuah objek DateTime yang merepresentasikan waktu ketika direktori tertentu terakhir kali dimodifikasi.

Menghasilkan array String yang merepresentasikan nama-nama direktori di dalam direktori tertentu.

Menghasilkan array String yang merepresentasikan nama-nama direktori di dalam file tertentu.

Menghasilkan sebuah objek DateTime yang merepresentasikan waktu ketika direktori tertentu diciptakan.

Menghasilkan sebuah objek DateTime yang merepresentasikan waktu ketika direktori tertentu terakhir kali diakses.

Menghasilkan sebuah objek DateTime yang merepresentasikan waktu ketika item-item terakhir kali dituliskan ke dalam direktori.

Memindahkan direktori tertentu ke lokasi tertentu.

Gambar 4.2 Beberapa metode static kelas Directory


Menganalisa Kelas File dan Kelas Directory
Kelas UjiFileForm (Gambar 4.3) menggunakan berbagai metode yang dideskripsikan pada Gambar 4.1 dan Gambar 4.2 untuk mengakses file dan informasi direktori. Kelas ini memuat TextBox masukanTextBox, yang memampukan pengguna untuk memasukkan sebuah file atau nama direktori.

Untuk setiap kunci yang ditekan pengguna pada kotak teks, program akan memanggil masukanTextBox_KeyDown (baris 19-75). Jika pengguna menekan kunci Enter (baris 22), metode ini akan menampilkan file atau isi direktori, tergantung dari masukan pengguna pada TextBox (Perhatikan bahwa, jika pengguna tidak menekan kunci Enter, maka metode ini tidak akan menampilkan isi apapun).

Baris 28 menggunakan metode Exists dari kelas File untuk menentukan apakah teks yang diberikan pengguna adalah sebuah file. Jika pengguna menspesifikasi sebuah file yang sudah ada, maka baris 31 akan memanggil metode private GetInformasi (baris 79-97), yang memanggil metode GetCreationTime (baris 88), GetLastWriteTime (baris 92), dan GetLastAccessTime (baris 96) dari kelas File untuk mengakses informasi pada file.

Ketika metode GetInformasi selesai dieksekusi, baris 38 menginstansiasi sebuah StreamReader untuk membaca teks dari file. Konstruktor StreamReader memerlukan sebuah argumen String yang memuat nama file yang akan dibuka. Baris 40 memanggil metode ReadToEnd dari kelas StreamReader untuk membaca isi file dan menampilkannya.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// Gambar 4.3: UjiFileForm.cs
// Menggunakan kelas File dan Directory.
using System;
using System.Windows.Forms;
using System.IO;

namespace UjiFile
{
    // menampilkan isi file dan direktori
    public partial class UjiFileForm : Form
    {
        //konstruktor tanpa parameter
        public UjiFileForm()
        {
            InitializeComponent();
        }

        // dipanggil ketika pengguna menekan kunci
        private void masukanTextBox_KeyDown(object sender, KeyEventArgs e)
        {
            // menentukan apakah pengguna menekan kunci Enter
            if ( e.KeyCode == Keys.Enter )
            {
                // mendapatkan file atau direktori yang ditetapkan pengguna
                string namaFile = masukanTextBox.Text;

                // menentukan apakan namaFile adalah sebuah file
                if ( File.Exists( namaFile ) )
                {
                    // mendapatkan waktu penciptaan, modifikasi, dsb dari file
                    GetInformasi( namaFile );
                    StreamReader aliran = null; // mendeklarasikan StreamReader
               
                    // menampilkan isi file dengan StreamReader
                    try
                    {
                        // mendapatkan reader dan isi file
                        using (aliran = new StreamReader(namaFile))
                        {
                            keluaranTextBox.AppendText(aliran.ReadToEnd());
                        } // akhir using
                    } // akhir try
                    catch ( IOException )
                    {
                        MessageBox.Show( "Error pembacaan dari file",
                            "File Error", MessageBoxButtons.OK,
                            MessageBoxIcon.Error );
                    } // akhir catch
                } // akhir if
                // menentukan apakan namaFile adalah sebuah direktori
                else if ( Directory.Exists( namaFile ) )
                {
                    // mendapatkan tanggal penciptaan,
                    // tanggal modifikasi, dll dari direktori.
                    GetInformasi(namaFile);

                    // mendapatkan daftar file/direktori dari direktori tertentu
string[] daftarDirektori =
    Directory.GetDirectories(namaFile);

                    keluaranTextBox.AppendText( "Isi direktori:\n" );

                    // menampilkan isi daftarDirektori
                    foreach ( var directori in daftarDirektori )
                        keluaranTextBox.AppendText(directori + "\n");
                } // akhir else if
                else
                {
                    // memberitahu pengguna bahwa file dan direktori tidak ada
                    MessageBox.Show( masukanTextBox.Text +
                        " tidak ada", "File Error",
                        MessageBoxButtons.OK, MessageBoxIcon.Error );
                } // akhir else
            } // akhir if
        } // akhir metode masukanTextBox_KeyDown

        // mendapatkan informasi file atau direktori,
        // dan menampilkannya pada keluaranTextBox
        private void GetInformasi (string namaFile)
        {
            keluaranTextBox.Clear();

            // menampilkan bahwa file atau direktori ada
            keluaranTextBox.AppendText(namaFile + " ada\n");

            // menampilkan kapan file atau direktori diciptakan
            keluaranTextBox.AppendText("Diciptakan: " +
            File.GetCreationTime( namaFile ) + "\n" );

            // menampilkan kapan file atau direktori terakhir dimodifikasi
            keluaranTextBox.AppendText("Terakhir dimodifikasi: " +
            File.GetLastWriteTime( namaFile ) + "\n" );

            // menampilkan kapan file atau direktori terakhir diakses
            keluaranTextBox.AppendText("Terakhir diakses: " +
            File.GetLastAccessTime( namaFile ) + "\n" );
        } // akhir metode GetInformasi
    } // akhir kelas UjiFileForm
} // akhir namespace UjiFile






Jika baris 28 menentukan bahwa teks yang dimasukkan pengguna bukanlah sebuah file, maka baris 51 memutuskan bahwa ia adalah sebuah direktori menggunakan metode Exists dari kelas Directory. Jika pengguna memasukkan direktori yang sudah ada, maka baris 55 memanggil metode GetInformasi untuk mengakses informasi direktori. Baris 59 memanggil metode GetDirectories dari kelas Directory untuk mendapatkan array string yang memuat nama-nama subdirektori di dalam direktori yang dispesifikasi. Baris 64-65 menampilkan setiap elemen di dalam array string. Perhatikan bahwa, jika baris 51 menentukan bahwa teks yang dimasukkan pengguna bukanlah file atau direktori, maka baris 70-72 akan memberitahu pengguna (lewat MessageBox) bahwa file atau direktori tidak ada.

Mencari Direktori dengan LINQ
Sekarang akan disajikan contoh lain yang menggunakan kapabilitas manipulasi direktori dan file pada Visual Basic. Kelas LINQToFileDirektoriForm (Gambar 4.4) menggunakan LINQ dengan kelas File, Path dan Directory untuk melaporkan jumlah file untuk tipe file di dalam path direktori yang dispesifikasi. Program juga berperan untuk utilitas “pembersihan”, ketika program menjumpai sebuah file berekstensi .bak (backup file). Program menampilkan sebuah MessageBox untuk menanyakan apakah file tersebut perlu dihapus dan merespon sesuai masukan pengguna. Contoh ini uga menggunakan LINQ terhadap objek untuk menghapus file backup.

Ketika pengguna menekan kunci Enter atau mengklik tombol Cari Direktori, program akan memanggil cariButton_Click (baris 25-65), yang mencari secara rekursif melalui path direktori yang disediakan pengguna. Jika pengguna memasukkan teks di dalam TextBox, baris 29 akan memanggil metode Exists dari kelas Directory untuk menentukan apakah teks tersebut mengindikasikan direktori yang valid. Jika pengguna menspesifikasi direktori yang tak valid, maka baris 32-33 akan memberitahu pengguna tentang error yang terjadi.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// Gambar 4.4: LINQToFileDirektoriForm.cs
// Menggunakan LINQ untuk melakukan pencarian direktori dan menentukan tipe-tipe file.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.IO;

namespace LINQToFileDirektori
{
    public partial class LINQToFileDirektoriForm : Form
    {
        string direktoriSekarang; // directori yang akan dijelajah

        // menyimpan ekstensi ditemukan, dan jumlah tiap ekstensi ditemukan
        Dictionary<string, int> ditemukan = new Dictionary<string, int>();

        // konstruktor tanpa parameter
        public LINQToFileDirektoriForm()
        {
            InitializeComponent();
        } // akhir konstruktor tanpa parameter

        // menangani event Click pada tombol Cari Direktori
        private void cariButton_Click(object sender, EventArgs e)
        {
            // memeriksa apakah pengguna menetapkan path yang ada
            if ( pathTextBox.Text != string.Empty &&
                !Directory.Exists( pathTextBox.Text ) )
            {
                // menampilkan error jika pengguna tidak menetapkan path yang valid
                MessageBox.Show( "Direktori Tak-Valid", "Error",
                MessageBoxButtons.OK, MessageBoxIcon.Error );
            } // akhir if
            else
            {
                // menggunakan direktoriSekarang jika tidak ada direktori yang ditetapkan
                if ( pathTextBox.Text == string.Empty )
                    direktoriSekarang = Directory.GetCurrentDirectory();
                else
                    direktoriSekarang = pathTextBox.Text;

                direktoriTextBox.Text = direktoriSekarang; // menampilkan direktori

                // membersihkan TextBox
                pathTextBox.Clear();
                hasilTextBox.Clear();

                CariDirektori( direktoriSekarang ); // mencari direktori

                // memampukan pengguna untuk menghapus file .bak
                HapusDirektori( direktoriSekarang );

                // menyimpulkan dan menampilkan hasil
                foreach ( var sekarang in ditemukan.Keys)
                {
                    // menampilkan jumlah file dengan ekstensi
                    hasilTextBox.AppendText(string.Format(
                        "* Ditemukan {0} {1} file.\r\n",
                        ditemukan[ sekarang ], sekarang ) );
                } // akhir foreach

                ditemukan.Clear(); // menghapus hasil dari pencarian baru
            } // akhir else
        } // akhir method cariButton_Click

        // pencarian direktori menggunakan LINQ
        private void CariDirektori(string folder)
        {
            // file-file yang dimuat di dalam direktori
            string[] file2 = Directory.GetFiles( folder );

            // sub-sudirektori di dalam direktori
            string[] direktori2 = Directory.GetDirectories( folder );

            // menemukan semua ekstensi file pada direktori ini
            var ekstensi2 =
( from file in file2
select Path.GetExtension( file ) ).Distinct();

            // menghitung jumlah file
            foreach ( var ekstensi in ekstensi2 )
            {
                var temp = ekstensi;

                // menghitung jumlah file dengan ekstensi
                var hitungEkstensi =
( from file in file2
where Path.GetExtension( file ) == temp
select file ).Count();

                // jika Dictionary telah memuat kunci untuk ekstensi
                if ( ditemukan.ContainsKey( ekstensi ) )
                    ditemukan[ ekstensi ] += hitungEkstensi; // perbarui perhitungan
                else
                    ditemukan.Add( ekstensi, hitungEkstensi ); // tambahkan
            } // akhir foreach

            // pemanggilan rekursif terhadap sub-sub direktori
            foreach ( var subdirektori in direktori2 )
                CariDirektori(subdirektori);
        } // akhir metode CariDirektori

        // memampukan pengguna untuk menghapus filebackup (.bak)
        private void HapusDirektori( string folder )
        {
            // file-file yang dimuat di dalam direktori
            string[] file2 = Directory.GetFiles( folder );

            // sub-sub direktori di dalam direktori
            string[] direktori2 = Directory.GetDirectories( folder );

            // memilih semua file backup pada direktori ini
            var file2Backup =
from file in file2
where Path.GetExtension( file ) == ".bak"
select file;

            // beriterasi menjelajahi semua file backup (.bak)
            foreach ( var backup in file2Backup )
            {
DialogResult hasil = MessageBox.Show( "Ditemukan file backup " +
    Path.GetFileName( backup ) + ". Hapus?", "Hapus Backup",
    MessageBoxButtons.YesNo, MessageBoxIcon.Question );

                // menghapus file jika pengguna mengklik 'yes'
                if ( hasil == DialogResult.Yes )
                {
File.Delete( backup ); // menghapus file backup
--ditemukan[ ".bak" ]; // mendekremen ditemukan

                    // jika tidak ada file .bak, hapus kunci dari Directory
                    if ( ditemukan[ ".bak" ] == 0 )
                        ditemukan.Remove( ".bak" );
                } // akhir if
            } // akhir foreach

            // pemanggilan rekursif untuk menghapus sub-subdirektori
            foreach (var subdirektori in direktori2)
                HapusDirektori( subdirektori );
        } // akhir metode HapusDirektori
    } // akhir kelas LINQToFileDirektoriForm
 } // akhir namespace LINQToFileDirektori





Metode CariDirektori
Baris 38-41 mendapatkan direktori terkini (jika pengguna tidak menetapkan path) atau direktori yang ditetapkan pengguna. Baris 49 melewatkan nama direktori kepada metode rekursif CariDirektori (baris 68-102). Baris 107 memanggil metode GetFiles dari kelas Directory untuk mendapatkan suatu array string yang memuat nama-nama file pada direktori tertentu. Baris 74 memanggil GetDirectories dari kelas Directory untuk mendapatkan sebuah array string yang memuat nama-nama subdirektori pada direktori tertentu.

Baris 78-79 menggunakan LINQ untuk mendapatkan ekstensi-ekstensi file pada array file2. Metode GetExtension dari kelas Path mendapatkan ekstensi untuk nama file tertentu. Untuk tiap ekstensi file yang dihasilkan oleh LINQ query, baris 82-97 menentukan jumlah kemunculan ekstensi tersebut pada array file2. LINQ query pada baris 88-90 membandingkan tiap ekstensi file pada array file2 dengan ekstensi yang sedang diproses (baris 89). Semua kecocokan dicantumkan pada hasil. Anda kemudian menggunakan metode Count untuk menghitung jumlah total file yang cocok dengan ekstensi terkini.

Kelas LINQToFileDirektoriForm menggunakan sebuah Directory (dideklarasikan pada baris 16) untuk menyimpan setiap ekstensi file dan jumlah dari nama file yang terkait dengan ekstensi itu. Sebuah Directory (namespace System.Collections.Generic) merupakan suatu koleksi pasangan kunci/nilai, dimana di dalamnya setiap kunci memiliki nilai tertentu. Kelas Directory merupakan sebuah kelas generik seperti kelas List. Baris 16 mengindikasikan bahwa Dictionary ditemukan memuat pasangan-pasangan string dan int, yang merepresentasikan ekstensi file dan jumlah filenya. Baris 93 menggunakan metode ContainsKey dari kelas Dictionary untuk menentukan apakah ekstensi file tertentu telah ditempatkan pada Dictionary. Jika metode ini menghasilkan true, maka baris 94 akan menambahkan hitungEkstensi yang ditentukan pada baris 88-90 pada jumlah ekstensi terkini yang disimpan pada Dictionary. Sebaliknya, baris 96 menggunakan metode Add dari kelas Dictionary untuk menyisipkan sebuah pasangan kunci/nilai ke dalam Dictionary untuk ekstensi file yang baru dan hitungEkstensinya. Baris 100-101 secara rekursif memanggil CariDirektori untuk tiap subdirektori di dalam direktori terkini.

Metode HapusDirektori
Ketika metode CariDirektori selesai dieksekusi, baris 52 memanggil HapusDirektori (didefinisikan pada baris 105-141) untuk melakukan pencarian terhadap semua file yang berekstensi .bak. Baris 108 dan 111 mendapatkan daftar nama file dan daftar nama direktori pada direktori terkini. LINQ query pada baris 115-117 mencari lokasi semua nama file pada direktori terkini yang memiliki ekstensi .bak. Baris 120-136 beriterasi menjelajah hasil-hasil query dan meminta pengguna untuk menentukan apakah tiap file perlu dihapus. Jika pengguna mengklik Yes pada dialog, maka baris 129 menggunakan metode Delete dari kelas File untuk menghapus file dari disk, dan baris 130 mengurangkan 1 dari jumlah total file .bak.


4.3 Menciptakan File Akses-Sekuensial
C# tidak memaksakan struktur apapun pada sebuah file. Ini berarti bahwa, programer harus menstrukturisasi file untuk memenuhi persyaratan aplikasi.

Kelas BankUIForm
Kelas BankUIForm (Gambar 4.5) memuat empat Label dan empat TextBox. Metode BersihTextBox (baris 28-40), SetNilaiTextBox (baris 43-64), dan GetNilaiTextBox (baris 67-78) menghapus, menetapkan nilai-nilai, dan mendapatkan nilai-nilai teks di dalam TextBox.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
// Gambar 4.5: BankUIForm.cs
// Windows Form yang dapat didaur-ulang untuk beberapa contoh pada buku ini.
using System;
using System.Windows.Forms;

namespace PustakaBank
{
    public partial class BankUIForm : Form
    {
        protected int JumlahTextBox = 4; // jumlah TextBoxes pada Form
       
        // konstanta-konstanta enumerasi untuk menetapkan indeks-indeks TextBox
        public enum IndeksTextBox
        {
            AKUN,
            PERTAMA,
            AKHIR,
            SALDO
        } // akhir enum
       
        // konstruktor tanpa-parameter
        public BankUIForm()
        {
            InitializeComponent();
        }

        // menghapus semua TextBox
        public void BersihTextBox()
        {
            // menjelajah setiap Control pada form
            foreach ( Control guiControl in Controls )
            {
                // menentukan apakan Control adalah TextBox
                if ( guiControl is TextBox )
                {
                    // menghapus TextBox
                     ( ( TextBox ) guiControl ).Clear();
                } // akhir if
            } // akhir for
        } // akhir metode BersihTextBox

        // menetapkan nilai-nilai TextBox menjadi nilai-nilai array string
        public void SetNilaiTextBox(string[] nilai2)
        {
            // menentukan apakah array string memiliki panjang yang tepat
            if ( nilai2.Length != JumlahTextBox )
            {
                // melempar eksepsi jika panjang tidak tepat
                throw ( new ArgumentException( "Harus ada " +
                    ( JumlahTextBox + 1 ) + " string pada array" ) );
            } // akhir if
            // menetapkan nilai-nilai array jika array memiliki panjang yang tepat
            else
            {
                // menetapkan nilai-nilai array menjadi nilai-nilai TextBox
                akunTextBox.Text =
                    nilai2[ ( int ) IndeksTextBox.AKUN ];
                namaPertamaTextBox.Text =
                    nilai2[ ( int ) IndeksTextBox.PERTAMA ];
                namaAkhirTextBox.Text = nilai2[ ( int ) IndeksTextBox.AKHIR ];
                saldoTextBox.Text =
                    nilai2[ ( int ) IndeksTextBox.SALDO ];
            } // akhir else
        } // akhir metode SetNilaiTextBox

        // menghasilkan nilai-nilai TextBox sebagai array string
        public string[] GetNilaiTextBox()
        {
            string[] nilai2 = new string[ JumlahTextBox ];

            // menyalin semua bidang TextBox ke array string
            nilai2[ ( int ) IndeksTextBox.AKUN ] = akunTextBox.Text;
            nilai2[ ( int ) IndeksTextBox.PERTAMA ] = namaPertamaTextBox.Text;
            nilai2[ ( int ) IndeksTextBox.AKHIR ] = namaAkhirTextBox.Text;
            nilai2[ ( int ) IndeksTextBox.SALDO ] = saldoTextBox.Text;

            return nilai2;
        } // akhir metode GetNilaiTextBox
    } // akhir kelas BankUIForm
} // akhir namespace PustakaBank




Dengan menggunakan pewarisan, Anda dapat mewarisi kelas ini untuk menciptakan GUI pada beberapa contoh pada bab ini. Ingat bahwa untuk mengdaur-ulang kelas BankUIForm, Anda harus mengkompilasi GUI tersebut menjadi sebuah pustaka kelas, kemudian menambahkan referensi ke pustaka kelas yang baru itu pada tiap projek yang menggunakannya.


Kelas Rekaman
Gambar 4.6 memuat kelas Rekaman untuk menuliskan ke atau membaca dari sebuah file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// Gambar 4.6: Rekaman.cs
// Kelas yang merepresentasikan sebuah rekaman data.

namespace PustakaBank
{
    public class Rekaman
    {
// properti Akun implementasi-diri
public int Akun { get; set; }

// properti NamaPertama implementasi-diri
public string NamaPertama { get; set; }

// properti NamaAkhir implementasi-diri
public string NamaAkhir { get; set; }

// properti Saldo implementasi-diri
public decimal Saldo { get; set; }
       
        // konstruktor tanpa parameter menetapkan nilai-nilai default
        public Rekaman()
            : this( 0, string.Empty, string.Empty, 0M )
        {
        } // akhir konstruktor

        // konstruktor teroverload menetapkan nilai-nilai parameter
        public Rekaman( int nilaiAkun, string nilaiNamaPertama,
            string nilaiNamaAkhir, decimal nilaiSaldo )
        {
            Akun = nilaiAkun;
            NamaPertama = nilaiNamaPertama;
            NamaAkhir = nilaiNamaAkhir;
            Saldo = nilaiSaldo;
        } // akhir konstruktor
 } // akhir kelas Rekaman
} // akhir namespace PustakaBank

Kelas BankUIForm Terperbarui
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
// Gambar 4.7: BankUIForm.cs
// Windows Form yang dapat didaur-ulang untuk beberapa contoh pada buku ini.
using System;
using System.Windows.Forms;
using System.IO;

namespace PustakaBank
{
    public partial class BankUIForm : Form
    {
        protected int JumlahTextBox = 4; // jumlah TextBoxes pada Form
        private StreamWriter penulisFile; // writes data to text file

        // konstanta-konstanta enumerasi untuk menetapkan indeks-indeks TextBox
        public enum IndeksTextBox
        {
            AKUN,
            PERTAMA,
            AKHIR,
            SALDO
        } // akhir enum

        // konstruktor tanpa-parameter
        public BankUIForm()
        {
            InitializeComponent();
        }

        // menghapus semua TextBox
        public void BersihTextBox()
        {
            // menjelajah setiap Control pada form
            foreach (Control guiControl in Controls)
            {
                // menentukan apakan Control adalah TextBox
                if (guiControl is TextBox)
                {
                    // menghapus TextBox
                    ((TextBox)guiControl).Clear();
                } // akhir if
            } // akhir for
        } // akhir metode BersihTextBox

        // menetapkan nilai-nilai TextBox menjadi nilai-nilai array string
        public void SetNilaiTextBox(string[] nilai2)
        {
            // menentukan apakah array string memiliki panjang yang tepat
            if (nilai2.Length != JumlahTextBox)
            {
                // melempar eksepsi jika panjang tidak tepat
                throw (new ArgumentException("Harus ada " +
                    (JumlahTextBox + 1) + " string pada array"));
            } // akhir if
            // menetapkan nilai-nilai array jika array memiliki panjang yang tepat
            else
            {
                // menetapkan nilai-nilai array menjadi nilai-nilai TextBox
                akunTextBox.Text =
                    nilai2[(int)IndeksTextBox.AKUN];
                namaPertamaTextBox.Text =
                    nilai2[(int)IndeksTextBox.PERTAMA];
                namaAkhirTextBox.Text = nilai2[(int)IndeksTextBox.AKHIR];
                akunTextBox.Text =
                    nilai2[(int)IndeksTextBox.SALDO];
            } // akhir else
        } // akhir metode SetNilaiTextBox

        // menghasilkan nilai-nilai TextBox sebagai array string
        public string[] GetNilaiTextBox()
        {
            string[] nilai2 = new string[JumlahTextBox];

            // menyalin semua bidang TextBox ke array string
            nilai2[(int)IndeksTextBox.AKUN] = akunTextBox.Text;
            nilai2[(int)IndeksTextBox.PERTAMA] = namaPertamaTextBox.Text;
            nilai2[(int)IndeksTextBox.AKHIR] = namaAkhirTextBox.Text;
            nilai2[(int)IndeksTextBox.SALDO] = saldoTextBox.Text;

            return nilai2;
        } // akhir metode GetNilaiTextBox

        // menangani event Click untuk simpanButton
        private void simpanButton_Click(object sender, EventArgs e)
        {
            // menciptakan dan menampilkan kotak dialog untuk menyimpan file
            DialogResult hasil; // hasil dari SaveFileDialog
            string namaFile; // nama file yang memuat data

using ( SaveFileDialog pemilihFile = new SaveFileDialog() )
{
    pemilihFile.CheckFileExists = false; // menciptakan file
    hasil = pemilihFile.ShowDialog();
    namaFile = pemilihFile.FileName; // nama file untuk disimpan
} // akhir using

             // memastikan bahwa pengguna mengklik "OK"
            if ( hasil == DialogResult.OK )
            {
                // menampilkan error jika pengguna menetapkan file tak-valid
                if ( namaFile == string.Empty )
                    MessageBox.Show( "Nama Tak Valid", "Error",
                        MessageBoxButtons.OK, MessageBoxIcon.Error );
                else
                {
                    // menyimpan file via FileStream jika pengguna menetapkan file valid
                    try
                    {
                        // membuka file dengan akses write
FileStream keluaran = new FileStream( namaFile,
FileMode.OpenOrCreate, FileAccess.Write );

                        // menetapkan file tempat penulisan
                        penulisFile = new StreamWriter( keluaran );

                        // menon-aktifkan tombol Simpan dan mengaktifkan tombol Enter
                        simpanButton.Enabled = false;
                        enterButton.Enabled = true;
                    } // akhir try
                    // menangani eksepsi jika ada masalah pembukaan file
                    catch ( IOException )
                    {
                        // memberitahu pengguna jika file tidak ada
                        MessageBox.Show( "Error pembukaan file", "Error",
                            MessageBoxButtons.OK, MessageBoxIcon.Error );
                    } // akhir catch
                } // akhir else
            } // akhir if
        } // akhir metode simpanButton_Click

        //menangani event Click untuk enterButton
        private void enterButton_Click(object sender, EventArgs e)
        {
            // menyimpan nilai-nilai TextBox
            string[] nilai2 = GetNilaiTextBox();

            // Rekaman memuat nilai-nilai TextBox yang akan ditampilkan
            Rekaman rekaman = new Rekaman();

            // menentukan apakah bidang akun kosong
            if ( nilai2[ ( int ) IndeksTextBox.AKUN ] != string.Empty )
            {
                // menyimpan nilai-nilai TextBox dalam Rekaman dan menampilkannya
                try
                {
                    // mendapatkan nilai nomor-akun dari TextBox
                    int nomorAkun = Int32.Parse(
                        nilai2[(int)IndeksTextBox.AKUN]);

                    // menentukan apakah nomorAkun valid
                    if ( nomorAkun > 0 )
                    {
                        // menyimpan bidang-bidang TextBox di dalam Rekaman
                        rekaman.Akun = nomorAkun;
                            rekaman.NamaPertama = nilai2[ ( int )
                            IndeksTextBox.PERTAMA];
                        rekaman.NamaAkhir = nilai2[ ( int )
                            IndeksTextBox.AKHIR];
                        rekaman.Saldo = Decimal.Parse(
                            nilai2[(int)IndeksTextBox.SALDO]);

                        // menuliskan Rekaman ke file, bidang-bidang dipisahkan dengan koma
penulisFile.WriteLine(
    rekaman.Akun + "," + rekaman.NamaPertama + "," +
    rekaman.NamaAkhir + "," + rekaman.Saldo );
                    } // akhir if
                    else
                    {
                        // memberitahu pengguna jika nomor akun tak-valid
                        MessageBox.Show( "Nomor Akun Tak-Valid", "Error",
                            MessageBoxButtons.OK, MessageBoxIcon.Error );
                    } // akhir else
                } // akhir try
                // memberitahu pengguna jika error terjadi selama operasi penampilan
                catch ( IOException )
                {
                    MessageBox.Show( "Error Penulisan ke File", "Error",
                        MessageBoxButtons.OK, MessageBoxIcon.Error );
                } // akhir catch
                // memberitahu pengguna jika error terjadi akibat format parameter
                catch ( FormatException )
                {
                    MessageBox.Show( "Format Tak-Valid", "Error",
                    MessageBoxButtons.OK, MessageBoxIcon.Error );
                } // akhir catch
            } // akhir if

            BersihTextBox(); // membersihkan nilai-nilai TextBox
        } // akhir metode enterButton_Click

        // menangani event Click untuk keluarButton
        private void keluarButton_Click(object sender, EventArgs e)
        {
            // menentukan apakah file ada
            if ( penulisFile != null )
            {
                try
                {
                    // menutup StreamWriter
                    penulisFile.Close();
                } // akhir try
                // memberitahu pengguna tentang error penutupan file
                catch ( IOException )
                {
                    MessageBox.Show( "Tidak bisa membuka file", "Error",
                    MessageBoxButtons.OK, MessageBoxIcon.Error );
                } // akhir catch
            } // akhir if

            Application.Exit();
        } // akhir metode keluarButton_Click
    } // akhir kelas BankUIForm
} // akhir namespace PustakaBank




Kelas BankUIForm terperbarui menciptakan atau membuka sebuah file (tergantung dari apakah file ada atau tidak), kemudian memampukan pengguna untuk menuliskan rekaman-rekaman ke dalam file tersebut. GUI pada kelas ini sekarang memuat tombol Simpan, Enter, dan Keluar.

  
Metode simpanButton_Click
Ketika pengguna mengklik tombol Simpan, program akan memanggil event handler simpanButton_Click. Metode ini menginstansiasi sebuah objek dari kelas SaveFileDialog (namespace System.Windows.Form). Dengan menempatkan objek ini pada sebuah statemen using, Anda dapat memastikan bahwa metode Dispose dipanggil untuk melepaskan sumberdayanya setelah program membaca masukan dari pengguna. Objek-objek SaveFileDialog dipakai untuk memilih file. Baris 91 mengindikasikan bahwa dialog tidak memeriksa jika nama yang disediakan pengguna telah ada atau tidak. Baris 92 memanggil metode ShowDialog dari kelas SaveFileDialog untuk menampilkan dialog. Ketika ditampilkan, objek SaveFileDialog akan mencegah pengguna untuk berinteraksi dengan jendela lain pada program sampai pengguna menutup SaveFileDialog dengan mengklik Save atau Cancel. Pengguna memilih drive, direktori, dan nama file, kemudian mengklik Save. Metode SaveDialog menghasilkan sebuah objek DialogResult yang menetapkan tombol mana (Save atau Cancel) yang diklik pengguna untuk menutup dialog. Objek ini ditugaskan kepada variabel hasil pada baris 92. Baris 93 membaca nama file dari dialog. Baris 97 menguji apakah pengguna mengklik OK dengan membandingkan nilai ini dengan DialogResult.OK. Jika kedua nilai sama, metode simpanButton_Click akan berlanjut.

Anda dapat membuka file untuk melakukan pemanipulasian teks dengan menciptakan objek dari kelas FileStream. Pada contoh ini, Anda ingin file dibuka untuk ditampilkan, jadi baris 109-110 mencitptakan sebuah objek FileStream. Konstruktor FileStream yang digunakan menerima tiga argumen, yaitu sebuah string yang memuat path dan nama file yang akan dibuka, sebuah konstanta yang menjelaskan bagaimana membuka suatu file, dan sebuah konstanta yang menjelaskan ijin file. Konstanta FileMode.OperOrCreate (baris 110) mengindikasikan bahwa objek FileStream membuka file jika file itu ada atau menciptakan file jika ia belum ada. Perhatikan bahwa isi dari file yang sudah ada akan ditimpa oleh StreamWriter. Untuk mempertahankan isi asli dari sebuah file, Anda bisa menggunakan FileMode.Append. Ada beberapa konstanta FileMode lain yang menjelaskan bagaimana membuka file; Konstanta FileAccess.Write mengindikasikan bahwa program hanya dapat melakukan operasi penulisan dengan objek FileStream. Ada dua konstanta lain untuk parameter ketiga pada konstruktor, yaitu FileAccess.Read untuk akses read-only dan FileAccess.ReadWrite untuk akses pembacaan dan penulisan. Baris 120 menangkap sebuah eksepsi IOException jika terdapat masalah dalam pembukaan file atau penciptaan StreamWriter. Jika ya, program akan menampilkan sebuah pesan error (baris 123-124). Jika tidak ada terjadi eksepsi, maka file dapat dibuka untuk ditulis.

Metode enterButton_Click
Setelah mengetikkan informasi ke dalam tiap TextBox, pengguna mengklik tombol Enter, yang memanggil event handler enterButton_Click (baris 130-188) untuk menyimpan dari dari tiap TextBox ke dalam file yang dipilih pengguna. Jika pengguna memasukkan nomor akun yang valid (misalnya, integer yang lebih besar dari nol), maka baris 153-159 akan menyimpan nilai-nilai TextBox di dalam sebuah objek bertipe Rekaman (diciptakan pada baris 137). Jika pengguna memasukkan data yang tak-valid pada salah satu TextBox (misalnya, karakter tak-numerik pada bidang Saldo), maka program akan melemparkan sebuah eksepsi FormatException. Blok catch pada baris 180-184 akan menangani eksepsi semacam itu dengan memberitahu pengguna (melalui sebuah MessageBox).

Jika pengguna memasukkan data valid, maka baris 162-164 akan menulis rekaman ke dalam file dengan memanggil metode WriteLine dari objek StreamWriter yang diciptakan pada baris 113. Metode WriteLine menuliskan serangkaian karakter ke dalam sebuah file. Objek StreamWriter dikonstruksi dengan sebuah argumen FileStream yang menetapkan file tempat penulisan. Kelas StreamWriter berada di dalam namespace System.IO.

Metode keluarButton_Click
Ketika pengguna mengklik Keluar, maka event handler keluarButton_Click (baris 191-210) akan dieksekusi. Baris 199 menutup StreamWriter, yang secara otomatis menutup FileStream. Kemudian, baris 209 menghentikan program. Perhatikan bahwa metode Close dipanggil di dalam sebuah blok try. Metode Close akan melemparkan sebuah eksepsi IOException jika file atau aliran tidak dapat ditutup dengan benar. Pada kasus ini, adalah penting untuk memberitahu pengguna bahwa informasi di dalam file bisa jadi terkorupsi.


4.4 Membaca Data dari Sebuah File Teks Akses-Sekuensial
Pada bagian sebelumnya telah didemonstrasikan bagaimana menciptakan sebuah file agar dapat digunakan pada aplikasi-aplikasi akses-sekuensial. Pada bagian ini, Akan didiskusikan bagaimana membaca data secara sekuensial dari sebuah file. Kelas BacaFileAksesSekuensialForm (Gambar 4.9) membaca rekaman-rekaman yang dibaca dari file yang diciptakan oleh program pada Gambar 4.7, kemudian menampilkan isi tiap rekaman. Banyak bagian kode pada contoh ini mirip dengan yang ada pada Gambar 4.7, jadi yang akan dibahas hanya aspek-aspek unik dari aplikasi.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// Gambar 4.8: Rekaman.cs
// Kelas yang merepresentasikan sebuah rekaman data.

namespace BacaFileAksesSekuensial
{
    public class Rekaman
    {
// properti Akun implementasi-diri
public int Akun { get; set; }

// properti NamaPertama implementasi-diri
public string NamaPertama { get; set; }

// properti NamaAkhir implementasi-diri
public string NamaAkhir { get; set; }

// properti Saldo implementasi-diri
public decimal Saldo { get; set; }
       
        // konstruktor tanpa parameter menetapkan nilai-nilai default
        public Rekaman()
            : this( 0, string.Empty, string.Empty, 0M )
        {
        } // akhir konstruktor

        // konstruktor teroverload menetapkan nilai-nilai parameter
        public Rekaman( int nilaiAkun, string nilaiNamaPertama,
            string nilaiNamaAkhir, decimal nilaiSaldo )
        {
            Akun = nilaiAkun;
            NamaPertama = nilaiNamaPertama;
            NamaAkhir = nilaiNamaAkhir;
            Saldo = nilaiSaldo;
        } // akhir konstruktor
 } // akhir kelas Rekaman
} // akhir namespace BacaFileAksesSekuensial

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// Gambar 4.9: BacaFileAksesSekuensialForm.cs
// Membaca sebuah file akses-sekuensial.
using System;
using System.Windows.Forms;
using System.IO;

namespace BacaFileAksesSekuensial
{
    public partial class BacaFileAksesSekuensialForm : Form
    {
        protected int JumlahTextBox = 4; // jumlah TextBoxes pada Form
        private StreamReader pembacaFile; // membaca data dari file teks

        // konstanta-konstanta enumerasi untuk menetapkan indeks-indeks TextBox
        public enum IndeksTextBox
        {
            AKUN,
            PERTAMA,
            AKHIR,
            SALDO
        } // akhir enum

        // konstruktor tanpa-parameter
        public BacaFileAksesSekuensialForm()
        {
            InitializeComponent();
        } // akhir konstruktor tanpa-parameter

        // menghapus semua TextBox
        public void BersihTextBox()
        {
            // menjelajah setiap Control pada form
            foreach (Control guiControl in Controls)
            {
                // menentukan apakan Control adalah TextBox
                if (guiControl is TextBox)
                {
                    // menghapus TextBox
                    ((TextBox)guiControl).Clear();
                } // akhir if
            } // akhir for
        } // akhir metode BersihTextBox

        // menetapkan nilai-nilai TextBox menjadi nilai-nilai array string
        public void SetNilaiTextBox(string[] nilai2)
        {
            // menentukan apakah array string memiliki panjang yang tepat
            if (nilai2.Length != JumlahTextBox)
            {
                // melempar eksepsi jika panjang tidak tepat
                throw (new ArgumentException("Harus ada " +
                    (JumlahTextBox + 1) + " string pada array"));
            } // akhir if
            // menetapkan nilai-nilai array jika array memiliki panjang yang tepat
            else
            {
                // menetapkan nilai-nilai array menjadi nilai-nilai TextBox
                akunTextBox.Text =
                    nilai2[(int)IndeksTextBox.AKUN];
                namaPertamaTextBox.Text =
                    nilai2[(int)IndeksTextBox.PERTAMA];
                namaAkhirTextBox.Text = nilai2[(int)IndeksTextBox.AKHIR];
                akunTextBox.Text =
                    nilai2[(int)IndeksTextBox.SALDO];
            } // akhir else
        } // akhir metode SetNilaiTextBox

        //dipanggil ketika pengguna mengklik tombol Buka File
        private void bukaFileButton_Click(object sender, EventArgs e)
        {
            // menciptakan dan menampilkan kotak dialog untuk membaca file
            DialogResult hasil; // hasil dari SaveFileDialog
            string namaFile; // nama file yang memuat data

            using (OpenFileDialog pemilihFile = new OpenFileDialog())
            {
hasil = pemilihFile.ShowDialog();
namaFile = pemilihFile.FileName; // nama file untuk disimpan
            } // akhir using

            // memastikan bahwa pengguna mengklik "OK"
            if (hasil == DialogResult.OK)
            {
                BersihTextBox();

                // menampilkan error jika pengguna menetapkan file tak-valid
                if (namaFile == string.Empty)
                    MessageBox.Show("Nama Tak Valid", "Error",
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                else
                {
                    try
                    {
                        // menciptakan FileStream untuk mendapatkan akses membaca
FileStream masukan = new FileStream(
    namaFile, FileMode.Open, FileAccess.Read);

                        // menetapkan file tempat pembacaan
                        pembacaFile = new StreamReader(masukan);

                        // menon-aktifkan tombol Simpan dan mengaktifkan tombol Enter
                        bukaFileButton.Enabled = false;
                        rekamanBerikutnyaButton.Enabled = true;
                    } // akhir try
                    // menangani eksepsi jika ada masalah pembukaan file
                    catch (IOException)
                    {
                        // memberitahu pengguna jika file tidak ada
                        MessageBox.Show("Error pembacaan file", "Error",
                            MessageBoxButtons.OK, MessageBoxIcon.Error);
                    } // akhir catch
                } // akhir else
            } // akhir if
        } // akhir metode bukaFileButton_Click

        //dipanggil ketika pengguna mengklik tombol Rekaman Berikutnya
        private void rekamanBerikutnyaButton_Click(object sender, EventArgs e)
        {
            try
            {
                // mendapatkan rekaman berikutnya dari file
                string rekamanMasukan = pembacaFile.ReadLine();
                string[] bidangMasukan; // menyimpan potongan individual data

                if ( rekamanMasukan != null )
                {
                    bidangMasukan = rekamanMasukan.Split( ',' );

                    Rekaman rekaman = new Rekaman(
                        Convert.ToInt32( bidangMasukan[ 0 ] ), bidangMasukan[ 1 ],
                        bidangMasukan[ 2 ],
                        Convert.ToDecimal( bidangMasukan[ 3 ] ) );

                    // menyalin nilai-nilai array-string ke nilai-nilai TextBox
                    SetNilaiTextBox( bidangMasukan );
                } // akhir if
                else
                {
                    // menutup StreamReader
                    pembacaFile.Close();
                    bukaFileButton.Enabled = true; // mengaktifkan tombol Buka File
                   
                    // menonaktifkan tombol Rekaman Berikutnyan
                    rekamanBerikutnyaButton.Enabled = false;
                    BersihTextBox();

                    // memberitahu pengguna jika tidak ada rekaman di dalam
                    MessageBox.Show( "Tidak ada rekaman lagi di dalam file",
                        string.Empty, MessageBoxButtons.OK,
                        MessageBoxIcon.Information );
                } // akhir else
            } // akhir try
            catch ( IOException )
            {
                MessageBox.Show( "Error Pembacaan dari File", "Error",
                    MessageBoxButtons.OK, MessageBoxIcon.Error );
            } // akhir catch
        } // akhir metode rekamanBerikutnyaButton_Click
    } // akhir kelas BacaFileAksesSekuensialForm
} // akhir namespace BacaFileAksesSekuensial





Metode bukaFileButton_Click
Ketika pengguna mengklik tombol Buka File, program memanggil event handler bukaFileButton_Click. Baris 75 menciptakan suatu OpenFileDialog, dan baris 77 memanggil metode ShowDialog untuk menampilkan dialog Open. Watak dan GUI dari dialog Open dan Save indentik, kecuali bahwa dialog Save diganti dengan Open. Jika pengguna memilih suatu nama file yang valid, maka baris 95-96 akan menciptakan sebuah objek FileStream dan menugaskannya untuk mereferensi masukan. Anda melewatkan konstanta FileMode.Open sebagai argumen kedua kepada konstruktor FileStream untuk mengindikasikan bahwa FileStream harus membuka file jika file memang ada atau melemparkan eksepsi FileNotFoundException jika file tidak ada. Pada contoh ini, konstruktor FileStream tidak melempar eksepsi FileNotFoundException, karena OpenFileDialog dikonfigurasi untuk memeriksa apakah file ada atau tidak. Pada contoh terakhir (Gambar 4.7), Anda menuliskan teks ke dalam file menggunakan sebuah objek FileStream dengan akses write-only. Pada contoh ini, Anda menetapkan akses read-only terhadap file dengan melewatkan konstanta FileAccess.Read sebagai argumen ketiga pada konstruktor FileStream. Objek FileStream ini dipakai untuk menciptakan suatu objek StreamReader pada baris 99. Objek FileStream menetapkan file yang akan dibaca oleh objek StreamReader.

Metode rekamanBerikutnyaButton_Click
Ketika pengguna mengklik tombol Rekaman Berikutnya, program memanggil event handler rekamanBerikutnyaButton_Click (baris 117-158), yang membaca rekaman berikutnya dari file yang dipilih pengguna. Pengguna perlu mengklik tombol Rekaman Berikutnya setelah membuka file untuk melihat rekaman pertama. Baris 122 memanggil metode ReadLine dari kelas StreamReader untuk membaca rekaman berikutnya. Jika suatu error terjadi saat pembacaan file, maka eksepsi IOException akan dilemparkan (ditangkap pada baris 106). Sebaliknya, baris 125 akan menentukan apakah metode ReadLine menghasilkan null atau tidak (apakah masih ada teks di dalam file atau tidak). Jika tidak ada lagi, maka baris 77 menggunakan metode Split dari kelas string untuk memisahkan aliran karakter-karakter yang telah dibaca dari file menjadi string-string yang merepresentasikan properti-properti Rekaman. Semua properti ini kemudian diurutkan dengan mengkonstruksi suatu objek Rekaman menggunakan properti-properti sebagai argumen (baris 129-132). Baris 135 menampilkan nilai-nilai Rekaman pada setiap TextBox. Jika ReadLine menghasilkan null, maka program menutup objek StreamReader (baris 140), yang secara otomatis akan menutup objek FileStream, kemudian memberitahu pengguna bahwa tidak ada lagi rekaman (baris 148-150).

4.5 Studi Kasus: Program Kredit
Untuk membaca data secara sekuensial dari sebuah file, program biasanya memulai dari awal file, membaca secara berurutan sampai data yang diinginkan ditemukan. Hal ini biasanya diperlukan untuk memproses file (dari awal file) berulang kali selama eksekusi sebuah program. Sebuah objek FileStream dapat memposisikan-ulang pointernya. Ketika suatu objek FileStream dibuka, pointer posisi-filenya ditetapkan ke posisi byte 0 (awal file).

Sekarang akan disajikan suatu program yang memakai konsep-konsep yang diterapkan pada Gambar 4.9. Kelas KreditForm (Gambar 4.11) merupakan program kredit yang memampukan seorang manajer kredit untuk melakukan pencarian dan menampilkan informasi akun bagi para konsumen (yaitu konsumen yang menyimpan uangnya pada perusahaan (saldo kredit), konsumen yang tidak memiliki hutang (saldo nol), dan konsumen yang memiliki hutang (saldo debit)).

Anda akan menggunakan sebuah RichTextBox pada program untuk menampilkan informasi akun. RichTextBox menyediakan fungsionalitas yang lebih daripada TextBox biasa. Sebagai contoh, RichTextBox menawarkan metode Find untuk melakukan pencarian string dan metode LoadFile untuk menampilkan isi file. Kedua kelas TextBox dan RichTextBox mewarisi kelas System.Windows.Forms.TextBoxBase. Pada contoh ini, Anda memilih RichTextBox, karena ia menampilkan beberapa baris teks secara default, sedangkan TextBox biasa hanya menampilkan satu baris secara default. Tetapi, sebenarnya Anda bisa saja menetapkan objek TextBox untuk menampilkan baris jamak dengan mengatur properti Multiline-nya menjadi true.

Program menampilkan tombol-tombol yang memampukan seorang manajer kredit untuk mendapatkan informasi kredit. Tombol Buka File membuka sebuah file. Tombol Saldo Kredit untuk menampilkan daftar akun yang memiliki saldo kredit, tombol Saldo Debit untuk menampilkan daftar akun yang memiliki saldo debit, dan tombol Saldo Nol untuk menampilkan daftar akun yang memiliki saldo nol. Tombol Selesai akan menghentikan aplikasi.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// Gambar 4.10: Rekaman.cs
// Kelas yang merepresentasikan sebuah rekaman data.

namespace Kredit
{
    public class Rekaman
    {
// properti Akun implementasi-diri
public int Akun { get; set; }

// properti NamaPertama implementasi-diri
public string NamaPertama { get; set; }

// properti NamaAkhir implementasi-diri
public string NamaAkhir { get; set; }

// properti Saldo implementasi-diri
public decimal Saldo { get; set; }
       
        // konstruktor tanpa parameter menetapkan nilai-nilai default
        public Rekaman()
            : this( 0, string.Empty, string.Empty, 0M )
        {
        } // akhir konstruktor

        // konstruktor teroverload menetapkan nilai-nilai parameter
        public Rekaman( int nilaiAkun, string nilaiNamaPertama,
            string nilaiNamaAkhir, decimal nilaiSaldo )
        {
            Akun = nilaiAkun;
            NamaPertama = nilaiNamaPertama;
            NamaAkhir = nilaiNamaAkhir;
            Saldo = nilaiSaldo;
        } // akhir konstruktor
 } // akhir kelas Rekaman
} // akhir namespace Kredit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
// Gambar 4.11: KreditForm.cs
// Membaca sebuah file secara sekuensial dan menampilkan isinya
// berdasarkan tipe akun yang ditetapkan pengguna.
using System;
using System.Windows.Forms;
using System.IO;

namespace Kredit
{
    public partial class KreditForm : Form
    {
        private FileStream masukan; // menetapkan koneksi ke file
        private StreamReader pembacaFile; // membaca data dari file teks

        // nama file yang menyimpan saldo kredit, saldo debit, dan saldo nol
        private string namaFile;

        // konstruktor tanpa-parameter
        public KreditForm()
        {
            InitializeComponent();
        }

        // menangani event jika tombol Buka File diklik
        private void bukaButton_Click(object sender, EventArgs e)
        {
             // menciptakan kotak dialog untuk membuka file
            DialogResult hasil;

            using ( OpenFileDialog pemilihFile = new OpenFileDialog() )
            {
hasil = pemilihFile.ShowDialog();
namaFile = pemilihFile.FileName;
            } // akhir using

            // keluar dari event handler jika pengguna mengklik Cancel
            if ( hasil == DialogResult.OK )
            {
                // menampilkan error jika pengguna menetapkan file tak-valid
                if ( namaFile == string.Empty )
                    MessageBox.Show( "Nama File Tak-Valid", "Error",
                        MessageBoxButtons.OK, MessageBoxIcon.Error );
                else
                {
                    // menciptakan FileStream untuk mendapatkan akses baca
masukan = new FileStream( namaFile,
    FileMode.Open, FileAccess.Read );

                    // menetapkan file dari mana data dibaca
                    pembacaFile = new StreamReader( masukan );

                    // mengaktifkan semua tombol, kecuali tombol Buka File
                    bukaButton.Enabled = false;
                    kreditButton.Enabled = true;
                    debitButton.Enabled = true;
                    nolButton.Enabled = true;
                } // akhir else
            } // akhir if
        } // akhir metode bukaButton_Click

        // dipanggil ketika tombol Saldo Kredit, Saldo Debit,
        // dan Saldo Nol diklik pengguna
        private void getSaldo_Click(object sender, EventArgs e)
        {
             // mengkonversi sender secara eksplisit menjadi objek dengan tipe tombol
            Button tombolSender = ( Button ) sender;

            // mendapatkan teks dari Button yang diklik, yang menyimpan tipe akun
            string tipeAkun = tombolSender.Text;

            // membaca dan menampilkan informasi file
            try
            {
                // kembali ke awal file
                masukan.Seek( 0, SeekOrigin.Begin );

                tampilTextBox.Text = "Akun adalah:\r\n";

                // menjelajah file sampai akhir file
                while ( true )
                {
                    string[] bidangMasukan; // menyimpan potongan data individual
                    Rekaman rekaman; // menyimpan setiap Rekaman ketika file dibaca
                    decimal saldo; // menyimpan saldo tiap Rekaman
                    // mendapatkan rekamanBerikutnya pada file
                    string rekamanMasukan = pembacaFile.ReadLine();

                    // di akhir file, keluar metode
                    if ( rekamanMasukan == null )
                        return;

                    bidangMasukan = rekamanMasukan.Split( ',' ); // memecah masukan

                    // menciptakan Rekaman dari masukan
                    rekaman = new Rekaman(
                        Convert.ToInt32( bidangMasukan[ 0 ] ), bidangMasukan[ 1 ],
                        bidangMasukan[ 2 ], Convert.ToDecimal(bidangMasukan[ 3 ]));

                    // menyimpan bidang terakhir pada saldo
                    saldo = rekaman.Saldo;

                    // menentukan apakah menampilkan saldo
                    if (HarusTampil(saldo, tipeAkun))
                    {
                        // menampilkan rekaman
                        string keluaran = rekaman.Akun + "\t\t" +
                            rekaman.NamaPertama + "\t\t" +
                                rekaman.NamaAkhir + "\t\t";

                        // menampilkan saldo dengan format moneter
                        keluaran += String.Format( "{0:F}", saldo ) + "\r\n";

                        // menyalin keluaran pada layar
                        tampilTextBox.AppendText( keluaran );
                    } // akhir if
                } // akhir while
            } // akhir try
            // handle exception when file cannot be read
            catch ( IOException )
            {
                MessageBox.Show( "Tidak dapat membaca file", "Error",
                    MessageBoxButtons.OK, MessageBoxIcon.Error );
            } // akhir catch
        } // akhir metode getSaldo_Click

        // menentukan apakah menampilkan rekaman atau tidak
        private bool HarusTampil(decimal saldo, string tipeAkun)
        {
            if ( saldo > 0M )
            {
                // menampilkan saldo kredit
                if ( tipeAkun == "Saldo Kredit" )
                    return true;
            } // akhir if
            else if ( saldo < 0M )
            {
                // menampilkan saldo debit
                if ( tipeAkun == "Saldo Debit" )
                    return true;
            } // akhir else if
            else // saldo == 0
            {
                // menampilkan saldo nol
                if ( tipeAkun == "Saldo Nol" )
                    return true;
            } // akhir else

            return false;
        } // akhir metode harusTampil

        //dipanggil ketika tombol Selesai diklik
        private void selesaiButton_Click(object sender, EventArgs e)
        {
            if ( masukan != null )
            {
                // menutup file dan StreamReader
                try
                {
                    // menutup StreamReader
                    pembacaFile.Close();
                } // akhir try
                // menangani eksepsi jika FileStream tidak ada
                catch ( IOException )
                {
                    // memberitahu pengguna ttg error penutupan file
                    MessageBox.Show( "Tidak dapat menutup file", "Error",
                        MessageBoxButtons.OK, MessageBoxIcon.Error );
                } // akhir catch
            } // akhir if

            Application.Exit();
        } // akhir metode selesaiButton_Click
    }
}



Ketika pengguna mengklik tombol Buka File, program memanggil event handler bukaTombol_Click (baris 24-59). Baris 30 menciptakan sebuah OpenFileDialog, dan baris 32 memanggil metode ShowDialog untuk menampilkan dialog Open, dimana di dalamnya pengguna memilih file yang akan dibuka. Baris 46-47 menciptakan sebuah objek FileStream dengan akses read-only dan menugaskannya kepada referensi masukan. Baris 50 menciptakan sebuah objek StreamReader yang Anda gunakan untuk membaca teks dari FileStream.

Ketika pengguna mengkli tombol Saldo Kredit, Saldo Debit, atau Saldo Nol, program akan memanggil metode getSaldo_Click (baris 63-124). Baris 66 mengkonversi paksa parameter sender, yang merupakan sebuah referensi object yang menunjuk ke kendali yang dibangkitkan oleh event, menjadi sebuah objek Button. Baris 69 mengekstrak teks pada objek Tombol, yang dipakai program untuk menentukan apa tipe akun. Baris 75 menggunakan metode Seek dari kelas FileStream untuk mereset pointer kembali ke awal file. Metode Seek ini memampukan Anda untuk memposisikan-ulang pointer dengan menetapkan jumlah byte (dari awal file, dari akhir file, atau dari posisi sekarang). Konstanta enumerasi SeekOrigin.Begin untuk menetapkan pointer ke awal file. Baris 80-116 mendefiniskan sebuah loop while yang menggunakan metode HarusTampil (baris 127-149) untuk menentukan apakah menampilkan setiap rekaman pada file. Loop while membaca setiap rekaman secara berulang dengan memanggil metode ReadLine dari kelas StreamReader (baris 87) dan memecah teks menjadi token-token (baris 92) yang dipakai untuk menginisialisasi objek rekaman (baris 95-97). Baris 89 menentukan apakah pointer telah meraih akhir file atau tidak. Jika pointer telah meraih akhir file, maka ReadLine menghasilkan null. Dengan demikian, program akan keluar dari metode getSaldo_Click (baris 90).



4.6 Serialisasi
Telah didemonstrasikan bagaimana menuliskan bidang-bidang individual dari sebuah objek Rekaman ke suatu file teks dan telah didemonstrasikan bagaimana membaca bidang-bidang itu dari suatu file dan menempatkan nilai-nilainya di dalam suatu objek Rekaman pada memori. Pada contoh-contoh itu, Rekaman dipakai untuk mengumpulkan informasi pada tiap rekaman. Ketika variabel-variabel instans untuk sebuah objek Rekaman dituliskan ke file, informasi tertentu akan hilang, seperti tipe data dari tiap nilai. Sebagai contoh, jika nilai “3” dibaca dari sebuah file, maka tidak diketahui apakah nilai itu berasal dari sebuah int, string, atau decimal. Yang dimiliki hanya data, bukan tipe informasi, pada media penyimpanan. Jika program yang membaca data ini mengetahui tipe objek apa dari data terkait, maka data tersebut dapat dibaca secara langsung. Sebagai contoh, pada contoh sebelumnya, Anda telah mengetahui bahwa Anda menempatkan sebuah int (nomor akun), diikuti dengan dua string (nama pertama dan nama akhir) dan sebuah decimal (saldo). Anda juga mengetahui bahwa nilai-nilai ini dipisahkan dengan koma, dengan satu rekaman per baris. Jadi, Anda dapat mengkonversi string-string dan mengkonversi nomor akun menjadi int dan saldo menjadi decimal.

C# menyediakan mekanisme, yang dikenal dengan serialisasi objek. Objek terserialkan merupakan sebuah objek yang direpresentasikan sebagai suatu runtun byte yang memuat data objek, berikut dengan informasi tentang tipe objek dan tipe data yang disimpan di dalam objek. Setelah objek terserialkan ditulis ke dalam sebuah file, ia dapat dibaca dari file dan dideserialisasi. Dengan demikian, informasi tipe dan byte-byte yang merepresentasikan objek dan datanya dapat dipakai untuk menciptakan-ulang objek di dalam memori.

Kelas BinaryFormatter (namespace System.Runtime.Serialization.Formatters.Binary) memampukan semua objek ditulis ke atau dibaca dari sebuah aliran. Metode Serialize dari kelas BinaryFormatter menuliskan suatu representasi objek ke file. Metode Deserialize dari kelas BinaryFormatter membaca representasi ini dari file dan mengkonstruksi objek semula. Kedua metode itu melemparkan eksepsi SerializationException jika error terjadi selama serialisasi atau deserialisasi. Kedua metode itu memerlukan sebuah objek Stream (misalnya, FileStream) sebagai parameter sehingga BinarryFormatter dapat mengakses aliran yang benar.

4.7 Menciptakan File Akses-Sekuensial Menggunakan Serialisasi Objek
Akan dimulai dengan menciptakan dan menulis objek-objek terserialkan ke sebuah file akses-sekuensial. Pada bagian ini, Anda akan mendaur-ulang kode dari bagian 4.3, sehingga Anda hanya fokus pada fitur-fitur baru.

Mendefiniskan Kelas RekamanTerserialkan
Akan dimulai dengan memodifikasi kelas Rekaman sehingga objek-objek dari kelas ini dapat diserialkan. Kelas RekamanTerserialkan (Gambar 4.12) dibubuhi atribut [Serializable] pada baris 7, yang mengindikasikan bahwa objek-objek dari kelas RekamanTerserialkan dapat diserialkan. Kelas-kelas untuk objek-objek yang akan menulis ke atau membaca dari suatu aliran harus mencantumkan atribut ini pada deklarasinya atau harus mewarisi implementasi ISerializable.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// Gambar 4.12: RekamanTerserialkan.cs
// Kelas yang merepresentasikan sebuah rekaman data.
using System;

namespace CiptakanFileTerserialkan
{
    [Serializable]
    public class RekamanTerserialkan
    {
        // properti Akun implementasi-diri
        public int Akun { get; set; }

        // properti NamaPertama implementasi-diri
        public string NamaPertama { get; set; }

        // properti NamaAkhir implementasi-diri
        public string NamaAkhir { get; set; }

        // properti Saldo implementasi-diri
        public decimal Saldo { get; set; }

        // konstruktor tanpa parameter menetapkan nilai-nilai default
        public RekamanTerserialkan()
            : this(0, string.Empty, string.Empty, 0M)
        {
        } // akhir konstruktor

        // konstruktor teroverload menetapkan nilai-nilai parameter
        public RekamanTerserialkan(int nilaiAkun, string nilaiNamaPertama,
            string nilaiNamaAkhir, decimal nilaiSaldo)
        {
            Akun = nilaiAkun;
            NamaPertama = nilaiNamaPertama;
            NamaAkhir = nilaiNamaAkhir;
            Saldo = nilaiSaldo;
        } // akhir konstruktor
    } // akhir kelas RekamanTerserialkan
} // akhir namespace CiptakanFileTerserialkan

Pada sebuah kelas yang membubuhkan atribut [Serializable] atau yang mengimplamentasikan antarmuka ISerializable, Anda perlu memastikan bahwa setiap variabel instans dari kelas itu juga serializable. Semua variabel tipe-sederhana dan string juga serializable. Untuk variabel bertipe referensi, Anda perlu memeriksa deklarasi kelas untuk memastikan bahwa tipe tersebut terserialkan. Secara default, objek array adalah serializable.


Menggunakan Aliran Serialisasi untuk Menciptakan File
Selanjutnya, akan diciptakan sebuah file akses-sekuensial dengan serialisasi (Gambar 4.13). Untuk menguji program ini, digunakan data yang sama pada contoh sebelumnya untuk menciptakan file. Baris 14 menciptakan sebuah objek BinaryFormatter untuk menuliskan objek-objek terserialkan. Baris 112-113 membuka FileStream, sehingga program dapat menuliskan objek-objek terserialkan ke dalamnya. Argumen string yang dilewatkan kepada konstruktor FileStream merepresentasikan nama dan path dari file yang akan dibuka.

Program ini mengasumsikan bahwa data dituliskan secara benar dan dengan urutan yang sesuai dengan nomor-rekaman. Event handler enterButton_Click (baris 131-186) melakukan operasi penulisan. Baris 137 menciptakan sebuah objek RekamanTerserialkan, yang ditugasi nilai-nilai pada baris 153-159. Baris 162 memanggil metode Serialize untuk menuliskan objek RekamanTerserialkan ke file keluaran. Metode Serialize memerlukan objek FileStream sebagai argumen pertama sehingga BinaryFormatter dapat munuliskan argumen keduanya ke file yang tepat. Hanya satu statemen yang diperlukan untuk keseluruhan objek. Jika terjadi masalah selama serialisasi, eksepsi SerializationException akan dilemparkan, yang ditangkap pada baris 178-182.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
// Gambar 4.13: CiptakanFileTerserialkan.cs
// Menciptakan sebuah file akses-sekuensial dengan serialisasi.
using System;
using System.Windows.Forms;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;

namespace CiptakanFileTerserialkan
{
    public partial class CiptakanFileTerserialkanForm : Form
    {
        protected int JumlahTextBox = 4; // jumlah TextBoxes pada Form
        private BinaryFormatter formatter = new BinaryFormatter();
        private FileStream keluaran; // aliran untuk menuliskan ke file

        // konstanta-konstanta enumerasi untuk menetapkan indeks-indeks TextBox
        public enum IndeksTextBox
        {
            AKUN,
            PERTAMA,
            AKHIR,
            SALDO
        } // akhir enum

        // konstruktor tanpa-parameter
        public CiptakanFileTerserialkanForm()
        {
            InitializeComponent();
        } // akhir konstruktor tanpa-parameter

        // menghapus semua TextBox
        public void BersihTextBox()
        {
            // menjelajah setiap Control pada form
            foreach (Control guiControl in Controls)
            {
                // menentukan apakan Control adalah TextBox
                if (guiControl is TextBox)
                {
                    // menghapus TextBox
                    ((TextBox)guiControl).Clear();
                } // akhir if
            } // akhir for
        } // akhir metode BersihTextBox

        // menetapkan nilai-nilai TextBox menjadi nilai-nilai array string
        public void SetNilaiTextBox(string[] nilai2)
        {
            // menentukan apakah array string memiliki panjang yang tepat
            if (nilai2.Length != JumlahTextBox)
            {
                // melempar eksepsi jika panjang tidak tepat
                throw (new ArgumentException("Harus ada " +
                    (JumlahTextBox + 1) + " string pada array"));
            } // akhir if
            // menetapkan nilai-nilai array jika array memiliki panjang yang tepat
            else
            {
                // menetapkan nilai-nilai array menjadi nilai-nilai TextBox
                akunTextBox.Text =
                    nilai2[(int)IndeksTextBox.AKUN];
                namaPertamaTextBox.Text =
                    nilai2[(int)IndeksTextBox.PERTAMA];
                namaAkhirTextBox.Text = nilai2[(int)IndeksTextBox.AKHIR];
                akunTextBox.Text =
                    nilai2[(int)IndeksTextBox.SALDO];
            } // akhir else
        } // akhir metode SetNilaiTextBox

        // menghasilkan nilai-nilai TextBox sebagai array string
        public string[] GetNilaiTextBox()
        {
            string[] nilai2 = new string[JumlahTextBox];

            // menyalin semua bidang TextBox ke array string
            nilai2[(int)IndeksTextBox.AKUN] = akunTextBox.Text;
            nilai2[(int)IndeksTextBox.PERTAMA] = namaPertamaTextBox.Text;
            nilai2[(int)IndeksTextBox.AKHIR] = namaAkhirTextBox.Text;
            nilai2[(int)IndeksTextBox.SALDO] = saldoTextBox.Text;

            return nilai2;
        } // akhir metode GetNilaiTextBox

        // menangani event Click untuk simpanButton
        private void simpanButton_Click(object sender, EventArgs e)
        {
            // menciptakan dan menampilkan kotak dialog untuk menyimpan file
            DialogResult hasil; // hasil dari SaveFileDialog
            string namaFile; // nama file yang memuat data

            using (SaveFileDialog pemilihFile = new SaveFileDialog())
            {
                pemilihFile.CheckFileExists = false; // menciptakan file
                hasil = pemilihFile.ShowDialog();
                namaFile = pemilihFile.FileName; // nama file untuk disimpan
            } // akhir using

            // memastikan bahwa pengguna mengklik "OK"
            if (hasil == DialogResult.OK)
            {
                // menampilkan error jika pengguna menetapkan file tak-valid
                if (namaFile == string.Empty)
                    MessageBox.Show("Nama Tak Valid", "Error",
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                else
                {
                    // menyimpan file via FileStream jika pengguna menetapkan file valid
                    try
                    {
                        // membuka file dengan akses write
keluaran = new FileStream(namaFile,
    FileMode.OpenOrCreate, FileAccess.Write);

                        // menon-aktifkan tombol Simpan dan mengaktifkan tombol Enter
                        simpanButton.Enabled = false;
                        enterButton.Enabled = true;
                    } // akhir try
                    // menangani eksepsi jika ada masalah pembukaan file
                    catch (IOException)
                    {
                        // memberitahu pengguna jika file tidak ada
                        MessageBox.Show("Error pembukaan file", "Error",
                            MessageBoxButtons.OK, MessageBoxIcon.Error);
                    } // akhir catch
                } // akhir else
            } // akhir if
        } // akhir metode simpanButton_Click

        // menangani event Click untuk enterButton
        private void enterButton_Click(object sender, EventArgs e)
        {
            // menyimpan nilai-nilai TextBox
            string[] nilai2 = GetNilaiTextBox();

            // RekamanTerserialkan memuat nilai-nilai TextBox untuk diserialkan
            RekamanTerserialkan rekaman = new RekamanTerserialkan();

            // menentukan apakah bidang akun kosong
            if (nilai2[(int)IndeksTextBox.AKUN] != string.Empty)
            {
                // menyimpan nilai-nilai TextBox dalam RekamanTerserialkan dan menyerialkannya
                try
                {
                    // mendapatkan nilai nomor-akun dari TextBox
                    int nomorAkun = Int32.Parse(
                        nilai2[(int)IndeksTextBox.AKUN]);

                    // menentukan apakah nomorAkun valid
                    if (nomorAkun > 0)
                    {
                        // menyimpan bidang-bidang TextBox di dalam Rekaman
                        rekaman.Akun = nomorAkun;
                        rekaman.NamaPertama = nilai2[(int)
                        IndeksTextBox.PERTAMA];
                        rekaman.NamaAkhir = nilai2[(int)
                            IndeksTextBox.AKHIR];
                        rekaman.Saldo = Decimal.Parse(
                            nilai2[(int)IndeksTextBox.SALDO]);

                        // menuliskan RekamanTerserialkan ke FileStream
                        formatter.Serialize(keluaran, rekaman);
                    } // akhir if
                    else
                    {
                        // memberitahu pengguna jika nomor akun tak-valid
                        MessageBox.Show("Nomor Akun Tak-Valid", "Error",
                            MessageBoxButtons.OK, MessageBoxIcon.Error);
                    } // akhir else
                } // akhir try
                // memberitahu pengguna jika error terjadi selama operasi penampilan
                catch (SerializationException)
                {
                    MessageBox.Show("Error Penulisan ke File", "Error",
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                } // akhir catch
                // memberitahu pengguna jika error terjadi akibat format parameter
                catch (FormatException)
                {
                    MessageBox.Show("Format Tak-Valid", "Error",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                } // akhir catch
            } // akhir if

            BersihTextBox(); // membersihkan nilai-nilai TextBox
        } // akhir metode enterButton_Click

        // event handler untuk tombol Keluar
        private void keluarButton_Click(object sender, EventArgs e)
        {
            // menentukan apakah file ada
            if (keluaran != null)
            {
                try
                {
                    // menutup FileStream
                    keluaran.Close();
                } // akhir try
                // memberitahu pengguna tentang error penutupan file
                catch (IOException)
                {
                    MessageBox.Show("Tidak bisa membuka file", "Error",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                } // akhir catch
            } // akhir if

            Application.Exit();
        } // akhir metode keluarButton_Click
    } // akhir kelas CiptakanFileTerserialkanForm
} // akhir namespace CiptakanFileTerserialkan




4.8 Membaca dan Mendeserialisasi Data dari File Biner
Gambar 4.15 membaca dan menampilkan isi dari file yang diciptakan oleh program pada Gambar 4.13. Program ini menciptakan objek BinaryFormatter yang akan dipakai untuk membaca objek. Program membuka file dengan menciptakan sebuah objek FileStream. Nama file yang akan dibuka ditetapkan sebagai argumen pertama kepada konstruktor FileStream.

Program membaca objek-objek dari sebuah file pada event handler rekamanBerikutnyaButton_Click. Anda menggunakan metode Deserialize (dari BinaryFormatter yang diciptakan) untuk membaca data. Perhatikan bahwa Anda mengkonversi paksa (cast) hasil dari Deserialize menjadi tipe RekamanTerserialkan. Hal ini diperlukan, karena Deserialize menghasilkan sebuah referensi dari tipe object dan Anda perlu mengakses properti-properti yang ada pada kelas Rekaman-Terserialkan. Jika error terjadi selama serialisasi, maka eksepsi SerializationException akan dilemparkan, dan objek FileStream akan ditutup.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// Gambar 4.14: RekamanTerserialkan.cs
// Kelas yang merepresentasikan sebuah rekaman data.
using System;

namespace CiptakanFileTerserialkan
{
    [Serializable]
    public class RekamanTerserialkan
    {
        // properti Akun implementasi-diri
        public int Akun { get; set; }

        // properti NamaPertama implementasi-diri
        public string NamaPertama { get; set; }

        // properti NamaAkhir implementasi-diri
        public string NamaAkhir { get; set; }

        // properti Saldo implementasi-diri
        public decimal Saldo { get; set; }

        // konstruktor tanpa parameter menetapkan nilai-nilai default
        public RekamanTerserialkan()
            : this(0, string.Empty, string.Empty, 0M)
        {
        } // akhir konstruktor

        // konstruktor teroverload menetapkan nilai-nilai parameter
        public RekamanTerserialkan(int nilaiAkun, string nilaiNamaPertama,
            string nilaiNamaAkhir, decimal nilaiSaldo)
        {
            Akun = nilaiAkun;
            NamaPertama = nilaiNamaPertama;
            NamaAkhir = nilaiNamaAkhir;
            Saldo = nilaiSaldo;
        } // akhir konstruktor
    } // akhir kelas RekamanTerserialkan
} // akhir namespace BacaFileTerserialkan

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// Gambar 4.15: BacaFileTerserialkanForm.cs
// Membaca sebuah file akses-sekuensial dengan deserialisasi.
using System;
using System.Windows.Forms;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;

namespace BacaFileTerserialkan
{
    public partial class BacaFileTerserialkanForm : Form
    {
        protected int JumlahTextBox = 4; // jumlah TextBoxes pada Form
        // objek untuk deserialisasi RekamanTerserialkan dalam format biner
        private BinaryFormatter pembaca = new BinaryFormatter();
        private FileStream masukan; // aliran untuk pembacaan file

        // konstanta-konstanta enumerasi untuk menetapkan indeks-indeks TextBox
        public enum IndeksTextBox
        {
            AKUN,
            PERTAMA,
            AKHIR,
            SALDO
        } // akhir enum

        // konstruktor tanpa-parameter
        public BacaFileTerserialkanForm()
        {
            InitializeComponent();
        } // akhir konstruktor

        // menghapus semua TextBox
        public void BersihTextBox()
        {
            // menjelajah setiap Control pada form
            foreach (Control guiControl in Controls)
            {
                // menentukan apakan Control adalah TextBox
                if (guiControl is TextBox)
                {
                    // menghapus TextBox
                    ((TextBox)guiControl).Clear();
                } // akhir if
            } // akhir for
        } // akhir metode BersihTextBox

        // menetapkan nilai-nilai TextBox menjadi nilai-nilai array string
        public void SetNilaiTextBox(string[] nilai2)
        {
            // menentukan apakah array string memiliki panjang yang tepat
            if (nilai2.Length != JumlahTextBox)
            {
                // melempar eksepsi jika panjang tidak tepat
                throw (new ArgumentException("Harus ada " +
                    (JumlahTextBox + 1) + " string pada array"));
            } // akhir if
            // menetapkan nilai-nilai array jika array memiliki panjang yang tepat
            else
            {
                // menetapkan nilai-nilai array menjadi nilai-nilai TextBox
                akunTextBox.Text =
                    nilai2[(int)IndeksTextBox.AKUN];
                namaPertamaTextBox.Text =
                    nilai2[(int)IndeksTextBox.PERTAMA];
                namaAkhirTextBox.Text = nilai2[(int)IndeksTextBox.AKHIR];
                akunTextBox.Text =
                    nilai2[(int)IndeksTextBox.SALDO];
            } // akhir else
        } // akhir metode SetNilaiTextBox

        //dipanggil ketika pengguna mengklik tombol Buka File
        private void bukaFileButton_Click(object sender, EventArgs e)
        {
            // menciptakan dan menampilkan kotak dialog untuk membaca file
            DialogResult hasil; // hasil dari SaveFileDialog
            string namaFile; // nama file yang memuat data

            using (OpenFileDialog pemilihFile = new OpenFileDialog())
            {
                hasil = pemilihFile.ShowDialog();
                namaFile = pemilihFile.FileName; // nama file untuk disimpan
            } // akhir using

            // memastikan bahwa pengguna mengklik "OK"
            if (hasil == DialogResult.OK)
            {
                BersihTextBox();

                // menampilkan error jika pengguna menetapkan file tak-valid
                if (namaFile == string.Empty)
                    MessageBox.Show("Nama Tak Valid", "Error",
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                else
                {
                    // menciptakan FileStream untuk mendapatkan akses baca
                    masukan = new FileStream(
                        namaFile, FileMode.Open, FileAccess.Read );

                    // menon-aktifkan tombol Simpan dan mengaktifkan tombol Enter
                    bukaFileButton.Enabled = false;
                    rekamanBerikutnyaButton.Enabled = true;
                } // akhir else
            } // akhir if
        } // akhir metode bukaFileButton_Click

        //dipanggil ketika pengguna mengklik tombol Rekaman Berikutnya
        private void rekamanBerikutnyaButton_Click(object sender, EventArgs e)
        {
            try
            {
                // mendapatkan RekamanTerserialkan berikutnya pada file
                RekamanTerserialkan rekaman =
                    (RekamanTerserialkan) pembaca.Deserialize(masukan);

                // menyimpan nilai-nilai RekamanTerserialkan pada array string sementara
                string[] nilai2 = new string[] {
                    rekaman.Akun.ToString(),
                    rekaman.NamaPertama.ToString(),
                    rekaman.NamaAkhir.ToString(),
                    rekaman.Saldo.ToString()
                };

                // menyalin nilai-nilai array-string ke nilai-nilai TextBox
                SetNilaiTextBox( nilai2 );
            } // akhir try
            // menangani eksepsi ketika tidak ada RekamanTerserialkan pada file
            catch ( SerializationException )
            {
                masukan.Close(); // menutup FileStream
                bukaFileButton.Enabled = true; // mengaktifkan tombol Buka File
                // menonaktifkan tombol Rekaman Berikutnya
                rekamanBerikutnyaButton.Enabled = false;
                BersihTextBox();

                // memberitahu pengguna jika tidak ada RekamanTerserialkan pada file
                MessageBox.Show( "Tidak ada rekaman lain pada file", string.Empty,
                    MessageBoxButtons.OK, MessageBoxIcon.Information );
            } // akhir catch
        } // akhir metode rekamanBerikutnyaButton_Click
    } // akhir kelas BacaFileTerserialkanForm
} akhir namespace BacaFileTerserialkan






No comments:

Post a Comment