2009-10-15 9 views
5

Her saniye güncellenecek bir günlük dosyasına sahibim. Günlük dosyasını periyodik olarak okumalıyım ve okuduktan sonra, okuduğum son satırın sonunda dosya işaretçisi konumunu kaydetmem gerekiyor ve sonraki periyodik okumada bu noktadan başlamalıyım.Java'da dosya tanıtıcılarını etkin bir şekilde kullanmanın yolu nedir? (Dosya işaretçisi ile BufferedReader'ı kullanma)

Şu anda, rasgele erişim dosyasını Java'da kullanıyorum ve getFilePointer() yöntemini kullanarak offset değerini ve seek() yönteminin ofset konumuna gitmesini sağlıyorum. Ancak, çoğu makalede ve hatta bir dosyanın verimli bir şekilde okunması için BufferredReader numaralı Java dokümanı önerilerini okudum. Bu dosyaya ulaşmak için (BufferedReader'u kullanarak dosya tanıtıcısını almayı ve son satıra geçmeyi) nasıl başarabilirim veya bu görevi gerçekleştirmenin başka etkili bir yolu var mı?

cevap

4

çalışması gerekir yollardan bir çift:

  • , bayt ilgili sayı) (atlama bir FileInputStream kullanarak dosyayı açın, daha sonra (bir InputStreamReader yoluyla) dere etrafında BufferedReader sarmak;
  • dosyayı (FileInputStream veya RandomAccessFile ile) açın, stream/RandomAccessFile akışındaki bir FileChannel'i almak için kanalda arama konumunu() çağırın ve sonra bir giriş akışı almak için Channels.newInputStream() öğesini çağırın. InputStreamReader -> BufferedReader'a aktarabileceğiniz kanal.

Daha iyi bir performansa sahip olduğunu görmek için bunları açık bir şekilde belirlemedim, ancak durumunuzda hangisinin daha iyi çalıştığını görmelisiniz.

RandomAccessFile ile ilgili sorun temelde readLine() yönteminin çok etkisiz olmasıdır. RAF'den okumak ve satırları ayırmak için kendi arabelleğinizi yapmak sizin için uygunsa, o zaman RAF ile ilgili yanlış bir şey yoktur - sadece onun readLine() öğesi kötü bir şekilde uygulanmışsa

1

Neil Coffey'in çözümü sizin için iyidir. Sabit uzunluktaki dosyaları okuyor. Ancak, değişken uzunluğa sahip olan dosyalar için (veriler gelmeye devam eder), bir FileStreamReader aracılığıyla doğrudan FileInputStream veya FileChannel giriş akışında BufferedReader kullanımıyla ilgili bazı sorunlar vardır. eski davaları dikkate For You istediğiniz

  • 1) geçerli dosya uzunluğuna ofset bazı veri okumak için. Dolayısıyla, FileInputStream/FileChannel'de (bir InputStreamReader aracılığıyla) BR kullanır ve readLine yöntemini kullanırsınız. Okuduğunuz meşgulken Ancak veriler bazı veriler (önceki dosya uzunluğu)

  • 2) beklenenden daha fazla veri okumak için BF en taleb neden olan ilave var diyelim Sen readline şeyler bitmiş ama okumaya çalıştığınızda Mevcut dosya uzunluğu/kanal pozisyonu aniden eklenir, bu da mevcut dosya uzunluk/kanal pozisyonunun artmasına neden olur, fakat bundan daha az veri okudunuz. Yukarıdaki her iki durumda

o yüzden

(o satırbaşı gibi bazı karakter atlar çünkü sadece taleb kullanılarak okunan verilerin uzunluğunu kullanamazsınız) okuduğunuz gerçek verileri bilmek zordur Verileri arabelleğe alınmış baytlarda okumak ve bunun etrafında bir BufferedReader sarıcısı kullanmak daha iyidir.Ben benzer bir sorun vardı bu

