Java'da Dosya İşlemleri

Java'da Dosya İşlemleri

Bu bölümde sizlere Java'da bir dosyaya veri yazmayı ve ardından okumayı göstereceğiz. İlk örneğimizde bir string değişkeni içerisinde saklanan veriyi disk üzerinde bir .txt (metin) dosyasına yazmayı anlatacağız.
 String str = "Bunu dosyaya yazdir";

        File file = new File("dosya.txt");
        if (!file.exists()) {
            file.createNewFile();
        }

        FileWriter fileWriter = new FileWriter(file, false);
        BufferedWriter bWriter = new BufferedWriter(fileWriter);
        bWriter.write(str);
        bWriter.close();
Java'da disk üzerindeki dosyalar ve klasörlerle iletişim sağlamak için File sınıfından faydalanırız. File sınıfı disk üzerinde belirtilen konumdaki bir dosya ya da klasörü kod içerisinden tanımlamak için kullanılır. Yukarıdaki kod parçasına bakarsak File sınıfının yapıcısı (Constructor) içerisinde dosyanın adı dosya.txt olarak belirtilmiş. Bu şekilde disk üzerinde dosya.txt adında bir dosyaya işlem yapmak için o dosyayı bir değişkene atamış oluyoruz. exists metodu dosyanın disk üzerinde önceden var olduğunu kontrol etmek için kullanılıyor. Eğer dosya diskte henüz yoksa createNewFile ile diskte dosya.txt adında bir dosya oluşturuyoruz.
Dosyaya metin yazma işlemini başlatmak için FileWriter sınıfından faydalanırız. FileWriter sınıfı File tipindeki bir değişkeni yazma amacıyla kullanmaya yarar. Yapıcı içerisinde yer alan boolean tipindeki değer dosyanın append modunda yazılmasını sağlar. append modu dosyanın içerisinde yer alan mevcut metinlere dokunmadan dosyanın son karakterinden itibaren yazma işlemini başlatacaktır. Yukarıdaki kod içerisinde bu değer false olduğundan dosya.txt her seferinde baştan yazılacaktır.
BufferedWriter sınıfı ise dosyaya bir kayıt yazarken bize ayarlanabilir bir tampon bellek (Buffer) sunacaktır. Bu işlem olmadan yazma işlemi yapılması karakterlerin anında byte'a dönüştürülüp dosyaya yazılmasına yol açacak ve programın verimsiz çalışmasına yol açacaktır (Bkz: Buradaki belge).
write metodu yazma işlemini başlatır. Dosyaya yazma işlemimiz tamamlandıktan sonra close komutuyla dosya ile olan işlemi tamamlarız ve diskte metin dosyamız oluşur.
dosya.txt metin dosyasının projedeki yeri
Dosyayı okumak içinse aşağıdaki kodu kullanırız:
FileReader fileReader = new FileReader(file);
String line;

BufferedReader br = new BufferedReader(fileReader);

while ((line = br.readLine()) != null) {

    System.out.println(line);
}
br.close();
Buradaki file değişkeni bir önceki örnekte oluşturulan File sınıfındaki değişkendir ve dosya.txt adındaki dosyamızı belirtir. Burada dosyayı okuma amacıyla FileReader adındaki sınıfı kullanmamız gerekir. Daha önceki örnekte olduğu gibi BufferedReader yardımıyla dosyamızı okumaya başlarız. Dosya içerisindeki her satır line adındaki bir değişkene atılır ve dosyanın sonuna gelene kadar bütün satırlar konsola yazdırılır (line != null). İşlem bitirildikten sonra BufferedReader close metoduyla kapatılır.

NOT: BufferedReader bize yüksek bir tampon bellek sağlar. BufferedReader kullanılmazsa read metodu her çağırıldığında dosyadan byte'lar çekilir, karakterlere dönüştürülür ve döndürülür. Bu da programın performansının düşmesine yol açar. (Bkz: Buradaki kılavuz belge)
Eğer bir resmi ya da İnternet üzerinden çektiğimiz bir dosyayı diske kayıt etmek istiyorsak, metin dosyası yerine binary dosya kullanmamız gerekir. Java bu amaçla aşağıdaki sınıfları sunmaktadır:
byte[] data = {0x01, 0x02};

