Kamis, 15 Desember 2011

File (Java)


Data dan program pada memori komputer hanya bisa bertahan selama komputer itu nyala. Untuk tempat penyimpanan yang lebih lama, komputer menggunakan file, yaitu kumpulan data yang disimpan dalam hard disk, disket atau CD-ROM, USB stick, dan lain-lain. File disusun dalam direktori (atau sering juga disebut folder). Direktori bisa terdiri dari direktori lain atau file lain. Nama direktori dan file digunakan untuk mencari suatu file dalam komputer.

Program dapat membaca data dari file yang sudah ada. Program juga bisa membuat file baru atau menulis data ke dalam file yang sudah ada. Dalam Java, input dan output seperti ini bisa menggunakan aliran (stream). Data karakter yang bisa dibaca manusial dapat dibaca dari file dengan menggunakan objek dari kelas FileReader yang merupakan kelas turunan Reader. Data bisa ditulis dalam bentuk yang bisa dibaca manusia dengan menggunakan FileWriter yang merupakan kelas turunan dari Writer.

Untuk membaca atau menyimpan suatu file dalam format mesin, kelas I/O-nya adalah FileInputStream danFileOutputStream. Semua kelas ini didefinisikan dalam paket java.io.

Perlu dicatat bahwa applet yang didownload dari suatu jaringan pada umumnya tidak bisa mengakses file karena pertimbangan keamanan. Kita bisa mendownload dan menjalankan applet, yaitu dengan mengunjungi halaman web pada browser kita. Jika applet tersebut bisa digunakan untuk mengakses file pada komputer kita, maka orang bisa membuat applet untuk menghapus semua file dalam komputer yang mendownloadnya.

Untuk mencegah hal seperti itu, ada beberapa hal di mana applet yang didownload tidak bisa lakukan. Mengakses file adalah salah satu hal yang dilarang. Akan tetapi program desktop bisa memiliki akses ke file kita seperti program-program lainnya. Program desktop bisa melakukan akses file yang dijelaskan pada bagian ini.


Kelas FileReader memiliki konstruktor yang mengambil nama file sebagai parameternya, kemudian membuat aliran input yang bisa digunakan untuk membaca file tersebut. Konstruktor ini akan melemparkan pengecualian bertipe FileNotFoundExceptionjika file tersebut tidak ditemukan.

Jenis pengecualian seperti ini membutuhkan penanganan wajib, sehingga kita harus memanggil konstruktor di dalam pernyataantry atau menambahkan pernyataan throw di kepala subrutin yang menjalankan konstruktor tersebut. Milsanya, anggap kita memiliki file bernama "data.txt", dan kita ingin membuat program untuk membaca data pada file tersebut. Kita bisa menggunakan pernyataan berikut untuk membaca aliran input dari file tersebut :
// (Mendeklarasikan variabel sebelum pernyataan try
// jika tidak, maka variabel tersebut hanya bisa
// dilihat di dalam blok try, dan kita tidak bisa
// menggunakannya lagi di bagian program lain
FileReader data;
 
try {
    // buat aliran input
    data = new FileReader("data.txt");
}
catch (FileNotFoundException e) {
    ... // lakukan sesuatu untuk menangani kesalahan
}

Kelas FileNotFoundException merupakan kelas turunan dari IOException, sehingga kita bisa menangkap IOException pada pernyataan try...catch di atas. Secara umum, hampir semua kesalahan yang terjadi pada saat operasi input/output dapat ditangkap dengan pernyataan catch yang menangani IOException.

Begitu kita berhasil membuat FileReader, kita bisa mulai membacanya. Tapi karena FileReader hanya memiliki metode input primitif dari standar kelas Reader, kita mungkin akan perlu membungkusnya dalam objek lain, misalnya BufferedReader atau kelas pembungkus lain. Untuk membuat BufferedReader untuk membaca file bernama "data.dat", kita bisa gunakan :
TextReader data;
try {
    data = new BufferedReader(new FileReader("data.dat"));
}
    catch (FileNotFoundException e) {
    ... // tangani pengecualian
}

BufferedReader memiliki metode bantu untuk mengambil data per baris dengan perintah readline(). Sehingga apabila satu data ditulis dalam urutan per baris, kita bisa gunakan perintah Double.parseDouble(string) atau Integer.parseInt(string) untuk mengubahnya menjadi double atau int.

