2009-04-10 11 views
7

द्वारा खपत बाइट्स क्या यह जानने का कोई तरीका है कि StreamReader द्वारा स्ट्रीम के कितने बाइट्स का उपयोग किया गया है?StreamReader

मेरे पास एक प्रोजेक्ट है जहां हमें एक फ़ाइल को पढ़ने की आवश्यकता है जिसमें बाइनरी डेटा की शुरुआत के बाद टेक्स्ट हेडर है।

private int _dataOffset; 
void ReadHeader(string path) 
{ 
    using (FileStream stream = File.OpenRead(path)) 
    { 
     StreamReader textReader = new StreamReader(stream); 

     do 
     { 
      string line = textReader.ReadLine(); 
      handleHeaderLine(line); 
     } while(line != "DATA") // Yes, they used "DATA" to mark the end of the header 

     _dataOffset = stream.Position; 
    } 
} 

private byte[] ReadDataFrame(string path, int frameNum) 
{ 
    using (FileStream stream = File.OpenRead(path)) 
    { 
     stream.Seek(_dataOffset + frameNum * cbFrame, SeekOrigin.Begin); 

     byte[] data = new byte[cbFrame]; 
     stream.Read(data, 0, cbFrame); 

     return data; 
    } 
    return null; 
} 

समस्या यह है कि जब मैं stream.Position को _dataOffset निर्धारित करते हैं, मैं स्थिति यह है कि StreamReader, नहीं हैडर के अंत तक पढ़ा है मिलता है: मेरी प्रारंभिक इस फाइल को पढ़ने के लिए प्रयास कुछ इस तरह था। जैसे ही मैंने इसके बारे में सोचा, यह समझ में आया, लेकिन मुझे अभी भी यह जानने में सक्षम होना चाहिए कि हेडर का अंत कहां है और मुझे यकीन नहीं है कि ऐसा करने का कोई तरीका है और अभी भी StreamReader का लाभ उठाएं।

उत्तर

0

तो आपकी आखिरी पंक्ति में 'डेटा' + अज्ञात मात्रा में डेटा बाइट शामिल हैं। आप इंडेक्सऑफ() का उपयोग करके अपनी पिछली पठित लाइन के साथ स्थिति निकाल सकते हैं। फिर स्ट्रीम को समायोजित करें। स्थिति।

लेकिन मुझे यकीन नहीं है कि आपको इस मामले में रीडलाइन() का उपयोग करना चाहिए या नहीं। हो सकता है कि बाइट द्वारा बाइट को तब तक पढ़ना बेहतर होगा जब तक कि आप 'डेटा' चिह्न तक नहीं पहुंच जाते।

+0

वैसे यह निश्चित रूप से मेरी फॉलबैक स्थिति है, मैं बस यह देखना चाहता था कि इसे लागू करने से पहले कोई बेहतर तरीका है या नहीं। –

1

तो डेटा utf8 (StreamReader के लिए डिफ़ॉल्ट एन्कोडिंग) है। यह एक मल्टीबाइट एन्कोडिंग है, इसलिए इंडेक्सऑफ अव्यवस्थित होगा। आप:

Encoding.UTF8.GetByteCount(string) 

अब तक आपके डेटा पर, लापता लाइन समाप्त होने के लिए 1 या 2 बाइट जोड़ना।

+0

अगर मैं तारों के लिए बाइट गणना का उपयोग करता हूं तो यह बिल्कुल मेरी चिंता है। मैं निश्चित रूप से नहीं जानता कि लाइन टर्मिनेटर के लिए कितना जोड़ना है। –

+1

यह काम नहीं करेगा, कुछ बाइट्स हैं, जो तकनीकी जानकारी को स्टोर करने के लिए उपयोग की जाती हैं, यदि आप इस तरह गिनने की कोशिश करेंगे तो इसे याद किया जाएगा। ईजी। - फ़ाइल की शुरुआत में तीन बाइट हैं, जो दिखाता है कि इस फ़ाइल में यूनिकोड एन्कोडिंग है। –

3

आप यह पता लगा सकते हैं कि StreamReader वास्तव में कितने बाइट्स (धारा से पढ़ने के विपरीत) के रूप में वापस आ गया है, उनमें से कोई भी बहुत सरल नहीं है।

  1. textReader.CurrentEncoding.GetByteCount(totalLengthOfAllTextRead) का परिणाम प्राप्त करें और फिर स्ट्रीम में इस स्थिति की तलाश करें।
  2. StreamReader ऑब्जेक्ट के निजी चर के मान को पुनर्प्राप्त करने के लिए कुछ प्रतिबिंब हैकर का उपयोग करें जो आंतरिक बफर के भीतर वर्तमान बाइट स्थिति से संबंधित है (धारा से अलग - आमतौर पर पीछे, लेकिन पाठ्यक्रम के बराबर नहीं) । .NET Reflector द्वारा निर्णय, इस चर को bytePos नाम दिया गया है।
  3. StreamReader का उपयोग करके परेशान न करें बल्कि Stream या BinaryReader के शीर्ष पर बनाए गए अपने कस्टम रीडलाइन फ़ंक्शन को लागू करें (BinaryReader भी गारंटी है कि आप जो अनुरोध करते हैं उससे आगे आगे पढ़ने के लिए कभी भी आगे न हों)। इस कस्टम फ़ंक्शन को चार से स्ट्रीम चार से पढ़ना चाहिए, इसलिए आपको वास्तव में निम्न-स्तर Decoder ऑब्जेक्ट का उपयोग करना होगा (जब तक कि एन्कोडिंग एएससीआईआई/एएनएसआई न हो, जिसमें सिंगल-बाइट एन्कोडिंग के कारण चीजें थोड़ा सरल होती हैं) ।

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

उम्मीद है कि मदद करता है।

1

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

0

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

using (FileStream stream = File.OpenRead(path)) { 
    List<byte> buffer = new List<byte>(); 
    bool hasCr = false; 
    bool done = false; 
    while (!done) { 
     int b = stream.ReadByte(); 
     if (b == -1) throw new IOException("End of file reached in header."); 
     if (b == 13) { 
     hasCr = true; 
     } else if (b == 10 && hasCr) { 
     string line = Encoding.UTF8.GetString(buffer.ToArray(), 0, buffer.Count); 
     if (line == "DATA") { 
      done = true; 
     } else { 
      HandleHeaderLine(line); 
     } 
     buffer.Clear(); 
     hasCr = false; 
     } else { 
     if (hasCr) buffer.Add(13); 
     hasCr = false; 
     buffer.Add((byte)b); 
     } 
    } 
    _dataOffset = stream.Position; 
} 

बजाय और इसे फिर से खोलने के लिए, आप निश्चित रूप से सिर्फ डाटा पढ़ने पर रख सकता है।

+0

यह विधि केवल ASCII/ANSI एन्कोडिंग के लिए काम करती है। अन्य एन्कोडिंग के लिए, आपको वास्तव में एक डिकोडर का उपयोग करना चाहिए, जैसा कि मैंने अपनी पोस्ट में विस्तृत किया है। साथ ही, एक सूची का उपयोग करना बहुत अक्षम होगा। – Noldorin

+0

हां, यह कुछ अनौपचारिक एन्कोडिंग के लिए काम नहीं करता है, मैं इसके बारे में नहीं जोड़ूंगा। एक सूची भंडारण के लिए बाइट सरणी का उपयोग करती है, इसलिए ऐसा कुछ भी नहीं है जो इसके बारे में बहुत अक्षम है। – Guffa

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