File binaryFile = new File("binary.dat");
FileOutputStream fos = new FileOutputStream(binaryFile);
BufferedOutputStream bos = new BufferedOutputStream(fos);
bos.write(data);
bos.close();

FileOutputStream binary bir dosyaya byte tipinde bir değişken yazmak için kullanılır. Yukarıdaki örnekte data değişkenindeki byte değerleri binary.dat adında bir dosyaya yazılmak için hazırlanmıştır. BufferedOutputStream ise binary dosyaya yazma işlemi sırasında bize tampon bellek sağlar. write komutuyla yazma işlemi tamamlandıktan sonra close metodu ile akış (stream) kapatılmalıdır.
Dosyayı okumak içinse aşağıdaki koddan faydalanırız:
data = new byte[(int) binaryFile.length()];
FileInputStream fis = new FileInputStream(binaryFile);
BufferedInputStream bis = new BufferedInputStream(fis);
bis.read(data, 0, data.length);
bis.close();

Yukarıda öncelikle dosyanın içeriğini alabileceğimiz bir byte dizisi oluşturuyoruz. Bu dizi binary dosya için dosyanın boyutu kadardır ve File sınıfında bulunan length metoduyla öğrenilebilir. Ardından oluşturulan FileInputStream akışı ile dosyaya erişim sağlanır ve BufferedInputStream yardımıyla dosya okunarak içerisindeki bütün byte değerleri data değişkenine aktarılır. Bu noktadan sonra dosyanın tüm içeriği data dizisi içinde yer alır. close metodu akışı kapatmak için kullanılır.
Android uygulamalarında SD kart üzerine veri yazmak ya da uzaktaki bir kaynaktan alınan resimleri saklamak için bu metodları sıklıkla kullanacağız.

Dosyalara Bilgi Kaydı

GİRİŞ-ÇIKIŞ AKIMLARI

Java’da Giriş-Çıkış akımları, iki ana gruba ayrılır:
  1. Karakter kökenli akımlar
  2. Byte kökenli akımlar
Bunların herbiri için ayrı sınıflar tanımlanmıştır. Aşağıdaki şekil bu konuda bize fikir veriyor:

Karakter Kökenli ve Byte Kökenli Akımlar

 

Karakter Kökenli Akımlar

Bu bölümde önce karakter kökenli akımlar ile bellek üzerindeki dosyalara bilgi kaydını gözden geçireceğiz. Bellek üzerine karakter türü bilgi kaydını Writer sınıfının alt sınıflarını kullanarak gerçekleştiriyoruz. Aşağıda, Writer sınıfıyla ilişkili sınıf hiyerarşisini görüyoruz:


FileWriter Sınıfının Kullanımı

Aşağıdaki örnek Java programı, FileWriter sınıfından yazar adlı bir nesne oluşturarak, bu nesne yardımıyla siir.txt adlı text tipi dosyaya bilgi kaydediyor. Dosyaya bir satırlık bilgi write metoduyla yazılıyor ve satır sonu ‘\n’ karakteriyle belirleniyor.
import java.io.FileWriter;
import java.io.IOException;

public class TextDosyaYaz {
    public static void main(String[] args) throws IOException {
        String dosyaAdi = "siir.txt";
        FileWriter yazar = new FileWriter(dosyaAdi);
        yazar.write("coklarindan dusuyor da bunca");
        yazar.write("gormuyor gelip gecenler");
        yazar.write("egilip aliyorum");
        yazar.write("solgun bir gul oluyor dokununca - behcet necatigil");
        yazar.close();
    }
}
Uygulamayı Eclipse ile çalıştırdığımızda projenin bulunduğu dizinde bir siir.txt dosyasının oluşturulduğunu görürüz:

