2016-02-10 10 views
6
 try (Stream<String> lines = Files.lines(targetFile)) { 
    List<String> replacedContent = lines.map(line -> 
             StringUtils.replaceEach(line,keys, values)) 
             .parallel() 
             .collect(Collectors.toList()); 
    Files.write(targetFile, replacedContent); 
} 

मैं फ़ाइल की प्रत्येक पंक्ति में एकाधिक टेक्स्ट पैटर्न को प्रतिस्थापित करने का प्रयास कर रहा हूं। लेकिन मैं देख रहा हूं कि "\ r \ n" (बाइट समतुल्य 10 और 13) को केवल "\ r" (केवल 10) के साथ प्रतिस्थापित किया जा रहा है और मेरे तुलना परीक्षण विफल हो रहे हैं।स्ट्रीम का उपयोग करते हुए फ़ाइल पढ़ने के दौरान न्यूलाइन को कैसे संरक्षित करें - जावा 8

मैं न्यूलाइन को संरक्षित करना चाहता हूं क्योंकि वे इनपुट फ़ाइल में हैं और जावा उन्हें छूना नहीं चाहते हैं। क्या कोई सुझाव दे सकता है कि "\ r \ n" के लिए एक अलग डिफ़ॉल्ट प्रतिस्थापन का उपयोग किए बिना ऐसा करने का कोई तरीका है या नहीं।

+0

लापता है कि के लिए खेद है: जब तक यह रिटर्न null

फिर, एक Scanner का उपयोग कर लाइनों पढ़ें। अभी जोड़ा गया। – AshwiniR

+0

बस समस्या को अलग करने के लिए replaceEach को हटा दें और इसकी फ़ाइलें.लाइन() जो ऐसा करने लगती हैं। – AshwiniR

+1

प्रतिस्थापन कहां हो रहा है? आपके द्वारा चिपकाए गए कोड ने स्ट्रिंग की एक सूची बनाई है, इसमें कोई नयालाइन वर्ण नहीं है। – mks

उत्तर

9

समस्या यह है कि Files.lines()BufferedReader.readLine() के शीर्ष पर लागू किया गया है, जो लाइन टर्मिनेटर तक एक लाइन को पढ़ता है और इसे फेंकता है। फिर, जब आप Files.write() जैसे कुछ के साथ लाइनें लिखते हैं, तो यह प्रत्येक लाइन के बाद सिस्टम-विशिष्ट लाइन टर्मिनेटर की आपूर्ति करता है, जो कि पढ़ने के लिए लाइन टर्मिनेटर से अलग हो सकता है।

यदि आप वाकई लाइन टर्मिनेटर को सुरक्षित रखना चाहते हैं जैसा कि वे हैं, भले ही वे अलग-अलग लाइन टर्मिनेटर का मिश्रण हों, फिर भी आप इसके लिए रेगेक्स और Scanner का उपयोग कर सकते हैं।

पहले एक पैटर्न है कि वैध लाइन टर्मिनेटर्स या EOF सहित एक पंक्ति से मेल खाता निर्धारित करें:

Pattern pat = Pattern.compile(".*\\R|.+\\z"); 

\\R एक विशेष LINEBREAK मिलानकर्ता कि हमेशा की तरह लाइन टर्मिनेटर्स साथ ही इसके कुछ यूनिकोड लाइन टर्मिनेटर्स कि मैंने मेल खाता है कभी नहीं सुना। :-) यदि आप सामान्य सीआरएलएफ, सीआर, या एलएफ टर्मिनेटर चाहते हैं तो आप (\\r\\n|\\r|\\n) जैसे कुछ उपयोग कर सकते हैं।

आपको उस फ़ाइल में संभावित अंतिम "पंक्ति" से मेल खाने के लिए .+\\z शामिल करना होगा जिसमें लाइन टर्मिनेटर नहीं है। सुनिश्चित करें कि रेगेक्स हमेशा कम से कम एक चरित्र से मेल खाता है ताकि स्कैनर फ़ाइल के अंत तक पहुंचने पर कोई मिलान नहीं मिलेगा।

