Program komputer bisa berguna jika
ia bisa berinteraksi dengan dunia lain. Interaksi di sini maksudnya
input/output atau I/O. Pada bab ini, kita akan melihat input output pada file
dan koneksi jaringan (network). Pada Java, input/output pada file dan jaringan
dilakukan berdasarkan aliran (stream), di mana semua objek dapat melakukan
perintah I/O yang sama. Standar output (System.out) dan standar input (System.in) adalah contoh aliran.
Untuk bekerja dengan file dan jaringan,
kita membutuhkan pengetahuan tentang pengecualian, yang telah dibahas sebelumnya. Banyak subrutin yang digunakan untuk bekerja dengan I/O
melemparkan pengecualian yang wajib ditangani. Artinya subrutin tersebut harus
dipanggil di dalam pernyataan try ... catch sehingga pengecualian yang terjadi bisa ditangani dengan
baik.
Stream, Reader, dan Writer
Tanpa bisa berinteraksi dengan dunia
lain, suatu program tidak ada gunanya. Interaksi suatu program dengan dunia
lain sering disebut input/output atau I/O. Sejak
dulu, salah satu tantangan terbesar untuk mendesain bahasa pemrograman baru
adalah mempersiapkan fasilitas untuk melakukan input dan output. Komputer bisa
terhubung dengan beragam jenis input dan output dari berbagai perangkat. Jika
bahasa pemrograman harus dibuat secara khusus untuk setiap jenis perangkat,
maka kompleksitasnya akan tak lagi bisa ditangani.
Salah satu kemajuan terbesar dalam
sejarah pemrograman adalah adanya konsep (atau abstraksi) untuk memodelkan
perangkat I/O. Dalam Java, abstraksi ini disebut dengan aliran (stream). Bagian
ini akan memperkenalkan tentang aliran, akan tetapi tidak menjelaskan dengan
komplit. Untuk lebih lengkapnya, silakan lihat dokumen resmi Java.
Ketika berhubungan dengan
input/output, kita harus ingat bahwa ada dua kategori data secara umum : data
yang dibuat oleh mesin, dan data yang bisa dibaca manusia. Data yang dibuat
mesin ditulis dengan model yang sama dengan bagaimana data tersebut disimpan di
dalam komputer, yaitu rangkaian nol dan satu. Data yang bisa dibaca manusia
adalah data dalam bentuk rangkaian huruf. Ketika kita membaca suatu bilangan
3.13159, kita membacanya sebagai rangkaian huruf yang kita terjemahkan sebagai
angka. Angka ini akan ditulis dalam komputer sebagai rangkaian bit yang kita
tidak mengerti.
Untuk menghadapi kedua jenis data
ini, Java memiliki dua kategori besar untuk aliran : aliran
byte untuk data mesin (byte stream), dan aliran
karakter (character stream) untuk data yang bisa dibaca manusia. Ada
banyak kelas yang diturunkan dari kedua kategori ini.
Setiap objek yang mengeluarkan
data ke aliran byte masuk sebagai kelas turunan dari kelas abstrak OutputStream. Objek yang membaca data dari aliran byte diturunkan
dari kelas abstrak InputStream. Jika
kita menulis angka ke suatu OutputStream, kita
tidak akan bisa membaca data tersebut karena ditulis dalam bahasa mesin. Akan
tetapi data tersebut bisa dibaca kembali oleh InputStream.
Proses baca tulis data akan menjadi sangat efisien, karena tidak ada
penerjemahan yang harus dilakukan : bit yang digunakan untuk menyimpan data di
dalam memori komputer hanya dikopi dari dan ke aliran tersebut.
Untuk membaca dan menulis data
karakter yang bisa dimengerti manusia, kelas utamanya adalah Reader dan Writer. Semua kelas aliran karakter
merupakan kelas turunan dari salah satu dari kelas abstrak ini. Jika suatu
angka akan ditulis dalam aliran Writer,
komputer harus bisa menerjemahkannya ke dalam rangkaian karakter yang bisa
dibaca maunsia.
Membaca angka dari aliran Reader menjadi variabel numerik juga harus diterjemahkan, dari
deretan karakter menjadi rangkaian bit yang dimengerti komputer. (Meskipun
untuk data yang terdiri dari karakter, seperti dari editor teks, masih akan ada
beberapa terjemahan yang dilakukan. Karakter disimpan dalam komputer dalam
nilai Unicode 16-bit. Bagi orang yang menggunakan alfabet biasa, data karakter
biasanya disimpan dalam file dalam kode ASCII, yang hanya menggunakan 8-bit.
Kelas Reader dan Writer akan menangani perubahan dari
16-bit ke 8-bit dan sebaliknya, dan juga menangani alfabet lain yang digunakan
negara lain.)
Adalah hal yang mudah untuk
menentukan apakah kita harus menggunakan aliran byte atau aliran karakter. Jika
kita ingin data yang kita baca/tulis untuk bisa dibaca manusia, maka kita
gunakan aliran karakter. Jika tidak, gunakan aliran byte. System.in dan System.out
sebenarnya adalah aliran byte dan bukan aliran karakter, karenanya bisa
menangani input selain alfabet, misalnya tombol enter, tanda panah, escape,
dsb.
Kelas aliran standar yang akan
dibahas berikutnya didefinisikan dalam paket java.io beserta beberapa kelas bantu lainnya. Kita harus mengimpor
kelas-kelas tersebut dari paket ini jika kita ingin menggunakannya dalam
program kita. Artinya dengan menggunakan "import java.io.*" di
awal kode sumber kita.
Aliran tidak digunakan dalam GUI,
karena GUI memiliki aliran I/O tersendiri. Akan tetapi kelas-kelas ini
digunakan juga untuk file atau komunikasi dalam jaringan. Atau bisa juga
digunakan untuk komunikasi antar thread yang sedang bekerja secara bersamaan.
Dan juga ada kelas aliran yang digunakan untuk membaca dan menulis data dari
dan ke memori komputer.
Operasi pada Aliran (Stream)
·
Kelas dasar I/O Reader, Writer, InputStream
dan OutputStream hanya menyediakan operasi I/O sangat dasar. Misalnya, kelas
InputStream memiliki metode instansi
·
public
int read()
throws IOException
·
untuk membaca satu byte data dari
aliran input. Jika sampai pada akhir dari aliran input , metode read() akan mengembalikan nilai -1. Jika ada kesalahan yang
terjadi pada saat pengambilan input, maka pengecualian IOException akan dilemparkan. Karena IOException
adalah kelas pengecualian yang harus ditangani, artinya kita harus menggunakan
metode read() di dalam
penyataan try atau mengeset subrutin untuk throws IOException. (Lihat kembali pembahasan tentang pengecualian di bab sebelumnya)
·
Kelas InputStream
juga memiliki metode untuk membaca beberapa byte data dalam satu langkah ke
dalam array byte. Akan tetapi InputStream tidak memiliki metode untuk
membaca jenis data lain, seperti int
atau double dari aliran. Ini bukan masalah karena dalam prakteknya kita
tidak akan menggunakan objek bertipe InputStream
secara langsung. Yang akan kita gunakan adalah kelas turunan dari InputStream yang memiliki beberapa metode input yang lebih beragam
daripada InputStream itu sendiri.
·
Begitu juga dengan kelas OutputStream memiliki metode output primitif untuk menulis satu byte
data ke aliran output, yaitu metode
·
public
void write(int b) throws IOException
·
Tapi, kita hampir pasti akan
menggunakan kelas turunannya yang mampu menangani operasi yang lebih kompleks.
·
Kelas Reader
dan Writer memiliki operasi dasar yang hampir sama, yaitu read
dan write, akan tetapi kelas ini berorientasi karakter (karena
digunakan untuk membaca dan menulis data yang bisa dibaca manusia). Artinya
operasi baca tulis akan mengambil dan menulis nilai char bukan byte. Dalam prakteknya kita akan menggunakan kelas
turunan dari kelas-kelas dasar ini.
·
Salah satu hal menarik dari paket
I/O pada Java adalah kemungkinan untuk menambah kompleksitas suatu aliran
dengan membungkus aliran tersebut dalam objek aliran lain. Objek pembungkus ini
juga berupa aliran, sehingga kita juga bisa melakukan baca tulis dari objek
yang sama dengan tambahan kemampuan dalam objek pembungkusnya.
·
Misalnya, PrintWriter adalah kelas turunan dari Writer
yang memiliki metode tambahan untuk menulis tipe data Java dalam karakter yang
bisa dibaca manusial. Jika kita memiliki objek bertipe Writer atau turunannya, dan kita ingin menggunakan metode pada PrintWriter untuk menulis data, maka kita bisa membungkus objek Writer dalam objek PrintWriter.
·
Contoh jika baskomKarakter bertipe Writer, maka kita bisa membuat
·
PrintWriter
printableBaskomKarakter = new PrintWriter(baskomKarakter);
·
Ketika kita menulis data ke printableBaskomKarakter dengan menggunakan metode pada PrintWriter yang lebih canggih, maka data tersebut akan ditempatkan di
tempat yang sama dengan apabila kita menulis langsung pada baskomKarakter. Artinya kita hanya perlu membuat antar muka yang lebih
baik untuk aliran output yang sama. Atau dengan kata lain misalnya kita bisa
menggunakan PrintWriter untuk menulis file atau mengirim data pada jaringan.
·
Untuk lengkapnya, metode pada kelas PrintWriter memiliki metode sebagai berikut :
·
//
Metode untuk menulis data dalam
·
//
bentuk yang bisa dibaca manusia
·
public
void print(String s)
·
public
void print(char c)
·
public
void print(int i)
·
public
void print(long l)
·
public
void print(float f)
·
public
void print(double d)
·
public
void print(boolean b)
·
·
//
Menulis baris baru ke aliran
·
public
void println()
·
·
//
Metode ini sama dengan di atas
·
// akan
tetapi keluarannya selalu
·
//
ditambah dengan baris baru
·
public
void println(String s)
·
public
void println(char c)
·
public
void println(int i)
·
public
void println(long l)
·
public
void println(float f)
·
public
void println(double d
·
public
void println(boolean b)
·
Catatan bahwa metode-metode di atas
tidak pernah melempar pengecualian IOException.
Akan tetapi, kelas PrintWriter memiliki
metode
·
public
boolean checkError()
·
yang akan mengembalikan true jika
ada kesalahan yang terjadi ketika menulis ke dalam aliran. Kelas PrintWriter menangkap pengecualian IOException
secara internal, dan mengeset nilai tertentu di dalam kelas ini jika kesalahan
telah terjadi. Sehingga kita bisa menggunakan metode pada PrintWriter tanpa khawatir harus menangkap pengecualian yang mungkin
terjadi. Akan tetapi, jika kita ingin membuat progam yang tangguh tentunya kita
harus selalu memanggil checkError() untuk
melihat apakah kesalahan telah terjadi ketika kita menggunakan salah satu
metode pada PrintWriter.
·
Ketika kita menggunakan metode PrintWriter untuk menulis data ke aliran, data tersebut diubah menjadi
rangkaian karakter yang bisa dibaca oleh manusia. Bagaimana caranya jika kita
ingin membuat data dalam bentuk bahasa mesin?
·
Paket java.io memiliki kelas aliran byte, yaitu DataOutputStream yang bisa digunakan untuk menulis suatu data ke dalam
aliran dalam format biner. DataOutputStream
berhubungan erat dengan OutputStream seperti
hubungan antara PrintWriter dan Writer.
·
Artinya, OutputStream hanya berisi metode dasar untuk menulis byte, sedangkan DataOutputStream memiliki metode writeDouble(double x) untuk menulis nilai double, writeInt(int x) untuk menulis nilai int, dan seterusnya. Dan juga kita bisa
membungkus objek bertipe OutputStream atau
turunannya ke dalam aliran DataOutputStream sehingga
kita bisa menggunakan metode yang lebih kompleks.
·
Misalnya, jika baskomByte adalah variabel bertipe OutputStream,
maka
·
DataOutputStream
baskomData = new
DataOutputStream(baskomByte);
·
untuk membungkus baskomByte dalam baskomData.
·
Untuk mengambil data dari aliran, java.io memiliki kelas DataInputStream.
Kita bisa membungkus objek bertipe InputStream
atau turunannya ke dalam objek bertipe DataInputStream.
Metode di dalam DataInputStream untuk membaca data biner bisa menggunakan readDouble(), readInt() dan
seterusnya. Data yang ditulis oleh DataOutputStream
dijamin untuk bisa dibaca kembali oleh DataInputStream,
meskipun data kita tulis pada satu komputer dan data dibaca pada komputer jenis
lain dengan sistem operasi berbeda. Kompatibilitas data biner pada Java adalah
salah satu keunggulan Java untuk bisa dijalakan pada beragam platform.
·
Salah satu fakta yang menyedihkan
tentang Java adalah ternyata Java tidak memiliki kelas untuk membaca data dalam
bentuk yang bisa dibaca oleh manusia. Dalam hal ini Java tidak memiliki kelas
kebalikan dari PrintWriter sebagaimana DataOutputStream
dan DataInputStream. Akan tetapi kita tetap bisa membuat kelas ini sendiri dan
menggunakannya dengan cara yang persis sama dengan kelas-kelas di atas.
·
Kelas PrintWriter,
DataInputStream, dan DataOutputStream
memungkinkan kita untuk melakukan input dan output semua tipe data primitif
pada Java. Pertanyaannya bagaimana kita melakukan baca tulis suatu objek?
·
Mungkin secara tradisional kita akan
membuat fungsi sendiri untuk memformat objek kita menjadi bentuk tertentu,
misalnya urutan tipe primitif dalam bentuk biner atau karakter kemudian
disimpan dalam file atau dikirim melalui jaringan. Proses ini disebut serialisasi (serializing) objek.
·
Pada inputnya, kita harus bisa
membaca data yang diserialisasi ini sesuai dengan format yang digunakan pada
saat objek ini diserialisasi. Untuk objek kecil, pekerjaan semacam ini mungkin
bukan masalah besar. Akan tetapi untuk ukuran objek yang besar, hal ini tidak
mudah.
·
Akan tetapi Java memiliki cara untuk
melakukan input dan output isi objek secara otomatis, yaitu dengan menggunakan ObjectInputStream dan ObjectOutputStream.
Kelas-kelas ini adalah kelas turunan dari InputStream
dan OutputStream yang bisa digunakan untuk membaca dan menulis objek yang
sudah diserialisasi.
·
ObjectInputStream
dan ObjectOutputStream adalah kelas yang bisa dibungkus oleh kelas InputStream dan OutputStream lain.
Artinya kita bisa melakukan input dan output objek pada aliran byte apa saja.
·
Metde untuk objek I/O adalah readObject() yang tersedia pada ObjectInputStream dan writeObject(Object obj) yang
tersedia dalam ObjectOutputStream. Keduanya bisa melemparkan IOException.
Ingat bahwa readObject()
mengembalikan nilai bertipe Object yang artinya harus di-type cast ke
tipe sesungguhnya.
·
ObjectInputStream
dan ObjectOutputStream hanya bekerja untuk objek yang mengimplementasikan
interface yang bernama Serializable. Lbih
jauh semua variabel instansi pada objek harus bisa diserialisasi, karena
interface Serializable tidak mempunyai metode apa-apa. Interface ini ada hanya
sebagai penanda untuk kompiler supaya kompiler tahu bahwa objek ini digunakan
untuk baca tulis ke suatu media.
·
Yang perlu kita lakukan adalah
menambahkan "implements Serializable"
pada definisi kelas. Banyak kelas standar Java yang telah dideklarasikan untuk
bisa diserialisasi, termasuk semua komponen kelas Swing dan AWT. Artinya
komponen GUI pun bisa disimpan dan dibaca dari dalam perangkat I/O menggunakan ObjectInputStream dan ObjectOutputStream.
http://tutorz1994.blogspot.com/2013/09/java-input-output.html
SSEMOGA BERMANFAAT
Tidak ada komentar:
Posting Komentar