Dosyayı açtığımızdaysa aşağıdaki içeriği görürüz:

Metin türünde bir dosyanın içeriğinin herhangi bir metin düzenleyici program yardımıyla görüntülenebileceğini belirtmiştik. Burada bunun örneğini görmüş olduk. siir.txt adlı dosyanın içeriğini bir Java programıyla da görüntüleyebiliriz. Bunun örneğini de biraz sonra göreceğiz. Ancak, byte tipi ya da ikili(binary) dosyaların içeriği sadece Java programı yardımıyla görüntülenebilir.

 

Metin Türü Dosyadan Bilgi Okumak

Metin türü bir dosyadan bilgi okumak için Reader sınıfını ve alt sınıflarını kullanırız. Aşağıda Reader sınıfı ve ilgili sınıfların hiyerarşisini görüyoruz:

FileReader sınıfı sayesinde disk üzerindeki metin tipi dosyadan alınan karakterler, bellek içinde char tipine dönüştürülür. Eğer UTF formatıyla desteklenen, İngiliz alfabesi dışındaki karakterler kullanılmışsa bir karakter 3 byte’lık yer kaplamış olabilir.
Diskten okunan verilerin önce bellekte bir tampon alan(buffer) içine yerleştirilmesi genellikle daha etkin bir yöntemdir. BufferedReader sınıfı bu amaçla kullanılır.

ÖRNEK JAVA PROGRAMI: FileReader ve BufferedReader ile Okuma

Bir önceki örnekte siir.txt adı ile oluşturduğumuz dosyayı şimdi bir Java programı ile okuyarak ekrana aktaracağız:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class TextDosyaOku {
    public static void main (String[] args){
        String dosyaAdi = "siir.txt";
        String satir;
        try{
            BufferedReader oku = new BufferedReader(new FileReader(dosyaAdi));
            satir = oku.readLine();
            while (satir != null) {
                System.out.println(satir);
                satir = oku.readLine();
            }
            oku.close();
        }
        catch (IOException iox){
            System.out.println(dosyaAdi+" adli dosya okunamiyor.");
        }
    }
}
Aşağıda olduğu gibi, siir.txt adlı metin dosyasının içeriğinin listelendiğini görürüz:


ÖRNEK UYGULAMA: Bir Metin Dosyasının İçeriğini Diğer Bir Metin Dosyasına Kopyalama

Aşağıdaki Java programı ile komut satırından adı girilen bir dosyanın içeriği yine komut satırından adı belirtilen diğer bir dosyaya kopyalanabiliyor. Aşağıdaki adımları izleyelim:
1. Aşağıdaki Java program bloğunu yazalım:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class Kopyala{
    String kaynakDosyaAdi, hedefDosyaAdi;
    BufferedReader kaynakBuffer;
    BufferedWriter hedefBuffer;
    String satir;

    public static void main (String[] args) {
        if (args.length == 3 && args[1].toUpperCase().equals("TO")) {
            new Kopyala().kopya(args[0], args[2]); 
        }
        else {
            System.out.println("Kullanim sekli: ");
            System.out.println("java Kopyala <dosya1> to <dosya2>");
        }
    }

    public boolean kopya(String isim1, String isim2) {
        kaynakDosyaAdi=isim1;
        hedefDosyaAdi=isim2;
        return dosyayiAc() && dosyayiKopyala() && dosyayiKapat();
    }

    private boolean dosyayiAc() {
        // Kaynak dosyayı aç
        try {      
            kaynakBuffer = new BufferedReader(
                    new FileReader(kaynakDosyaAdi));
        }
        catch (IOException e) {
            System.out.println(kaynakDosyaAdi
                    +" dosyasinin acilisinda sorun var!");
            return false;
        }

        // Hedef dosyayı aç
        try    {      
            hedefBuffer = new BufferedWriter(
                    new FileWriter(hedefDosyaAdi));
        }
        catch (IOException e) {
            System.out.println(hedefDosyaAdi
                    +" dosyasinin acilisinda sorun var!");
            return false;
        }
        return true; //iki dosya da ulasilabilirse true döndürür
    }

    private boolean dosyayiKopyala() {
        //esas metodumuz
        try    {      
            satir = kaynakBuffer.readLine();
            while (satir != null) {
                hedefBuffer.write(satir);
                hedefBuffer.newLine();
                satir = kaynakBuffer.readLine();
            }
        }
        catch (IOException e) {
            System.out.println("Kopyalama yapilamiyor.");
            return false;
        }
        return true;
    }

    private boolean dosyayiKapat() {
        boolean sorunsuzMu=true;
        // kaynağı kapat
        try    {      
            kaynakBuffer.close();
        }
        catch (IOException e) {
            System.out.println(kaynakDosyaAdi+" dosyasinin kapanisinda hata!");
            sorunsuzMu = false;
        }
        // hedefi kapat
        try    {      
            hedefBuffer.close();
        }
        catch (IOException e) {
            System.out.println(hedefDosyaAdi+" dosyasinin kapanisinda hata!");
            sorunsuzMu = false;
        }
        return sorunsuzMu;
    }
}
2. Komut satırından aşağıdaki komutu girelim:
Böylece siir.txt adlı dosyanın içeriği aynen manzum.txt adlı metin dosyasına kopyalanır. 

