2009-07-02 15 views
12

किसी और की प्रक्रिया एक समय में एक रेखा को जोड़कर एक CSV फ़ाइल बना रही है, जैसे घटनाएं होती हैं। मेरे पास फ़ाइल प्रारूप या अन्य प्रक्रिया पर कोई नियंत्रण नहीं है, लेकिन मुझे पता है कि यह केवल संलग्न होगा।जावा में, एक फ़ाइल को जोड़ने के लिए सबसे अच्छा/सुरक्षित पैटर्न क्या है?

जावा प्रोग्राम में, मैं इस फ़ाइल की निगरानी करना चाहता हूं, और जब एक लाइन संलग्न की जाती है तो नई लाइन पढ़ती है और सामग्री के अनुसार प्रतिक्रिया देती है। अब के लिए सीएसवी पार्सिंग मुद्दे को अनदेखा करें। परिवर्तनों के लिए फ़ाइल की निगरानी करने और एक समय में एक पंक्ति पढ़ने का सबसे अच्छा तरीका क्या है?

आदर्श रूप से यह मानक पुस्तकालय कक्षाओं का उपयोग करेगा। फ़ाइल नेटवर्क ड्राइव पर भी हो सकती है, इसलिए मुझे विफलता के लिए कुछ मजबूत चाहिए। यदि संभव हो तो मैं मतदान का उपयोग नहीं करना चाहूंगा - मैं इसके बजाय कुछ प्रकार के अवरोध समाधान पसंद करूंगा।

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

उत्तर

7

चूंकि जावा 7 पर newWatchService() विधि रहा है।

हालांकि, कुछ चेतावनियां हैं:

  • यह केवल जावा 7
  • यह एक वैकल्पिक तरीका है
  • यह केवल देखता निर्देशिका है, तो आप फ़ाइल अपने आप से निपटने करते हैं, और चिंता करने की ज़रूरत फ़ाइल चलने आदि के बारे में

जावा 7 से पहले मानक API के साथ यह संभव नहीं है।

मैं निम्नलिखित (एक 1 सेकंड अंतराल पर मतदान) की कोशिश की और यह काम करता है (बस प्रसंस्करण में प्रिंट):

private static void monitorFile(File file) throws IOException { 
    final int POLL_INTERVAL = 1000; 
    FileReader reader = new FileReader(file); 
    BufferedReader buffered = new BufferedReader(reader); 
    try { 
     while(true) { 
     String line = buffered.readLine(); 
     if(line == null) { 
      // end of file, start polling 
      Thread.sleep(POLL_INTERVAL); 
     } else { 
      System.out.println(line); 
     } 
     } 
    } catch(InterruptedException ex) { 
    ex.printStackTrace(); 
    } 
    } 

कोई और नहीं एक एक समाधान है जो एक वर्तमान उत्पादन जावा मैंने सोचा था कि का उपयोग करता है का सुझाव दिया है के रूप में मैं इसे जोड़ूंगा। यदि त्रुटियां हैं तो कृपया टिप्पणियों में जोड़ें।

+0

उपरोक्त कोड संलग्न लाइन को पढ़ने की गारंटी देते हैं? – DerekY

+1

मेरी आवश्यकता फ़ोल्डर को देखना है और जैसे ही फ़ाइल को फ़ोल्डर में जोड़ा/लिखा/स्थानांतरित किया जाता है, उस पर तत्काल कार्रवाई करें (उदाहरण के लिए फ़ाइल को ईमेल करें)। जिस समस्या में मैं चल रहा हूं वह यह है कि जब फ़ाइल बड़ी होती है, तो लिखित या प्रतिलिपि प्राप्त करने में कुछ समय लग सकता है, जबकि फ़ाइल के पहले बाइट फ़ोल्डर में लिखे जाने पर FILE_CREATE ईवेंट की घोषणा की जाती है। तो मैं तुरंत कार्रवाई नहीं कर सकता। यह निर्धारित करने का एक विश्वसनीय तरीका क्या है कि फ़ाइल पर कोई कार्रवाई करने से पहले पूरी तरह से लिखा गया है या नहीं? –

0

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

2

मानक लाइब्रेरी कक्षाओं के साथ यह संभव नहीं है। विवरण के लिए यह question देखें।

कुशल मतदान के लिए Random Access का उपयोग करना बेहतर होगा। यदि आपको फ़ाइल के अंतिम छोर की स्थिति याद है और वहां से पढ़ना शुरू होता है तो इससे मदद मिलेगी।

+0

धन्यवाद - जैसा कि मैंने प्रतिबिंबित करने के लिए प्रश्न संपादित किया है, इसका मतलब है कि मुझे मतदान समाधान की आवश्यकता है। क्या आपके पास सबसे मजबूत/कुशल क्या है इस पर कोई सुझाव है? –

3

उपयोग जावा 7 के WatchService, NIO.2

का हिस्सा WatchService एपीआई अनुप्रयोगों फ़ाइल परिवर्तन की घटनाओं के बारे में सूचित करने की आवश्यकता है के लिए बनाया गया है।

+1

वाह, जावा 7 जारी किया गया है? मुझे कुछ समय के लिए गुफा में जाना होगा। – kgiannakakis

+0

वर्तमान में या तो प्रारंभिक पहुंच पूर्वावलोकन रिलीज, या नवीनतम बाइनरी स्नैपशॉट रिलीज है। –

+2

WatchService निर्देशिका देखता है, फाइल नहीं – finnw

2

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

यहां, दो प्रक्रियाएं इन जावा कक्षाओं को निष्पादित कर रही हैं, लेकिन मुझे लगता है कि लेखन प्रक्रिया किसी अन्य एप्लिकेशन से हो सकती है। (मान लीजिए कि इसमें फ़ाइल पर एक विशेष लॉक नहीं है- क्या कुछ ऑपरेटिंग सिस्टम पर ऐसी फाइल सिस्टम लॉक हैं?)

