2010-05-20 6 views
11

मैं एक एकीकृत लॉग फ़ाइल व्यूअर के साथ एक सॉफ्टवेयर उत्पाद पर काम कर रहा हूं। समस्या यह है कि, वास्तव में बड़ी फ़ाइलों के लिए इसकी धीमी और अस्थिर है क्योंकि जब आप लॉग फ़ाइल देखते हैं तो यह पूरी फ़ाइल को स्मृति में पढ़ता है। मैं एक नया लॉग फ़ाइल व्यूअर लिखना चाहता हूं जो इस समस्या को संबोधित करता है।बड़ी लॉग फ़ाइलों के लिए मैं जावा टेक्स्ट फ़ाइल व्यूअर कैसे लिखूं

बड़ी टेक्स्ट फ़ाइलों के लिए दर्शकों को लिखने के लिए सबसे अच्छे अभ्यास क्या हैं? नोटपैड ++ और वीआईएम जैसे संपादकों ने इसे कैसे लागू किया? मैं जावा के टेबल मॉडल के साथ एक buffered द्वि-दिशात्मक पाठ स्ट्रीम रीडर का उपयोग करने के बारे में सोच रहा था। क्या मैं सही लाइनों के साथ सोच रहा हूं और जावा के लिए ऐसे स्ट्रीम कार्यान्वयन उपलब्ध हैं?

संपादित करें: पाठ की प्रत्येक पंक्ति की शुरुआत की स्थिति को सूचीबद्ध करने के लिए फ़ाइल के माध्यम से चलाने के लिए उपयुक्त होगा ताकि कोई जानता है कि कहां से खोजना है? मुझे शायद लाइनों की मात्रा की आवश्यकता होगी, इसलिए शायद कम से कम एक बार फाइल को स्कैन करना होगा?

संपादित 2: मैंने अपना कार्यान्वयन नीचे दिए गए उत्तर में जोड़ा है। कृपया इस पर टिप्पणी करें या इसे संपादित करने के लिए इसे संपादित करें ताकि हम/अधिक सर्वोत्तम अभ्यास कार्यान्वयन पर पहुंच सकें या अन्यथा अपना स्वयं का प्रदान कर सकें।

उत्तर

4

मुझे यकीन नहीं है कि नोटपैड ++ वास्तव में यादृच्छिक पहुंच लागू करता है, लेकिन मुझे लगता है कि यह जाने का तरीका है, खासकर लॉग फ़ाइल व्यूअर के साथ, जिसका अर्थ है कि यह केवल पढ़ा जाएगा।

चूंकि आपका लॉग व्यूअर केवल पढ़ा जाएगा, आप केवल पढ़ने के लिए random access मेमोरी मैप की गई फ़ाइल "स्ट्रीम" का उपयोग कर सकते हैं। जावा में, यह FileChannel है।

फिर बस आवश्यकतानुसार फ़ाइल में चारों ओर कूदें और स्क्रीन पर केवल स्क्रीन की एक स्क्रॉलिंग विंडो प्रस्तुत करें।

FileChannel के फायदों में से एक यह है कि समवर्ती धागे फ़ाइल को खोल सकते हैं, और पढ़ना वर्तमान फ़ाइल सूचक को प्रभावित नहीं करता है। इसलिए, यदि आप किसी अन्य थ्रेड में लॉग फ़ाइल में शामिल हैं, तो यह प्रभावित नहीं होगा।

एक अन्य लाभ यह है कि आप किसी भी समय फ़ाइल आकार प्राप्त करने के लिए FileChannel के आकार विधि को कॉल कर सकते हैं।

मेमोरी मेमोरी के साथ सीधे यादृच्छिक एक्सेस फ़ाइल में समस्या, जो कुछ पाठ संपादक अनुमति देते हैं (जैसे एचएक्सडी और अल्ट्राएडिट), यह है कि कोई भी परिवर्तन सीधे फ़ाइल को प्रभावित करता है। इसलिए, परिवर्तन तत्काल हैं (लेखन कैशिंग को छोड़कर), जो कुछ उपयोगकर्ता आमतौर पर नहीं चाहते हैं। इसके बजाए, उपयोगकर्ता आमतौर पर अपने परिवर्तन तब तक नहीं करना चाहते जब तक कि वे सहेजें पर क्लिक न करें। हालांकि, चूंकि यह सिर्फ एक दर्शक है, इसलिए आपके पास समान चिंताएं नहीं हैं।

+0