İKİLİ (BINARY) DOSYALAR

Metin tipi dosyalarda, her byte veya byte ikilisi bir ASCII kodu şeklinde yorumlanırken, ikili dosyalarda değişik uzunluklardaki byte grupları farklı türlerdeki veri olarak yorumlanır. Bu yorum yazılım tarafından gerçekleştirilir. Örneğin, bir Java binary dosyasında, bir int türü veri 4 byte’lık bir veri grubuyla saklanır.
İkili (binary) dosyaya veri kaydetmek için temel sınıf OutputStream sınıfıdır. Aşağıdaki şekilde bu sınıf ve alt sınıflarını görüyoruz:


Aşağıdaki kod örneği ikili dosyaların birbirine kopyalanmasını gösterir.
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class IkiliDosya {
    
    public static void main(String[] args) {
        
        //Dosyalarınızın yolunu belirtin.
        String kaynakDosya = "Kaynak dosyanın yolu";
        String hedefDosya = "Hedef dosyanın yolu";
        
        try {
            //Kopyalama işlemi için InputStream ve OutputStream nesnelerinizi oluşturun.
            FileInputStream fis = new FileInputStream(kaynakDosya);
            FileOutputStream fos = new FileOutputStream(hedefDosya);
            
            //Kopyalanacak satırın ilk harfinin yerini belirtin.
            int offset = 0;
            //Kopyalanacak satirin boyutunu tanımlayın.
            int satirinboyutu = 0;
            //Kopyalanacak satır için array oluşturun.
            byte[] satir = new byte[1024];
            
            //İlk satırı okuyup boyutunu alın.
            satirinboyutu = fis.read(satir);
            
            //Okunan satırların boyutu -1 değilse, yani sona gelinmediyse kopyalayın.
            while (satirinboyutu != -1) {
                //Hedef dosyaya yazın.
                fos.write(satir, offset, satirinboyutu);
                //Yeni bir satır okuyun.
                satirinboyutu = fis.read(satir);
            }
            
            //Her iki dosyayı da kapatın.
            fis.close();
            fos.close();
            
        }
        catch (IOException e) {
            //Bir hata durumunda programınıza uyarı verdirin.
            System.out.println("Bir hata oluştu " + e);
        }
    }
}

Yorumlar

Bu blogdaki popüler yayınlar

İç İçe Döngüler

CSS Bir Elemanın Genişliği ve Yüksekliği

JavaScript Dilinde Fonksiyon Çağırma Teknikleri