Monday, July 27, 2009

Java LineNumberReader

Bu yazıyı ingilizce yazarım diye düşünüyordum fakat klavyenin başına geçince iş değişti. Bu sefer de işin kolayına kaçıyorum. Bu günlüğe ilk başladığım zamanlarda yazılarım ingilizceydi. Bakınız : Volatile Variables In JAVA. İngilizce yazmanın şöyle bir avantajı oluyor, yazınızı dzone, digg gibi sosyal link paylaşım sitelerine gönderdiğiniz anda tahmin edemeyeceğiniz kadar çok ziyaretçi geliyor sitenize. dzone, reddit, digg benzeri türkçe link paylaşım sitelerini pek bilmiyorum ama araştırıp yazıları oraya eklesem iyi olacak galiba ;) Sonuçta bu yazıları benim gibi yazılım meraklıları okusun diye yazıyorum. Fikirlerimi ve yazılarımı ne kadar çok kişi okursa o kadar çok geribesleme alabilirim diye düşünüyorum. Google'ın satın aldığı feedburner servisinin söylediğine göre ben dahil bu günlüğü takip eden 16 kişi var :D

İstanbul'da 3 büyük GSM operatöründen birisinde yazılım geliştirme departmanında çalışıyorum. (Hangi operatorde çalıştığımı merak edenler için ipucu: "Fark var!!!"). İçinde milyonlarca satır olan bir text dosyasını işleyecek bir java uygulaması yazmam gerekti. Uygulamanın yapacağı iş çok basit, satır satır tüm dosyayı okuyup her satır için belirli işleri çalıştıracak.

İşlenecek dosya içinde çok fazla satır olduğu için uygulamanın çalışma süresi de yarım saatten fazla oluyor. Uygulamayı başlattıktan sonra işin yüzde kaçının tamamlandığını ekrana yazdırmak için başlangıçta dosya içinde kaç satır olduğunu bilmek yeterli. Bunun için iki yöntem var.


  • Birinci yöntem dosyayı açıp satır satır taramak ve her satırda satır sayısı sayacını bir artırmak.
  • İkinci yöntem java.util.LineNumberReader sınıfını kullanmak.

Aşağıdaki kod parçası iki yöntemin çalışma sürelerini karşılaştırmak için yazıldı. 10 milyon satırlı bir deneme dosyası ile 100 iterasyonun ortalamasını alarak elde ettiğim sonuç:

LineNumberReader average : 388 miliseconds.
FileScanner average : 839 miliseconds.

Birinci yöntem ile 10 milyon satırlı bir dosyanın satır sayısını bulmak 839 milisaniye sürerken ikinci yöntem ile 388 milisaniye sürmüş.


package util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;


public class LineNumberReaderTest {

public static void main(String[] args) throws IOException {
LineNumberReaderTest test = new LineNumberReaderTest();
String filePath = args[0];
File textFile = new File(filePath);
int numberOfIterations = 100;
int result_1 = test.testByLineNumberReader(numberOfIterations, textFile);
int result_2 = test.testByFileScan(numberOfIterations, textFile);
assert result_1 == result_2;
}


private int testByLineNumberReader(int numberOfIterations, File textFile) throws IOException {
int numberOfLines = 0;
long start = System.currentTimeMillis();
for (int i = 0; i < numberOfIterations; i++) {
numberOfLines = this.numberOfLinesByLineNumberReader(textFile);
}
long diff = System.currentTimeMillis() - start;
System.out.println("LineNumberReader average : " + diff/numberOfIterations + " miliseconds.");
return numberOfLines;
}


public int testByFileScan(int numberOfIterations, File textFile) throws IOException {
int numberOfLines = 0;
long start = System.currentTimeMillis();
for (int i = 0; i < numberOfIterations; i++) {
numberOfLines = this.numberOfLinesByScanningFile(textFile);
}
long diff = System.currentTimeMillis() - start;
System.out.println("FileScanner average : " + diff/numberOfIterations + " miliseconds.");
return numberOfLines;
}

/**
* Dosyayı satir satir gezerek satir sayisini bulmaya yarar
* @param textFile
* @return dosyadaki satir sayisi
* @throws IOException
*/
public int numberOfLinesByScanningFile(File textFile) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new FileReader(textFile));
int numberOfLines = 0;
while(bufferedReader.readLine() != null) {
numberOfLines++;
}
return numberOfLines;
}

/**
* LineNumberReader sinifini kullanarak satir sayisini verir.
* @param textFile
* @return dosyadaki satir sayisi
* @throws IOException
*/
public int numberOfLinesByLineNumberReader(File textFile) throws IOException {
LineNumberReader lineNumberReader = new LineNumberReader(new FileReader(textFile));
lineNumberReader.skip(textFile.length());
return lineNumberReader.getLineNumber();
}
}


Merak ettiğim bir konu var. Ben bu LineNumberReader sınıfına ilk defa iki gün önce rastladım. Siz böyle bir sınıfın varlığını biliyor muydunuz?

Son olarak aklımdayken söyleyeyim. 10 milyon satırlık test dosyasını aşağıdaki komut ile oluşturdum:

ilkinulas@tututil:/tmp$ seq 10000000 > deneme.txt
ilkinulas@tututil:/tmp$ wc -l deneme.txt
10000000 deneme.txt

2 comments:

Abidin said...

hocam merhaba,
ben denedim fakat yapamadım. hatam nerde soyleye bilir misin?


try {
satırokuyucu = new LineNumberReader(new FileReader("C://öğretmenx.3-18//"+gelenİsim));
} catch (FileNotFoundException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
try {
satırokuyucu.skip(("C://öğretmenx.3-18//"+gelenİsim).length());
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
satırsayısı= satırokuyucu.getLineNumber();

System.out.println(satırsayısı);

İlkin Ulaş BALKANAY said...

Merhaba, derleyip calistirdiginda nasil bir hata veriyor?