Untuk menyimpan data tidaklah lebih sulit dari ini. Kita bisa membuat objek bertipe FileWriter. Dan kemudian kita mungkin ingin membungkus aliran output ini dalam objek PrintWriter. Misalnya, kita ingin menyimpan data ke file yang bernama "hasil.dat", kita bisa menggunakan :
PrintWriter result;
 
try {
    keluaran = new PrintWriter(new FileWriter("hasil.dat"));
}
    catch (IOException e) {
    ... // tangani pengecualian
}

Jika tidak ada file bernama "hasil.dat", maka file baru akan dibuat. Jika file sudah ada, maka isinya akan dihapus dan diganti dengan data yang ditulis oleh program kita. Pengecualian IOException bisa terjadi jika, misalnya, file tersebut sedang dibaca oleh program lain, sehingga sistem operasi menolak program kita untuk menulisnya pada saat yang sama.

Setelah kita selesai menggunakan file, sebaiknya anda menutup file tersebut, atau mengatakan kepada sistem operasi bahwa kita telah selesai menggunakan file itu (Jika kita lupa, sistem operasi akan menutup file secara otomatis setelah program selesai dijalankan atau objek aliran file diambil oleh pemulung memori, akan tetapi akan sangat baik jika kita menutup file secara manual untuk menghindari kemungkinan lainnya).

Kita bisa menutup file dengan menggunakan metode close() pada aliran tersebut. Setelah file telah ditutup, maka kita tidak mungkin lagi membaca atau menulis data dari atau ke file tersebut. Kita harus membukanya kembali. (Perlu dicatat bahwa penutupan file juga bisa melemparkan pengecualian IOException yang wajib ditangani, akan tetapi PrintWriter menangani pengecualian tersebut secara otomatis sehingga kita tidak perlu menanganinya lagi).

Sebagai contoh komplit, berikut ini adalah program yang akan membaca angka dari file bernama "data.dat", dan kemudian menuliskannya kembali dalam urutan terbalik ke dalam file yang bernama "hasil.dat". Dalam file tersebut hanya akan ada satu angka untuk setiap barisnya dan diasumsikan tidak ada lebih dari 1000 angka sekaligus. Penanganan pengecualian digunakan untuk mengecek apakah ada masalah di tengah operasi. Meskipun mungkin tidak begitu berguna untuk aplikasi sungguhan, akan tetapi program ini mendemonstrasikan bagaimana menggunakan operasi baca tulis sederhana pada file.
package balikfile;
 
import java.io.*;
 
public class BalikFile {
 
    /**
     * @param args
     */
    public static void main(String[] args) {
        BufferedReader data;  // Aliran input karakter untuk membaca data
        PrintWriter hasil;  // Aliran output karakter untuk menulis data
 
        // Array untuk menampung semua angka dari dalam file
        double[] angka = new double[1000];  
 
        int banyakAngka;  // Banyaknya angka yg disimpan dlm array
 
        try {  // Buat aliran input
            data = new BufferedReader(new FileReader("data.dat"));
        }
        catch (FileNotFoundException e) {
            System.out.println("Tidak bisa menemukan data.dat!");
            return;  // akhiri program
        }
 
        try {  // Membuat aliran output
            hasil = new PrintWriter(new FileWriter("hasil.dat"));
        }
        catch (IOException e) {
            System.out.println("Tidak bisa membuka hasil.dat!");
            System.out.println(e.toString());
            try {
                data.close();  // Tutup file input
            }
            catch (IOException f) {
                System.out.println("Tidak bisa menutup data.dat");
            }
            return;        // End the program.
        }
 
        String baris = null; // variabel untuk menyimpan satu baris teks
 
        try {
             // Baca data dari file input
             banyakAngka = 0;
             while ((baris = data.readLine()) != null) {  // baca hingga habis
                 angka[banyakAngka] = Double.parseDouble(baris);
                 banyakAngka++;
             }
 
             // Tulis hasilnya dalam urutan terbalik
             for (int i = banyakAngka-1; i >= 0; i--)
                 hasil.println(angka[i]);
 
             System.out.println("Selesai!");
 
        }
        catch (IOException e) {
            // Ada masalah dengan pembacaan/penulisan file
            System.out.println("Kesalahan baca/tulis");
        }
        catch (NumberFormatException e) {
            // Ada masalah dengan format angka dalam file
            System.out.println("Kesalahan format: " + e.getMessage());
        }
        catch (IndexOutOfBoundsException e) {
            // Tidak boleh meletakkan 1000 angka dalam file
            System.out.println("Terlalu banyak angka.");
            System.out.println("Penulisan dihentikan.");
        }
        finally {
            // Akhiri dengan menutup semua file apapun yang terjadi
            try {
                data.close();  // Tutup file input
            }
            catch (IOException e) {
                System.out.println("Tidak bisa menutup data.dat");
            }
            hasil.close();  // Tutup file output
        }
    }
}

