"Merhaba! Bugünkü dersimizde Java'daki girdi ve çıktı akışları ( Java I/O ) hakkındaki konuşmamıza devam edeceğiz. Bu konuyla ilgili ilk ders değil ve kesinlikle son da olmayacak :) Olduğu gibi Java dili, G/Ç ile çalışmak için pek çok yol sağlar. Bu işlevi uygulayan epeyce sınıf vardır, bu yüzden bunları birkaç derse ayırdık - böylece baştan kafanız karışmaz :) Geçmişte derslerin
BufferedReader
yanı sıra InputStream
soyut sınıflara ve birkaç alt sınıfa değindik.Bugün OutputStream
3 yeni sınıfı ele alacağız: FileInputStream
, FileOutputStream
, ve BufferedInputStream
.
FileOutputStream sınıfı
Sınıfın temel amacı,FileOutputStream
bir dosyaya bayt yazmaktır. Hiçbir şey karmaşık değil :), soyut FileOutputStream
sınıfın uygulamalarından biridir OutputStream
. Kurucuda, bu sınıfın nesneleri ya hedef dosyanın yolunu (baytların yazılması gereken yer) ya da bir File
nesneyi alır. Her birinin örneklerini inceleyeceğiz:
public class Main {
public static void main(String[] args) throws IOException {
File file = new File("C:\\Users\\Username\\Desktop\\test.txt");
FileOutputStream fileOutputStream = new FileOutputStream(file);
String greetings = "Hi! Welcome to CodeGym — The best site for would-be programmers!";
fileOutputStream.write(greetings.getBytes());
fileOutputStream.close();
}
}
Nesneyi oluştururken File
, yapıcıya istenen yolu geçtik. Önceden oluşturmamıza gerek yok: eğer mevcut değilse, program onu yaratacaktır. Ayrıca, fazladan bir nesne oluşturmadan, yalnızca yolla bir dize geçirerek de yapabilirsiniz:
public class Main {
public static void main(String[] args) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Username\\Desktop\\test.txt");
String greetings = "Hi! Welcome to CodeGym — The best site for would-be programmers!";
fileOutputStream.write(greetings.getBytes());
fileOutputStream.close();
}
}
Her iki durumda da sonuç aynı olacaktır. Dosyamızı açabilir ve orada aşağıdakileri görebiliriz:
Hi! Welcome to CodeGym — The best site for would-be programmers!
Ama burada bir nüans var. Yukarıdaki örnekteki kodu art arda birkaç kez çalıştırmayı deneyin. Sonra dosyaya bakın ve şu soruyu cevaplayın: kaç satırı var? Sadece bir tane. Ancak kodu birkaç kez çalıştırdınız. Her seferinde verilerin üzerine yazıldığı ortaya çıktı - eskinin yerini yenisi alıyor. Bu bize uymuyorsa ve dosyaya sırayla yazmamız gerekiyorsa ne yapacağız? Bir dosyaya arka arkaya üç kez selamlamamızı yazmak istersek ne olur? Her şey çok basit. Dil, her durumda hangi davranışa ihtiyacımız olduğunu bilemediğinden, FileOutputStream
yapıcı ek bir parametre alabilir -boolean append
. Değeri true ise, veriler dosyanın sonuna yazılacaktır. Yanlış ise (ve varsayılan olarak yanlıştır), tüm eski veriler silinecek ve yeni verilerle değiştirilecektir. Değiştirilen kodumuzu üç kez çalıştırarak bunu kontrol edelim:
public class Main {
public static void main(String[] args) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Username\\Desktop\\test.txt", true);
String greetings = "Hi! Welcome to CodeGym — The best site for would-be programmers!\r\n";
fileOutputStream.write(greetings.getBytes());
fileOutputStream.close();
}
}
Dosya içeriği:
Hi! Welcome to CodeGym — The best site for would-be programmers!
Hi! Welcome to CodeGym — The best site for would-be programmers!
Hi! Welcome to CodeGym — The best site for would-be programmers!
Şimdi bu farklı! G/Ç sınıflarını kullanırken bu özelliği unutmayın. close()
Görevler üzerinde saatler harcadığım, saatlerce beynimi zorladığım, verilerimin dosyalardan nasıl kaybolduğunu anlamaya çalıştığım bir zaman vardı :) Ve tabii diğer I/O sınıflarında olduğu gibi, yöntemi kullanmayı unutmayın ücretsiz kaynaklara.
FileInputStream sınıfı
BununFileInputStream
tersi bir amacı vardır — bir dosyadan bayt okumak. Tıpkı FileOutputStream
inherits gibi OutputStream
, bu sınıf da soyut sınıftan türemiştir InputStream
. " test.txt " dosyamıza birkaç satırlık bir metin yazacağız :
"So close no matter how far
Couldn't be much more from the heart
Forever trusting who we are
And nothing else matters"
Aşağıdakileri kullanarak bir dosyadan veri okumak nasıl görünür FileInputStream
?
public class Main {
public static void main(String[] args) throws IOException {
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\test.txt");
int i;
while((i=fileInputStream.read())!= -1){
System.out.print((char)i);
}
}
}
Dosyadan bir byte okuyoruz, okunan byteları karaktere çeviriyoruz ve konsolda görüntülüyoruz. Ve işte konsol çıktısı:
So close no matter how far
Couldn't be much more from the heart
Forever trusting who we are
And nothing else matters
BufferedInputStream sınıfı
BufferedInputStream
Geçmiş derslerdeki bilgileri göz önünde bulundurarak, sınıfa neden ihtiyaç duyduğumuzu ve kıyasla ne gibi avantajları olduğunu kolayca söyleyebilirsiniz FileInputStream
:) Zaten arabelleğe alınmış akışlarla karşılaştık, bu yüzden okumaya devam etmeden önce tahmin etmeye (veya hatırlamaya) çalışın :) Arabelleğe alınmış akışlar, esas olarak G/Ç'yi optimize etmek için gereklidir. Bir dosyadan okumak gibi bir veri kaynağına erişmek, performans açısından pahalı bir işlemdir ve her baytı okumak için bir dosyaya erişmek israftır. Bu nedenle, BufferedInputStream
verileri her seferinde bir bayt olarak değil, bloklar halinde okur ve bunları geçici olarak özel bir arabellekte saklar. Bu, dosyaya erişme sayımızı azaltarak programı optimize etmemizi sağlar. Bunun neye benzediğini görelim:
public class Main {
public static void main(String[] args) throws IOException {
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\test.txt");
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream, 200);
int i;
while((i = bufferedInputStream.read())!= -1){
System.out.print((char)i);
}
}
}
Burada bir nesne oluşturduk BufferedInputStream
. Yapıcısı, sınıfın bir örneğini InputStream
veya soyundan herhangi birini alır, öyle FileInputStream
yapacaktır. Ek bir bağımsız değişken olarak arabellek boyutunu bayt cinsinden alır. Bu argüman sayesinde, veriler artık dosyadan bir seferde bir bayt değil, bir seferde 200 bayt okunacak! Dosya erişimi sayısını ne kadar azalttığımızı bir düşünün. Performansı karşılaştırmak için, büyük bir metin dosyası (birkaç megabaytlık metin) alabilir ve okumanın ve konsola çıkışın milisaniye cinsinden ne kadar sürdüğünü FileInputStream
ve kullanarak karşılaştırabilirsiniz BufferedInputStream
. İşte her iki seçeneği de gösteren kod:
public class Main {
public static void main(String[] args) throws IOException {
Date date = new Date();
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\textBook.rtf");
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
int i;
while((i = bufferedInputStream.read())!= -1){
System.out.print((char)i);
}
Date date1 = new Date();
System.out.println((date1.getTime() - date.getTime()));
}
}
public class Main {
public static void main(String[] args) throws IOException {
Date date = new Date();
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\26951280.rtf");
int i;
while((i = fileInputStream.read())!= -1){
System.out.print((char)i);
}
Date date1 = new Date();
System.out.println((date1.getTime() - date.getTime()));
}
}
Bilgisayarımda 1.5 MB'lık bir dosyayı okurken FileInputStream
işi ~3500 milisaniyede tamamladım ama BufferedInputStream
~1700 milisaniyede başardım. Gördüğünüz gibi, arabelleğe alınmış akış işi optimize ederek yarıya indirdi! :) G/Ç sınıflarını incelemeye devam edeceğiz — yakında görüşürüz!
GO TO FULL VERSION