2009-10-15 8 views
5

मेरे पास एक लॉग फ़ाइल है जो हर सेकेंड को अपडेट हो जाती है। मुझे समय-समय पर लॉग फ़ाइल को पढ़ने की ज़रूरत है, और एक बार जब मैं पढ़ता हूं, तो मुझे पढ़ने वाली अंतिम पंक्ति के अंत में फ़ाइल पॉइंटर स्थिति को स्टोर करने की आवश्यकता होती है और अगले आवधिक पढ़ने में मुझे उस बिंदु से शुरू करना चाहिए।जावा में फ़ाइल पॉइंटर्स को संभालने का कुशल तरीका? (फ़ाइल पॉइंटर के साथ BufferedReader का उपयोग करना)

वर्तमान में, मैं जावा में एक यादृच्छिक अभिगम फ़ाइल का उपयोग कर रहा हूं और ऑफसेट स्थिति पर जाने के लिए seek() विधि प्राप्त करने के लिए getFilePointer() विधि का उपयोग कर रहा हूं।

हालांकि, मैंने फ़ाइल के कुशल पढ़ने के लिए BufferredReader का उपयोग करने के लिए अधिकांश लेखों और जावा दस्तावेज़ अनुशंसाओं में भी पढ़ा है। BufferedReader का उपयोग करके मैं इसे कैसे प्राप्त कर सकता हूं (फ़ाइल पॉइंटर प्राप्त कर रहा हूं और अंतिम पंक्ति में जा रहा हूं), या क्या इस कार्य को प्राप्त करने के लिए कोई अन्य कुशल तरीका है?

उत्तर

4

तरीकों में से एक जोड़े है कि काम करना चाहिए:

  • एक FileInputStream का उपयोग कर, छोड़() बाइट्स की प्रासंगिक संख्या फ़ाइल खोलते हैं, तो धारा के आसपास BufferedReader (एक InputStreamReader के माध्यम से) लपेट;
  • फ़ाइल खोलें (या तो FileInputStream या RandomAccessFile के साथ), चैनल पर अंतर्निहित FileChannel, कॉल स्थिति() प्राप्त करने के लिए स्ट्रीम/RandomAccessFile पर getChannel() को कॉल करें, फिर चैनल से इनपुट स्ट्रीम प्राप्त करने के लिए Channels.newInputStream() को कॉल करें चैनल, जिसे आप इनपुटस्ट्रीम रीडर को पास कर सकते हैं -> BufferedReader।

मैंने यह देखने के लिए ईमानदारी से प्रोफाइल नहीं किया है कि कौन सा बेहतर प्रदर्शन-योग्य है, लेकिन आपको देखना चाहिए कि आपकी स्थिति में कौन सा बेहतर काम करता है।

RandomAccessFile के साथ समस्या अनिवार्य रूप से है कि इसकी readLine() विधि बहुत अक्षम है। यदि आपके लिए आरएएफ से पढ़ना सुविधाजनक है और लाइनों को विभाजित करने के लिए अपनी खुद की बफरिंग करें, तो आरएएफ प्रति से कुछ भी गलत नहीं है - बस इसकी पढ़ाई रेखा() को खराब तरीके से लागू किया गया है

1

नील कॉफ़ी का समाधान अच्छा है यदि आप निश्चित लंबाई फाइलें पढ़ रहे हैं। हालांकि उन फ़ाइलों के लिए जिनमें परिवर्तनीय लम्बाई है (डेटा आ रहा है) BufferedReader का उपयोग सीधे FileInputStream या FileChannel इनपुटस्ट्रीम पर इनपुट इनपुट स्ट्रीमर के माध्यम से करने में कुछ समस्याएं हैं।

  • 1) आप चाहते हैं पूर्व मामलों पर विचार के लिए कुछ वर्तमान फ़ाइल लंबाई करने के लिए ऑफसेट का डेटा पढ़ने की। तो आप FileInputStream/FileChannel (एक इनपुटस्ट्रीम रीडर के माध्यम से) पर BR का उपयोग करते हैं और इसकी रीडलाइन विधि का उपयोग करते हैं। लेकिन जब आप डेटा पढ़ने में व्यस्त रहते हैं तो कहें कि कुछ डेटा जोड़ा गया है जो बीएफ की पढ़ाई को आपके द्वारा अपेक्षित की तुलना में अधिक डेटा पढ़ने के लिए कारण बनाता है (पिछली फ़ाइल लंबाई)

  • 2) आपने पढ़ा सामान पूरा किया लेकिन जब आप पढ़ने की कोशिश करते हैं वर्तमान फ़ाइल लंबाई/चैनल स्थिति कुछ डेटा अचानक जोड़ा गया है जो वर्तमान फ़ाइल लंबाई/चैनल स्थिति को बढ़ाने का कारण बनता है लेकिन आप इससे पहले ही कम डेटा पढ़ चुके हैं।

ऊपर दोनों मामलों में यह वास्तविक डेटा आप पढ़ लिया है पता करने के लिए

तो (तुम सिर्फ डेटा की लंबाई उपयोग नहीं कर सकते ReadLine का उपयोग करना पढ़ें क्योंकि यह गाड़ी वापसी जैसे कुछ वर्ण को छोड़ देता है) के लिए मुश्किल है buffered बाइट्स में डेटा को पढ़ने के लिए बेहतर है और इसके आसपास एक BufferedReader wrapper का उपयोग करें।मैं इस

/** 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

मैं एक ऐसी ही समस्या थी जैसे कुछ तरीकों को लिखा था और मैं इस वर्ग BufferedStream से लाइनों लेते हैं, और गिनती कितने बाइट्स आप अब तक getBytes() का उपयोग करके पढ़ा है करने के लिए बनाया। हम मानते हैं कि रेखा विभाजक के पास डिफ़ॉल्ट रूप से एक बाइट है, और हम काम करने के लिए seek() के लिए BufferedReader दोबारा उदाहरण देते हैं।

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; 
    } 
} 
संबंधित मुद्दे