try (Scanner in = new Scanner(Paths.get(INFILE), "UTF-8")) { 
    String line; 
    while ((line = in.findWithinHorizon(pat, 0)) != null) { 
     // Process the line, then write the output using something like 
     // FileWriter.write(String) that doesn't add another line terminator. 
    } 
} 
+0

स्टुअर्ट और अन्य, मुझे लगता है कि मैं मल्टीथ्रेड प्रोग्राम के साथ स्कैनर का उपयोग नहीं कर सकता? क्या बहुप्रचारित कार्यक्रमों के लिए इसे हासिल करने का कोई और तरीका है? – AshwiniR

+0

@AshwiniR आप एक मल्टीथ्रेड प्रोग्राम में एक समय में केवल एक थ्रेड से एकल 'स्कैनर' उदाहरण का उपयोग कर सकते हैं। एकाधिक थ्रेड अलग-अलग 'स्कैनर' उदाहरणों का उपयोग कर सकते हैं, जब तक कि एक ही उदाहरण पर कोई भी दो थ्रेड संचालित न हो। यदि आप समानांतर में एक फ़ाइल से लाइनों को संसाधित करना चाहते हैं, तो यह मुश्किल है, क्योंकि फ़ाइल पढ़ने और आउटपुट लिखना अनुक्रमिक है। यदि संभवतः प्रत्येक पंक्ति के लिए गणना की बड़ी मात्रा है तो यह समानांतर में चलने योग्य है। –

+0

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

3

आपकी स्ट्रीम की रेखाओं में कोई नयालाइन वर्ण शामिल नहीं है।

यह अच्छा होगा अगर Files.lines() के लिए विधि प्रलेखन का उल्लेख किया गया हो। हालांकि, अगर आप कार्यान्वयन का पालन करते हैं, तो अंततः BufferedReader.readLine() की ओर जाता है। उस विधि को लाइन की सामग्री, not including any line-termination characters वापस करने के लिए प्रलेखित किया गया है।

जब आप उन्हें लिखते हैं तो आप लाइनों में एक न्यूलाइन चरित्र जोड़ सकते हैं।

एक सिस्टम पर निर्भर लाइन विभाजकFiles.write() विधि आप documented in its sibling के रूप में, कॉल कर रहे हैं प्रयोग किया जाता है। आप System.lineSeparator() के साथ इस सिस्टम-निर्भर लाइन विभाजक भी प्राप्त कर सकते हैं।

यदि आप एक अलग लाइन विभाजक चाहते हैं, और जानें कि यह क्या है, आप इसे निर्दिष्ट कर सकते हैं। उदाहरण के लिए:

try (PrintStream out = new PrintStream(Files.newOutputStream(targetFile))) 
    { 
     lines.forEach(line -> out.print(line + "\r\n")); 
    } 

आप मूल फ़ाइल की लाइन विभाजक चाहते हैं, आप केवल एक विधि है कि उन बाहर स्ट्रिप्स पर भरोसा नहीं कर सकते हैं। विकल्पों में शामिल हैं:

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

चेतावनी: आपका कोड उसी फ़ाइल से पढ़ता है और लिखता है। असामान्य समाप्ति या बग के कारण आप अपना मूल डेटा खो सकते हैं।

+0

ऐसा प्रतीत होता है कि 'Files.write()' "पंक्ति का अंत" अनुक्रम जोड़ता है क्योंकि यह दी गई सूची में प्रत्येक पंक्ति को लिखता है। –

+0

मुझे लगता है कि Files.write उन्हें जोड़ रहा है लेकिन यह केवल "\ r" जोड़ रहा है। मेरी इनपुट फ़ाइल में "\ r \ n" है। मुझे Files.write() में इसे बदलने का कोई तरीका नहीं दिख रहा है !! – AshwiniR

+0

@AshwiniR - आप 'line.separator' प्रॉपर्टी को सेट करके ऐसा करने में सक्षम हो सकते हैं, लेकिन वह हैक पूरी प्रक्रिया को प्रभावित करता है। 'Files.write()' के अलावा किसी अन्य तंत्र का उपयोग करना बेहतर हो सकता है। उपरोक्त संपादित पाठ में एक उदाहरण देखें। अपनी टिप्पणी के बाद जोड़ा गया चेतावनी भी ध्यान दें। –

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