2009-07-07 10 views
33

के साथ जावा फ़ाइल इनपुट मुझे दो फ़ंक्शन में एक बड़ी फ़ाइल पढ़ने के लिए किसी प्रकार की इनपुट स्ट्रीम चीज (जैसे इनपुट इनपुट या फ़ाइल चैनल) में एक फ़ंक्शन लिखना होगा: एक बार कुछ क्षमताओं को पूर्ववत करने के लिए, और दूसरा "असली" काम करने के लिए। मैं नहीं चाहता कि पूरी फाइल एक बार में स्मृति में लोड हो (जब तक यह छोटा न हो)।रिवाइंड()/रीसेट() क्षमता

क्या कोई उचित जावा क्लास है जो इस क्षमता को प्रदान करती है? FileInputStream स्वयं चिह्न()/रीसेट() का समर्थन नहीं करता है। BufferedInputStream करता है, मुझे लगता है, लेकिन मुझे स्पष्ट नहीं है कि इसे पूरी फ़ाइल को ऐसा करने के लिए स्टोर करना है या नहीं।

सी इतना आसान है, आप बस fseek(), ftell(), और रिवाइंड() का उपयोग करें। :-(

+3

जेसन, मेरा उत्तर अन-स्वीकार करते हैं और ले कृपया [इस एक।] (Http://stackoverflow.com/a/18665678/3474) यह अच्छा है क्योंकि यह मानक मार्कबल 'इनपुटस्ट्रीम' एपीआई का एक कुशल कार्यान्वयन प्रदान करता है; 'इनपुटस्ट्रीम' का कोई उपभोक्ता पूरी फ़ाइल लोड किए बिना इसका उपयोग कर सकता है। – erickson

उत्तर

22

मुझे लगता है कि फ़ाइलChannel का संदर्भ देने वाले उत्तरों चिह्न पर हैं।

यहां एक इनपुट स्ट्रीम का एक नमूना कार्यान्वयन है जो इस कार्यक्षमता को समाहित करता है। यह प्रतिनिधिमंडल का उपयोग करता है, इसलिए यह एक वास्तविक FileInputStream नहीं है, लेकिन यह एक इनपुटस्ट्रीम है, जो आमतौर पर पर्याप्त होता है। यदि कोई आवश्यकता है तो कोई भी फाइलइनपुटस्ट्रीम का विस्तार कर सकता है।

परीक्षण किया है, अपने स्वयं के जोखिम :) पर उपयोग

public class MarkableFileInputStream extends FilterInputStream { 
    private FileChannel myFileChannel; 
    private long mark = -1; 

    public MarkableFileInputStream(FileInputStream fis) { 
     super(fis); 
     myFileChannel = fis.getChannel(); 
    } 

    @Override 
    public boolean markSupported() { 
     return true; 
    } 

    @Override 
    public synchronized void mark(int readlimit) { 
     try { 
      mark = myFileChannel.position(); 
     } catch (IOException ex) { 
      mark = -1; 
     } 
    } 

    @Override 
    public synchronized void reset() throws IOException { 
     if (mark == -1) { 
      throw new IOException("not marked"); 
     } 
     myFileChannel.position(mark); 
    } 
} 
+1

यह अब तक का सबसे अच्छा समाधान है। BufferedInput का बड़ा हिस्सा होता है, या संभावित रूप से सभी फाइलों को डबल buffered होने का कारण बनता है। यह एक बड़ा अपशिष्ट है। और RandomAccessFile I से प्राप्त नहीं होता है। nputStream, इसलिए विकल्प में एक बूंद नहीं हो सकती है जहां आप पहले से ही स्ट्रीम का उपयोग कर रहे हैं। हालांकि यह छोटी कक्षा बेहद तेज और स्मृति कुशल होना चाहिए। – Adam

+0

यह मेरे लिए बहुत अच्छा काम करता है। मैंने कन्स्ट्रक्टर को 'चिह्न (0) जोड़ा; क्योंकि मुझे 'रीसेट()' पर पहली कॉल पर" चिह्नित नहीं किया गया "त्रुटि मिल रही थी, और कम से कम मेरे मामले में, यह डिफ़ॉल्ट रीसेट स्थिति के लिए समझ में आता है 0 –

+2

यह समाधान एक छोटे से परिवर्तन के साथ, महान काम करता है। मैं रीसेट विधि के अंदर "चिह्न = -1" को हटा दूंगा। रीसेट के लिए javadocs कोई संकेत नहीं देते हैं कि यह निशान, केवल स्थिति को रीसेट करना चाहिए। यह मार्क को एक बार कॉल करने की अनुमति देता है, और उसके बाद एकाधिक बार कहा जाता है, उदाहरण के लिए, एकाधिक रीट्रीज़ करते समय। –

2

चेक बाहर java.io.RandomAccessFile

+0

ठीक है, धन्यवाद। ऐसा लगता है कि मैं फ़ाइल खोलने के लिए इसका उपयोग कर सकता हूं और उसके बाद फ़ाइलChannel को क्लास के रूप में उपयोग/पढ़ने/लिखने के लिए उपयोग कर सकता हूं। –

+0

बहुत खराब RandomAccessFile इनपुटस्ट्रीम को इसके चिह्न()/रीसेट() विधियों के साथ लागू नहीं करता है। > :( –

+0

आप अपना खुद का काफी आसानी से रोल कर सकते हैं (यदि वह सुंदरता से नहीं है), तो देखें http://www.coderanch.com/t/277378/Streams/java/InputStream-RandomAccessFile-best-way उदाहरण के लिए –

7

java.nio.channels.FileChannel एक विधि position(long) स्थिति सी

6

RandomAccessFile में fseek() की तरह शून्य करने के लिए वापस रीसेट करना होता है कि आप क्या चाहते:

22

BufferedInputStream स्मृति में सामग्री बफरिंग द्वारा mark समर्थन करता है। यह अनुमानित आकार के अपेक्षाकृत छोटे दिखने के लिए सबसे अच्छा आरक्षित है।

इसके बजाय, RandomAccessFile सीधे इस्तेमाल किया जा सकता है, या यह एक ठोस InputStream, एक rewind() विधि के साथ बढ़ाया के लिए आधार के रूप में सेवा कर सकता है।

वैकल्पिक रूप से, प्रत्येक पास के लिए एक नया FileInputStream खोला जा सकता है।

+1

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

2

PushbackInputStream भी काम करेंगे, जब तक कि आप जानते हैं कि कितने वर्ण आप रिवाइंड करने के लिए

+0

सत्य नहीं है। 'पुशबैक इनपुट स्ट्रीम # अपठित (int b) '' b' बाइट्स को रिवाइंड नहीं करता है, लेकिन मैं 'b दबाता हूं स्ट्रीम के शीर्ष पर। –

2

BufferedInputStreammark(readlimit) और reset() है सक्षम होना चाहते हैं। readlimit मार्क वैध बनाने के लिए filesize से बड़ा होना चाहिए। file.length()+1 ठीक है। इसका मतलब है कि readlimit बाइट पढ़ने तक मार्क मान्य है, इस प्रकार आप reset() पर वापस जा सकते हैं।

2

आप क्या चाहते हैं RandomAccessFileInputStream - InputStream इंटरफ़ेस चिह्न/रीसेट के साथ कार्यान्वित करता है, कभी-कभी RandomAccessFiles पर आधारित होता है। कुछ कार्यान्वयन मौजूद हैं जो आपको चाहिए जो आपको चाहिए।

स्रोतों के साथ पूरा एक उदाहरण http://www.fuin.org/utils4j/index.html में है, लेकिन आप इंटरनेट पर कई अन्य खोज पाएंगे और यदि कोई भी ठीक से फिट नहीं होता है तो यह कोड के लिए आसान है।

19

यदि आप 10 से FileChannel प्राप्त करते हैं, तो आप फ़ाइल सूचक को फ़ाइल में कहीं भी सेट करने के लिए स्थिति विधि का उपयोग कर सकते हैं।

FileInputStream fis = new FileInputStream("/etc/hosts"); 
FileChannel  fc = fis.getChannel(); 


fc.position(100);// set the file pointer to byte position 100; 
संबंधित मुद्दे