2016-01-17 7 views
15

में स्कैला/जावा में फ़ाइलों को इटरेट करना यह प्रतीत होता है कि एनओओ .list एक धारा लौटाता है जो प्रति उपभोग करने पर एक फ़ाइल डिस्क्रिप्टर पर रखता है, जब तक .close पूरी स्ट्रीम पर नहीं कहा जाता है। इसका मतलब है कि 1000 फाइलों के साथ डेटा निर्देशिका सामान्य ulimit मानों के विरुद्ध आसानी से ब्रश कर सकती है। इस फ़ाइल डिस्क्रिप्टर संचय का समग्र प्रभाव, नेस्टेड ट्रैवर्सल से निपटने के दौरान आगे बढ़ता है।ओ (1) ओपन फाइल डिस्क्रिप्टर

ओएस फ़ाइल सूची कमांड पर कॉल करने के लिए नीचे जाने के अलावा, बड़ी निर्देशिकाओं की फ़ाइलों पर पुन: प्रयास करने का एक वैकल्पिक तरीका क्या हो सकता है? यदि बड़ी निर्देशिका की फ़ाइलों को पुन: सक्रिय किया जाए तो यह अच्छा होगा, एक फ़ाइल डिस्क्रिप्टर केवल वर्तमान पुनरावृत्त फ़ाइल के अनुसार ही बनाए रखा जाएगा, जैसा कि उचित स्ट्रीम सेमेटिक्स द्वारा निहित किया गया है।

संपादित करें:

listjava.nio.file.Path की एक जावा स्ट्रीम कौन सा API कॉल प्रत्येक आइटम leaner यात्रा के लिए है, न कि केवल जब पूरे धारा को बंद कर दिया जा रहा है की तुलना में धारा पर बंद करने संसाधित होने के बाद किया गया है, के लिए इस्तेमाल किया जाएगा देता है? स्कैला में, इसे here से बेहतर, बेहतर फ़ाइलों से एपीआई रैपर का उपयोग करके आसानी से जोड़ा जा सकता है।

+0

"करने के लिए फ़ाइल प्रति एक फ़ाइल वर्णनकर्ता दोहराया पर रखती है, जब तक .close पर कहा जाता है पूरी धारा "आप उस निष्कर्ष पर कैसे आए? – Tunaki

+1

मैं जेएमएक्स (ओबंटू पर ओराकल जावा 8 पर स्कैला 2.11) के माध्यम से फाइल डिस्क्रिप्टरों को गिनने के बाद, '.list' के परिणाम को दोबारा शुरू करने के बाद और पुनरावृत्ति के बाद' बंद 'के बिना कॉल करने के बाद उस निष्कर्ष पर आया। – matanster

+1

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

उत्तर

2

जब मैंने स्ट्रीम बंद नहीं किया तो मैं उसी समस्या (विंडोज सर्वर 2012 आर 2 पर) चला गया। जब तक जेवीएम बंद नहीं हो जाता तब तक मेरे द्वारा पुन: उपयोग की जाने वाली सभी फ़ाइलें रीड मोड में खुली थीं। हालांकि, यह मैक ओएस एक्स पर नहीं हुआ था और चूंकि स्ट्रीम FileSystemProvider और DirectoryStream के ओएस-निर्भर कार्यान्वयन पर निर्भर करती है, मुझे लगता है कि यह समस्या ओएस-निर्भर भी हो सकती है।

@Ian McLaird टिप्पणी के विपरीत, यह Files.list() दस्तावेज में बताया गया है कि

फाइल सिस्टम संसाधनों का समय पर निपटान की आवश्यकता है, कोशिश के साथ-संसाधनों निर्माण सुनिश्चित करना है कि इस्तेमाल किया जाना चाहिए धारा संचालन पूरा होने के बाद स्ट्रीम की करीबी विधि लागू की जाती है।

एक DirectoryStream निर्माण पर खोला जाता है और करीब विधि लागू द्वारा बंद कर दिया गया है:

लौटे धारा एक DirectoryStream, जिसका जावाडोक कहते है। एक निर्देशिका स्ट्रीम बंद करना स्ट्रीम से जुड़े किसी भी संसाधन को जारी करता है। स्ट्रीम को बंद करने में विफलता के परिणामस्वरूप संसाधन रिसाव हो सकता है।

मेरे समाधान सलाह का पालन करें और उपयोग करें जब मैं धारा ठीक से बंद (ऊपर try-with-resources निर्माण में प्रयोग किया जाता) try-with-resources

try (Stream<Path> fileListing = Files.list(directoryPath)) { 
    // use the fileListing stream 
} 

निर्माण, फ़ाइल हैंडल तुरंत रिहा कर दिया गया गया था।

File directory = new File("/path/to/dir"); 
File[] files = directory.listFiles(); 
if (files != null) { // 'files' can be null if 'directory' "does not denote a directory, or if an I/O error occurs." 
    // use the 'files' array or convert to a stream: 
    Stream<File> fileStream = Arrays.stream(files); 
} 
:

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

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

+0

आप अपने मामले में धारा को बंद करने के साथ पर्याप्त क्यों नहीं थे? आप मेरे अनुभव को प्रतिबिंबित करते हैं जिसमें एक फ़ाइल हैंडलर प्रति फ़ाइल (और संचित) प्रति फ़ाइल प्रतिरक्षित किया गया था, जिसे बाद में मैं पुन: पेश नहीं कर सका। – matanster

+0

हालांकि मेरा प्रश्न एक गैर-प्रश्न का प्रकार था, क्योंकि, मैं पुन: पेश नहीं कर सका कि फ़ाइल हैंडलर को केवल निर्देशिका को पुन: स्थापित करके लिया गया था, मैं यहां इनाम प्रदान कर रहा हूं क्योंकि यह उत्तर समग्र मामले पर सबसे अधिक प्रकाश डालने लगता है, शायद उपयोगी रूप से अन्य मामलों/खोजों के लिए भी। इसके अलावा मैं पैनोरमिक और शोध उन्मुख उत्तर के लिए बहुत आभारी हूं। – matanster

+0

@matanster: प्रशंसा के लिए धन्यवाद! मुझे यकीन नहीं है कि क्या हम एक-दूसरे को सही ढंग से समझते हैं - शुरुआत में मैंने ** ** स्ट्रीम बंद नहीं किया था और जैसा आपने किया था उसी मुद्दे पर भाग गया। जब मैंने 'कोशिश-संसाधनों' निर्माण का उपयोग किया ** यह ** मदद की और फ़ाइल हैंडल तुरंत जारी किए गए (लेकिन केवल स्ट्रीम बंद करने के बाद)। मैंने उस पर जोर देने के लिए जवाब संपादित किया। मैं मैक ओएस एक्स पर विकास कर रहा था जहां यह समस्या नहीं हुई थी, लेकिन जब मैंने विन सर्वर 2012 आर 2 पर तैनात किया, तो ऐसा हुआ। –

4

यदि ऐसा होता है तो पुराने स्कूल java.io.File का उपयोग क्यों न करें?

File folder = new File(pathToFolder); 
String[] files = folder.list(); 

lsof के साथ परीक्षण किया और ऐसा लगता है कि सूचीबद्ध फ़ाइलों की कोई की तरह खुला है। आप सरणी को किसी सूची या स्ट्रीम में बाद में परिवर्तित कर सकते हैं। जब तक कि निर्देशिका बहुत बड़ी या रिमोट न हो, तब तक मैं पथ वस्तुओं और कचरा इकट्ठा करने या किसी भी तरह उन्हें नष्ट करने की कोशिश करता हूं।

1

आप अपाचे FileUtils पुस्तकालय है, जो पुराने java.io.File.listFiles का उपयोग का उपयोग कर सकते internaly काम करते हैं:

Iterator<File> it = FileUtils.iterateFiles(folder, null, true); 
while (it.hasNext()) 
{ 
    File fileEntry = (File) it.next(); 
} 
संबंधित मुद्दे