मैंने विंडोज और लिनक्स दोनों में सफलतापूर्वक इन दो वर्गों का परीक्षण किया है। मुझे यह जानना बहुत पसंद होगा कि क्या कुछ शर्त है (उदा। ऑपरेटिंग सिस्टम) जिस पर वे असफल हो जाते हैं।

क्लास # 1:

import java.io.File; 
import java.io.FileWriter; 
import java.io.PrintWriter; 

public class FileAppender { 

    public static void main(String[] args) throws Exception { 
     if ((args != null) && (args.length != 0)) throw 
      new IllegalArgumentException("args is not null and is not empty"); 

     File file = new File("./file.txt"); 
     int numLines = 1000; 
     writeLines(file, numLines); 
    } 

    private static void writeLines(File file, int numLines) throws Exception { 
     PrintWriter pw = null; 
     try { 
      pw = new PrintWriter(new FileWriter(file), true); 
      for (int i = 0; i < numLines; i++) { 
       System.out.println("writing line number " + i); 
       pw.println("line number " + i); 
       Thread.sleep(100); 
      } 
     } 
     finally { 
      if (pw != null) pw.close(); 
     } 
    } 

} 

क्लास # 2:

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

public class FileMonitor { 

    public static void main(String[] args) throws Exception { 
     if ((args != null) && (args.length != 0)) throw 
      new IllegalArgumentException("args is not null and is not empty"); 

     File file = new File("./file.txt"); 
     readLines(file); 
    } 

    private static void readLines(File file) throws Exception { 
     BufferedReader br = null; 
     try { 
      br = new BufferedReader(new FileReader(file)); 
      while (true) { 
       String line = br.readLine(); 
       if (line == null) { // end of file, start polling 
        System.out.println("no file data available; sleeping.."); 
        Thread.sleep(2 * 1000); 
       } 
       else { 
        System.out.println(line); 
       } 
      } 
     } 
     finally { 
      if (br != null) br.close(); 
     } 
    } 

} 
+0

मेरे लिए इन दो अलग-अलग कामों को चलाना, लेकिन अगर मैं केवल फाइल मॉनिटर चलाता हूं और vim के साथ फ़ाइल.txt मैन्युअल रूप से संपादित करता हूं, तो परिवर्तनों को पहचाना नहीं जाता है। विचार? –

1

दुर्भाग्य से, TailInputStream वर्ग है, जो एक फ़ाइल के अंत की निगरानी के लिए इस्तेमाल किया जा सकता, मानक जावा मंच से एक नहीं है कक्षाएं, लेकिन वेब पर कुछ कार्यान्वयन हैं। आप http://www.greentelligent.com/java/tailinputstream पर उपयोग उदाहरण के साथ टेलर इनपुटस्ट्रीम क्लास के कार्यान्वयन को एक साथ पा सकते हैं।

5

यदि आप WatchService क्लास का उपयोग कर फ़ाइल में कोई परिवर्तन होता है तो आप फ़ाइल सिस्टम द्वारा अधिसूचित होने के लिए पंजीकरण कर सकते हैं। यह Java7, यहाँ प्रलेखन http://docs.oracle.com/javase/tutorial/essential/io/notification.html

यहाँ

करने के लिए स्निपेट कोड के लिए लिंक की आवश्यकता है कि:

public FileWatcher(Path dir) { 
    this.watcher = FileSystems.getDefault().newWatchService(); 
    WatchKey key = dir.register(watcher, ENTRY_MODIFY); 
} 

void processEvents() { 
    for (;;) { 
     // wait for key to be signalled 
     WatchKey key; 
     try { 
      key = watcher.take(); 
     } catch (InterruptedException x) { 
      return; 
     } 

     for (WatchEvent<?> event : key.pollEvents()) { 
      WatchEvent.Kind<?> kind = event.kind(); 

      if (kind == OVERFLOW) { 
       continue; 
      } 
      // Context for directory entry event is the file name of entry 
      WatchEvent<Path> ev = cast(event); 
      Path name = ev.context(); 
      Path child = dir.resolve(name); 
      // print out event 
      System.out.format("%s: %s file \n", event.kind().name(), child); 
     } 
     // reset key and remove from set if directory no longer accessible 
     boolean valid = key.reset(); 
    } 
} 
+1

क्या आप यह कहने के लिए अपना जवाब संपादित कर सकते हैं कि: यह जावा 7 में नया है, यह java.nio में है, और यह नया WatchService() एक वैकल्पिक तरीका है। शायद javadoc के लिए एक लिंक जोड़ें? –

0

पोल, या तो एक सुसंगत चक्र पर या एक यादृच्छिक चक्र पर; 200-2000ms एक अच्छा यादृच्छिक मतदान अंतराल अवधि होना चाहिए।

चेक दो बातें ...

आप, फ़ाइल विकास के लिए घड़ी तो EOF/बाइट गणना देखें, और कहा कि और लड़की सर्वेक्षण साथ fileAccess या fileWrite बार की तुलना करें होना जरूरी है। अगर (>), तो फाइल लिखी गई है।

फिर, विशेष लॉक/पढ़ने के उपयोग की जांच के साथ गठबंधन करें। अगर फ़ाइल को पढ़ा जा सकता है और यह बढ़ गया है, तो जो कुछ भी लिख रहा था वह समाप्त हो गया है।

अकेले किसी भी संपत्ति के लिए जांच करने से आपको लिखित ++ और वास्तव में उपयोग की जाने वाली गारंटी की गारंटी प्राप्त नहीं होगी।

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