/** Read data from offset to length bytes in RandomAccessFile using BufferedReader 
* @param offset 
* @param length 
* @param accessFile 
* @throws IOException 
*/ 
    public static void readBufferedLines(long offset, long length, RandomAccessFile accessFile) throws IOException{ 
    if(accessFile == null) return; 
    int bufferSize = BYTE_BUFFER_SIZE;// constant say 4096 

    if(offset < length && offset >= 0){ 
     int index = 1; 
     long curPosition = offset; 
     /* 
     * iterate (length-from)/BYTE_BUFFER_SIZE times to read into buffer no matter where new line occurs 
     */ 
     while((curPosition + (index * BYTE_BUFFER_SIZE)) < length){   

      accessFile.seek(offset); // seek to last parsed data rather than last data read in to buffer 

      byte[] buf = new byte[bufferSize]; 
      int read = accessFile.read(buf, 0, bufferSize); 
      index++;// Increment whether or not read successful 

      if(read > 0){ 

       int lastnewLine = getLastLine(read,buf); 

       if(lastnewLine <= 0){ // no new line found in the buffer reset buffer size and continue 
        bufferSize = bufferSize+read; 
        continue; 

       } 
       else{ 
        bufferSize = BYTE_BUFFER_SIZE; 
       } 

       readLine(buf, 0, lastnewLine); // read the lines from buffer and parse the line 

       offset = offset+lastnewLine; // update the last data read 

      } 

     } 



     // Read last chunk. The last chunk size in worst case is the total file when no newline occurs 
     if(offset < length){ 

      accessFile.seek(offset); 
      byte[] buf = new byte[(int) (length-offset)]; 
      int read = accessFile.read(buf, 0, buf.length); 

      if(read > 0){ 

       readLine(buf, 0, read); 

       offset = offset+read; // update the last data read 


      } 
     } 


    } 

} 

private static void readLine(byte[] buf, int from , int lastnewLine) throws IOException{ 

    String readLine = ""; 
    BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(buf,from,lastnewLine))); 
    while((readLine = reader.readLine()) != null){ 
     //do something with readLine 
     System.out.println(readLine); 
    } 
    reader.close(); 
} 


private static int getLastLine(int read, byte[] buf) { 
    if(buf == null) return -1; 
    if(read > buf.length) read = buf.length; 
    while(read > 0 && !(buf[read-1] == '\n' || buf[read-1] == '\r')) read--;  
    return read; 
} 
public static void main(String[] args) throws IOException { 
    RandomAccessFile accessFile = new RandomAccessFile("C:/sri/test.log", "r"); 
    readBufferedLines(0, accessFile.length(), accessFile); 
    accessFile.close(); 

} 
0

gibi bazı yöntemler yazdım ve BufferedStream gelen satırları almak ve o ana kadar getBytes() kullanarak okudum kaç bayt saymak için bu sınıfı yarattı. Satır ayırıcısının varsayılan olarak tek bir bayt olduğunu varsayar ve seek() için BufferedReader'u yeniden çalışır duruma getirdik.

public class FileCounterIterator { 

    public Long position() { 
     return _position; 
    } 

    public Long fileSize() { 
     return _fileSize; 
    } 

    public FileCounterIterator newlineLength(Long newNewlineLength) { 
     this._newlineLength = newNewlineLength; 
     return this; 
    } 

    private Long _fileSize = 0L; 
    private Long _position = 0L; 
    private Long _newlineLength = 1L; 
    private RandomAccessFile fp; 
    private BufferedReader itr; 

    public FileCounterIterator(String filename) throws IOException { 
     fp = new RandomAccessFile(filename, "r"); 
     _fileSize = fp.length(); 
     this.seek(0L); 
    } 

    public FileCounterIterator seek(Long newPosition) throws IOException { 
     this.fp.seek(newPosition); 
     this._position = newPosition; 
     itr = new BufferedReader(new InputStreamReader(new FileInputStream(fp.getFD()))); 
     return this; 
    } 

    public Boolean hasNext() throws IOException { 
     return this._position < this._fileSize; 
    } 

    public String readLine() throws IOException { 
     String nextLine = itr.readLine(); 
     this._position += nextLine.getBytes().length + _newlineLength; 
     return nextLine; 
    } 
} 
İlgili konular