Skip to main content

Java’da Dosya Kopyalama işlemleri ve performans

javaTekrardan merhaba. Kısa bir süre önce Yeniden Bloglamaya Başlamak diye bir yazı kaleme almış ve uzun süren sessizliği bozmuştum. Madem öyle, kaldığımız yerden devam edelim.

Bu yazıda Java’da dosya kopyalama yöntemleri üzerine değineceğim. Java’da dosya kopyalamak için kullanılan yöntem tek değil. Birden fazla yöntemle bu işi halledebilirsiniz. Ben bu yazıda bu yöntemlerden en çok bilinen yöntem olan File Stream ve Java 7 ile birlikte gelen Java NIO kütüphanesinde bulunan File Channel yöntemlerini irdeleyeceğim.

Bu yöntemlerden ilki olan File Stream yöntemi aslında bütün standart Java kitaplarında ortaya konan bir yöntem. Ama bu yöntemin bazı dezavantajları var. Bu yöntem  Bu yöntemde bir bir Buffer oluşturuyoruz ve buffer’a  döngü içinde genelde 1 Byte’lik veriler okuyarak dosyamızı kopyalıyoruz. Ama özellikle büyük boyutlu dosyalarda bu yöntem oldukça performans kaybına sebep olabiliyor.

Bu sebeple olsa gerek ki Java 7’de gelen Java NIO’ (Java New Input Ouput) da Java’cı abiler File Channel diye bir şey eklemişler. Bu yeni yöntem ile hem dosya kopyalama işi kolaylaşmış hem de hızlanmış. Üstelik bu yeni yöntemde bir döngü de kullanmak zorunda değiliz. Java geliştiricileri sizi düşünmüş ve sizin için arka planda her şeyi halletmiş.

Şimdi yavaş yavaş anlattığımız şeyleri somutlaştırmaya başlayalım. İlk olarak standart yöntem olan Stream için bir Metod yazalım. Bu Metod bir Kaynak dosya  ve bir hedef dosya yolu alıyor.

 

private static void copyFileStream(File sourceFile, File targetFile)
            throws IOException {
        InputStream input = null;
        OutputStream output = null;
        try {
            input = new FileInputStream(sourceFile);
            output = new FileOutputStream(targetFile);
            byte[] buf = new byte[1024];
            int bytesRead;
            while ((bytesRead = input.read(buf)) > 0) {
                output.write(buf, 0, bytesRead);
            }
        } finally {
            try {
                //olurda dosyalar bulunamaz ve null değer dönerse
                //diye kontrol yapalım
                if (input != null && output != null) {
                    input.close();
                    output.close();
                }
            } catch (Exception e) {
                System.out.println("Hata" + e.getMessage());
            }

        }
    }

Bu metodu inceleyecek olursak. Standart olarak Stream ile işlemler yapacağımız için Bir InputStream birde OutputStream tanımlanıyor. Ve metoda gönderilen kaynak dosya üzerinden byte byte okuma yapılarak buffer’a yazılıyor. Tabi ki her dosya işleminde olduğu gibi Try-Catch istisna yapısını kullanıyoruz ki olası bir dosya yolu hatasında veya okuma yazma hatasında hata fırlatabilelim.

Şimdide Java 7’den sonra hayatımıza giren File Channel için bir yöntem yazalım.


private static void copyFileChannels(File sourceFile, File targetFile)
throws IOException {
FileChannel inputChannel = null;
FileChannel outputChannel = null;
try {
inputChannel = new FileInputStream(sourceFile).getChannel();
outputChannel = new FileOutputStream(targetFile).getChannel();
outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
} finally {

try {

if (inputChannel != null && outputChannel != null) {

inputChannel.close();
outputChannel.close();
}

} catch (Exception e) {
System.out.println("Hata " + e.getMessage());
}

}
}



Bu yöntemde bir kaynak dosya ve hedef dosya yolu alıyor. Kodun şu kısımlarına dikkat edelim.