Berikut ini adalah program lengkapnya yang bisa diimport ke dalam Eclipse beserta contoh file data.dat.

Setelah selesai dijalankan file baru akan dibuat hasil.dat yang bisa Anda double-click untuk melihat hasilnya

Nama File, Direktori, dan Kelas File


Topik tentang nama file sebenarnya lebih kompleks daripada yang telah kita bahas. Untuk menunjuk pada sebuah file, kita harus memberikan bukan hanya nama file, tapi juga nama direktori di mana file tersebut disimpan. Nama file sederhana seperti "data.dat" atau "hasil.dat" diambil dengan mengacu pada direktori sekarang (current directory, atau juga disebut direktori kerja). Pada program di bagian sebelumnya, hasil.dat disimpan pada direktori yang sama dengan direktori utama pada proyek balikfile.

File yang tidak diletakkan pada direktori kerja harus diberikan nama "path", atau nama lengkap termasuk nama direktorinya. Untuk memperjelas lagi, ada dua jenis nama path, yaitu nama path absolut dan nama path relatif. Nama path absolut memiliki informasi lengkap dari akar direktorinya, misalnya "C:\workspace\balikfile\data.dat". Sedangkan nama path relatif adalah nama file yang dihitung mulai dari direktori aktifnya.

Sayangnya, sintaks untuk nama path dan file bervariasi dari satu sistem ke sistem lain. Misalnya "

- data.dat -- pada komputer apapun, yaitu file data.dat pada direktori aktif.

- /home/lyracc/java/contoh/data.dat -- Nama path absolut pada sistem operasi LINUX atau UNIX. Mengacu pada file bernama data.dat di direktori yang ditunjuk.

- C:\lyracc\java\contoh\data.dat -- Nama path absolut pada DOS atau Windows

- Hard Drive:java:contoh:data.dat -- Misalnya "Hard Drive" adalah nama dari drivenya, maka ini adalah nama path absolut pada Macintosh OS 9
contoh/data.dat -- nama path relatif pada LINUX atau UNIX. "contoh" adalah nama direktori yang terdapat
pada direktori aktif, dan data.dat adalah file dalam direktori tersebut. Pada Windows, nama path relatifnya menjadi contoh\data.dat dan pada Macintosh menjadi contoh:data.dat.

Untuk mencegah berbagai masalah yang mungkin muncul karena beragam sistem ini, Java memiliki kelas bernama java.io.File. Objek bertipe kelas ini melambangkan suatu file. Lebih tepatnya, objek bertipe File melambangkan nama file, bukan file itu sendiri. Nama yang ditunjuk belum tentu ada. Direktori juga dianggap Java sebagai File, sehingga File juga melambangkan nama direktori sekaligus nama file.

Objek File memiliki konstruktor new File(String) yang akan membuat objek File dari namanya. Nama tersebut bisa nama sederhana, nama path relatif, atau nama path absolut. Misalnya new File("data.dat") membuat objek File dari file bernama data.dat di direktori aktif.

Konstruktor lain memiliki konstruktor new File(File,String), di mana parameter pertama adalah direktori di mana file tersebut berada, dan parameter kedua adalah nama filenya.

Objek File memiliki beberapa metode instansi. Misalnya file adalah variabel bertipe File, berikut ini adalah beberapa metodenya :

- file.exists() -- mengembalikan nilai boolean, yang jika true maka file tersebut ada. Kita bisa menggunakan perintah ini misalnya untuk mencegah menulis file yang sama ketika kita membuka objek FileWriter baru.

- file.isDirectory() -- mengembalikan nilai boolean yang mengembalikan true jika objek File adalah suatu direktori, dan false jika File adalah file biasa, atau tidak ada file dengan nama tersebut.

- file.delete() -- menghapus file jika ada

- file.list() -- jika objek File adalah suatu direktori, maka fungsi ini mengembalikan array bertipe String[] yang berisi nama-nama file pada direktori tersebut. Jika tidak, maka kembaliannya adalah null.

Berikut ini adalah contoh program yang menulis isi file di dalam direktori yang diinput dari user :
package daftardirektori;
 