धन्यवाद, मैं भी FileChannel के अलावा जो साबित हो सकता है उपयोगी –

2

एक विशिष्ट दृष्टिकोण एक खोजने योग्य फ़ाइल रीडर का उपयोग करना है, लॉग ऑफसेट के माध्यम से लाइन ऑफसेट की एक अनुक्रमणिका को रिकॉर्ड करना और अनुरोध के अनुसार फ़ाइल के एक भाग पर केवल एक विंडो प्रस्तुत करना है।

यह त्वरित डेटा में आपको आवश्यक डेटा दोनों को कम करता है और एक विजेट लोड नहीं करता है जहां इसकी 99% सामग्री वर्तमान में दिखाई नहीं दे रही है।

0

मैं आपकी सुविधा के लिए और आगे की टिप्पणियों और आलोचना के लिए यहां अपने परीक्षण कार्यान्वयन (मार्कस एडम्स और एमएसडब्ल्यू की सलाह के बाद) पोस्ट करता हूं। यह काफी तेज़ है।

मुझे यूनिकोड एन्कोडिंग सुरक्षा से परेशान नहीं है। मुझे लगता है कि यह मेरा अगला सवाल होगा। उस स्वागत पर कोई संकेत।

class LogFileTableModel implements TableModel { 

    private final File f; 
    private final int lineCount; 
    private final String errMsg; 
    private final Long[] index; 
    private final ByteBuffer linebuf = ByteBuffer.allocate(1024); 
    private FileChannel chan; 

    public LogFileTableModel(String filename) { 
     f = new File(filename); 
     String m; 
     int l = 1; 
     Long[] idx = new Long[] {}; 
     try { 
      FileInputStream in = new FileInputStream(f); 
      chan = in.getChannel(); 
      m = null; 
      idx = buildLineIndex(); 
      l = idx.length; 
     } catch (IOException e) { 
      m = e.getMessage(); 
     } 
     errMsg = m; 
     lineCount = l; 
     index = idx; 
    } 

    private Long[] buildLineIndex() throws IOException { 
     List<Long> idx = new LinkedList<Long>(); 
     idx.add(0L); 

     ByteBuffer buf = ByteBuffer.allocate(8 * 1024); 
     long offset = 0; 
     while (chan.read(buf) != -1) { 
      int len = buf.position(); 
      buf.rewind();    
      int pos = 0; 
      byte[] bufA = buf.array(); 
      while (pos < len) { 
       byte c = bufA[pos++]; 
       if (c == '\n') 
        idx.add(offset + pos); 
      } 
      offset = chan.position(); 
     } 
     System.out.println("Done Building index"); 
     return idx.toArray(new Long[] {}); 
    } 

    @Override 
    public int getColumnCount() { 
     return 2; 
    } 

    @Override 
    public int getRowCount() { 
     return lineCount; 
    } 

    @Override 
    public String getColumnName(int columnIndex) { 
     switch (columnIndex) { 
     case 0: 
      return "#"; 
     case 1: 
      return "Name"; 
     } 
     return ""; 
    } 

    @Override 
    public Object getValueAt(int rowIndex, int columnIndex) { 
     switch (columnIndex) { 
      case 0:     
       return String.format("%3d", rowIndex); 
      case 1: 
       if (errMsg != null) 
        return errMsg; 
       try { 
        Long pos = index[rowIndex]; 
        chan.position(pos); 
        chan.read(linebuf); 
        linebuf.rewind(); 
        if (rowIndex == lineCount - 1) 
         return new String(linebuf.array()); 
        else  
         return new String(linebuf.array(), 0, (int)(long)(index[rowIndex+1]-pos)); 
       } catch (Exception e) { 
        return "Error: "+ e.getMessage(); 
       } 
     }    
     return "a"; 
    } 

    @Override 
    public Class<?> getColumnClass(int columnIndex) { 
     return String.class; 
    } 

    // ... other methods to make interface complete 


} 
+0

हममम, ठीक है, मेरे कार्यान्वयन की तरह लगता है में RandomAccessFile देखा UTF-8, UTF-8 निहित आत्म सिंक्रनाइज़ करना सत्ता की वजह से सुरक्षित है।'\ N' की जांच करना जो बाइनरी 00100000 है यूटीएफ -8 में अद्वितीय है। एक बहु-बाइट अनुक्रम का हिस्सा है जो सभी बाइट्स कम से कम 8 सेट होगा। –

संबंधित मुद्दे