inputChannel = new FileInputStream(sourceFile).getChannel();
outputChannel = new FileOutputStream(targetFile).getChannel();
outputChannel.transferFrom(inputChannel, 0, inputChannel.size());

inputChannel değişkenine .getChannel() metodu kullanarak  bu kanaldan kuma yapacağız diyoruz. Aynı şekilde outputChannel ile de okuduğumuzu yazacağımız kanalı belirtiyoruz. transferForm isimli metodu kullanarakta hedefimize dosyayı kopyalamaya başlıyoruz. Bu metodu üç parametre alıyor.

transferForm(kaynakDosya,neredenBaslanacak,nereyeKadar)

Birinci parametreden nereden kopyalama yapılacağı belirtiliyor. Biz kaynak dosyamızı buraya gönderdik. İkinci parametre de ise dosyanın neresinden başlanacağı belirtiliyor. Biz komple bir kopyalama işlemi yapmak istiyoruz. Bu sebeple ikinci parametreyi 0 gönderdik. 0.Byte'dan başla kaynak dosyanın boyutu kadar veriyi hedef dosyamıza yaz diyoruz kısaca bu metodla. Kaynak dosyanın boyutunu da inputChannel.size() diyerek alıyoruz.

Gördüğünüz gibi DÖNGÜ Yok!

Karışıklık yok!

Java sizin için arka planda herşeyi halllediyor.

Üstelik daha hızlı bir şekilde.

Hız olarak test etmek için hemen bir test kodu yazalım.


public static void main(String[] args) throws IOException {

//Dosya yollarımızı belirtiyoruz.
File sourceFile = new File("C:\\Users\\Aytac\\Downloads\\Documents\\maven.pdf");
File targetFile = new File("C:\\Users\\Aytac\\Downloads\\Documents\\maven_yeni.pdf");

// copy file using FileStreams
long startTime = System.nanoTime();
long endTime;
copyFileStream(sourceFile, targetFile);
//Nano saniye cinsinden aradaki farkı elde ettik
endTime = (System.nanoTime() - startTime);
//nano saniyeyi SANİYE'ye çeviriyoruz.
double seconds = (double) endTime / 1000000000.0;
System.out.println("Standart Yöntemle Kopyalama Süresi= "
+ seconds);

//aynı dosyayı birde farklı yöntemle kopyalayacağız. Bu sebeple
//hedef dosyaya yeni bir isim vermek yeterli. kaynak dosya ise aynı olacak
//cunku aynı dosyayı kopyalayıp performans karşılaştırması yapacağız.
targetFile = new File("C:\\Users\\Aytac\\Downloads\\Documents\\maven_yeni_2.pdf");
startTime = System.nanoTime();
copyFileChannels(sourceFile, targetFile);
endTime = System.nanoTime();
seconds = (double) (endTime - startTime) / 1000000000.0;
System.out.println("Kanal Kopyalama Yöntemi İle = " + seconds);
}

 

Ben bu işlemi 1.8 Megabytelik bir dosyada denedim. Bende çıkan sonuçlarda ilk yöntem ile 0.045946358 saniye ile işlem sona ererken , kaynak yöntemi ile aynı dosya 0.013704676 saniyede başarılı ile kopyalandı.

Ufacık bir dosyada bile fark inanılmaz!

Artık bu farkı bildiğinize göre profesyonel arenada çalışırken Stream yöntemini kullanmazsınız diye düşünüyorum 🙂

Kaynak Dosya için tıklayın.

Bol Javalı günler 🙂

 

 

 

Share and Enjoy

  • Facebook
  • Twitter
  • Delicious
  • LinkedIn
  • StumbleUpon
  • Add to favorites
  • Email
  • RSS

Aytaç Cici

İstanbul Üniversitesi Bilgisayar Mühendisliği mezunu bir Yazılım Geliştirici. Çeşitli zamanlarda Java, PHP, C# ve Delphi gibi diller kullanarak yazılım geliştirmiştir. Bir dönem SEO alanında da çalışmalar yapmıştır.

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Email
Print