import java.io.*;
 
public class DaftarDirektori {
 
    /* Program ini mengembalikan isi suatu direktori
     * User memasukkan direktori yang ingin dilihat
     * Jika direktori tidak ada, maka pesan kesalahan
     * akan ditulis dan program akan berhenti
     */
 
     public static void main(String[] args) {
 
        String namaDirektori = null;  // Nama direktori dari user
        File direktori;        // objek File yang mengacu pada direktori
        String[] isiFile;      // Array berisi file pada direktori
 
        // buat objek baru untuk mengambil input
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
 
        System.out.print("Masukkan nama direktori : ");
        try {
            namaDirektori = br.readLine();
        } catch(IOException ioe) {
            System.out.println("Kesalahan IO terjadi");
            System.exit(1);
        }
 
        direktori = new File(namaDirektori);
 
        if (direktori.isDirectory() == false) {
            if (direktori.exists() == false)
                System.out.println("Tidak ada direktori ini!");
            else
                System.out.println("Ini bukan direktori.");
        }
        else {
            isiFile = direktori.list();
            System.out.println("Files dalam direktori \"" + direktori + "\":");
            for (int i = 0; i < isiFile.length; i++)
                System.out.println("   " + isiFile[i]);
        }
 
    }
 
}
Berikut ini adalah program lengkapnya yang bisa diimport ke dalam Eclipse. Ini adalah hasil keluarannya :
Semua kelas yang digunakan untuk memaca dan menulis data dari dan ke dalam file memiliki konstruktor yang bisa mengambil objek File sebagai parameternya. Misalnya, jika file adalah variabel bertipe File, dan kita ingin mengambil karakter dari file tersebut, maka kita bisa membuat FileReader untuk melakukannya dengan menggunakan new FileReader(file).

Mengkopi File


Mengkopi suatu file adalah operasi biasa, dan sistem operasi manapun memiliki perintah atau cara untuk melakukannya. Akan tetapi kita juga bisa membuat program Java untuk melakukannya.

Karena program harus bisa mengkopi file jenis apapun, kita tidak bisa menganggap data di dalam file adalah data yang bisa dibaca manusia. File lagu atau video misalnya berisi deretan byte yang merupakan representasi digital dari lagu atau video tersebut.

Oleh karena itu kita harus menggunakan InputStream dan OutputStream untuk melakukan operasi baca tulis yang bisa menangani data biner, bukan Reader dan Writer yang hanya bisa menangani data yang bisa dibaca manusia.

Program yang kita buat akan mengkopi beberapa byte sekaligus dari InputStream ke OutputStream, akan tetapi kita membutuhkan tempat sementara di mana data tersebut akan ditempatkan sebelum data tersebut ditulis kembali padaOutputStream. Tempat sementara tersebut disebut buffer yang merupakan array berukuran tertentu, misalnya 4096 byte (atau 4 kilo byte).

Jika sumber adalah variabel bertipe InputStream, maka byteTerbaca = sumber.read(buffer) akan mengisi penuh buffer. Metode ini mengembalikan int yang merupakan berapa byte yang efektif diambil oleh sumber, kemudian diletakkan dalam variabelbyteTerbaca. Jika hasilnya -1, berarti tidak ada lagi data yang bisa diambil dari dalam sumber.

Begitu juga jika kopi adalah keluaran yang bertipe OutputStream maka kopi.write(buffer, 0, byteTerbaca) menulis deretan byte dari buffer dari posisi 0 hingga byteTerbaca ke aliran keluaran kopi.

Sehingga secara umum perintah-perintah di atas dapat dirangkum menjadi :
byte[] buffer = new byte[4096];
int byteTerbaca;
 
while((byteTerbaca = sumber.read(buffer)) != -1)
    kopi.write(buffer, 0, byteTerbaca);

Perintah kopi-file pada sistem operasi baik DOS/Windows atau LINUX/UNIX menggunakan perintah pada konsol yang menambahkan file sumber dan file tujuannya. Misalnya, pada konsol Windows, kita bisa menggunakan "copy awal.datakhir.dat" untuk mengkopi file awal.dat ke file bernama akhir.dat.

Tambahan parameter pada konsol ini disebut argumen baris perintah. Argumen baris perintah ini bisa juga digunakan dalam program Java. Dalam Java argumen baris perintah ini diisi dalam array String[] bernama args, yang kemudian dimasukkan sebagai parameter dalam subrutin main(). Ingat bagaimana "biasanya" subrutin main() dideklarasikan sebagai public static voidmain(String[] args).

Pada program Java yang sudah dikompilasi, kita bisa memanggilnya dengan "java KopiFile awal.dat akhir.dat" jika KopiFile adalah nama kelas yang akan kita buat untuk mengkopi file. args[0] akan berisi awal.dat sedangkan args[1] akan berisi akhir.dat.

Program yang akan kita buat menerima input dari baris perintah. Kemudian program akan mengecek apakah kedua parameter tersebut berisi nama file dengan benar. Jika salah satu parameternya kosong, maka program akan menampilkan pesan kesalahan. Program juga akan mengecek apakah akhir.dat merupakan file yang sudah ada sebelumnya, kemudian memberi pertanyaan kepada user apakah isi file ini ingin ditindih dengan isi file awal.dat. Jika ya, maka operasi akan diteruskan, jika tidak maka program akan dihentikan.

Berikut ini adalah listing lengkap program KopiFile, yang bisa diunduh di sini dan diimport ke dalam Eclipse.
import java.io.*;
 
public class KopiFile {
 
    /**
     * @param args
     */
    public static void main(String[] args) {
        // Mengecek apakah argumen program cukup untuk meneruskan program
        // Dibutuhkan dua argumen, yaitu sumberFile dan tujuanFile
        if (args.length < 2) {
            System.out.println("Cara menjalankan program : " +
              "java KopiFile sumberFile tujuanFile");
            return;
        }
 
        String sumberNamaFile = args[0];
        String tujuanNamaFile = args[1];
 
        File sumberFile = new File(sumberNamaFile);
        File kopiFile = new File(tujuanNamaFile);
 
        // Jika kopi file sudah ada, kita akan tanyakan apakah file tujuan
        // akan ditimpa
        if (kopiFile.exists()) {
            // buat objek baru untuk mengambil input
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            String timpaFile = null;
 
            System.out.print("Apakah Anda ingin menimpa " + tujuanNamaFile + " ? (y/t) ");
            try {
                timpaFile = br.readLine();
            } catch(IOException ioe) {
                System.out.println("Kesalahan IO terjadi");
                System.exit(1);
            }
 
            // jika jawabannya tidak, hentikan program
            if (timpaFile.equalsIgnoreCase("t"))
                return;
        }
 
        // Di sini kita siap untuk mengkopi file
        // Buat aliran input dan output
        FileInputStream sumber = null;
        try {
            sumber = new FileInputStream(sumberFile);
        } catch (FileNotFoundException e) {
            System.out.println("File sumber tidak ada, berupa direktori " +
              "atau tidak bisa dibuka, program dihentikan!");
            return;
        }
 
        FileOutputStream kopi = null;
        try {
            kopi = new FileOutputStream(tujuanNamaFile);
        } catch (FileNotFoundException e) {
            System.out.println("File tujuan tidak valid atau tidak bisa ditulis, " +
              "program dihentikan!");
            return;
        }
 
        byte[] buffer = new byte[4096];
        int byteTerbaca;
 
        try {
            while((byteTerbaca = sumber.read(buffer)) != -1)
                kopi.write(buffer, 0, byteTerbaca);
        } catch (IOException e) {
            System.out.println("Ada masalah di tengah pengkopian program");
            return;
        }
 
        System.out.println("Kopi file selesai dijalankan!");
    }
 
}
Perlu diingat bahwa program ini tidak bisa dijalankan lewat Eclipse. Jika Anda mencoba menjalankan lewat Eclipse, maka tampilan kesalahan akan muncul, karena tidak ada parameter yang diberikan.

Untuk menjalankan program, Anda harus membuka konsol pada Windows dengan Start -> Run -> kemudian ketik cmd dan enter. Setelah itu pergi ke direktori tempat proyek Anda berada pada Eclipse. Misalnya pada komputer saya, saya meletakkan semua proyek Eclipse pada c:\belajarjava.lyracc.com\KopiFile. Di dalamnya seharusnya Anda akan menemui 2 direktori, yaitu src dan bin. src adalah tempat di mana kode sumber berada, sedangkan bin adalah tempat dimana hasil kompilasi berada. Eclipse akan melakukan kompilasi secara otomatis.

Berikut screenshot hasil jalannya program. Di sini saya mengkopi file daric:\belajarjava.lyracc.com\KopiFile\src\KopiFile.java ke c:\belajarjava.lyracc.com\Kopi123.java.



Tidak ada komentar:

Posting Komentar