2008-08-05 15 views
41

में बाइनरी फ़ाइल पढ़ें मैं सी # का उपयोग कर बाइनरी डेटा पढ़ने की कोशिश कर रहा हूं। मेरे पास उन फ़ाइलों में डेटा के लेआउट के बारे में सारी जानकारी है जिन्हें मैं पढ़ना चाहता हूं। मैं डेटा को "खंड द्वारा खंडित" पढ़ने में सक्षम हूं, यानी डेटा के पहले 40 बाइट्स को इसे स्ट्रिंग में परिवर्तित करने में सक्षम हूं, अगले 40 बाइट प्राप्त करें।एक संरचना

चूंकि डेटा के कम से कम तीन थोड़ा अलग संस्करण हैं, इसलिए मैं सीधे डेटा को डेटा में पढ़ना चाहता हूं। यह "रेखा से लाइन" पढ़ने से बस इतना अधिक सही लगता है।

मैं निम्नलिखित दृष्टिकोण की कोशिश की लेकिन कोई लाभ नहीं हुआ है:

StructType aStruct; 
int count = Marshal.SizeOf(typeof(StructType)); 
byte[] readBuffer = new byte[count]; 
BinaryReader reader = new BinaryReader(stream); 
readBuffer = reader.ReadBytes(count); 
GCHandle handle = GCHandle.Alloc(readBuffer, GCHandleType.Pinned); 
aStruct = (StructType) Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(StructType)); 
handle.Free(); 

धारा एक खोला FileStream जहाँ से मैं से पढ़ना शुरू किया गया है। Marshal.PtrToStructure का उपयोग करते समय मुझे AccessViolationExceptio एन मिलता है।

स्ट्रीम में पढ़ने की कोशिश करने की तुलना में अधिक जानकारी शामिल है क्योंकि मुझे फ़ाइल के अंत में डेटा में दिलचस्पी नहीं है।

[StructLayout(LayoutKind.Explicit)] 
struct StructType 
{ 
    [FieldOffset(0)] 
    public string FileDate; 
    [FieldOffset(8)] 
    public string FileTime; 
    [FieldOffset(16)] 
    public int Id1; 
    [FieldOffset(20)] 
    public string Id2; 
} 

उदाहरण कोड मूल से बदल गया है इस सवाल का कम करने के लिए:

struct की तरह परिभाषित किया गया है।

मैं फ़ाइल से संरचना में बाइनरी डेटा कैसे पढ़ूं?

उत्तर

0

इस प्रयास करें:

using (FileStream stream = new FileStream(fileName, FileMode.Open)) 
{ 
    BinaryFormatter formatter = new BinaryFormatter(); 
    StructType aStruct = (StructType)formatter.Deserialize(filestream); 
} 
+4

बाइनरीफॉर्मेटर के पास बाइनरी डेटा के लिए अपना प्रारूप है - यदि आप डेटा को स्वयं पढ़ रहे/लिख रहे हैं तो ठीक है। उपयोगी नहीं है अगर आप किसी अन्य स्रोत से फ़ाइल प्राप्त कर रहे हैं। – russau

1

मैं अपने कोड के साथ किसी भी समस्या नहीं दिख रहा।

बस मेरे सिर से बाहर, यदि आप इसे मैन्युअल रूप से करने का प्रयास करते हैं तो क्या होगा? क्या यह काम करता है?

BinaryReader reader = new BinaryReader(stream); 
StructType o = new StructType(); 
o.FileDate = Encoding.ASCII.GetString(reader.ReadBytes(8)); 
o.FileTime = Encoding.ASCII.GetString(reader.ReadBytes(8)); 
... 
... 
... 

भी कोशिश

StructType o = new StructType(); 
byte[] buffer = new byte[Marshal.SizeOf(typeof(StructType))]; 
GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned); 
Marshal.StructureToPtr(o, handle.AddrOfPinnedObject(), false); 
handle.Free(); 

तो बफर [] अपने BinaryReader में बजाय FileStream से डेटा पढ़ने के लिए कि क्या आप अभी भी AccessViolation अपवाद को देखने के लिए का उपयोग करें।

मुझे कोई BinaryFormatter का उपयोग कर किस्मत थी, मैं एक पूरा struct कि सटीक मेल खाता फ़ाइल की सामग्री के लिए मेरे पास है लगता है।

यह समझ में आता है, बाइनरीफॉर्मेटर का अपना डेटा प्रारूप है, जो आपके साथ पूरी तरह से असंगत है।

3

मुझे बाइनरीफॉर्मेटर का उपयोग करने में कोई भाग्य नहीं था, मुझे लगता है कि मेरे पास एक पूर्ण संरचना है जो फ़ाइल की सामग्री से मेल खाती है। मैंने महसूस किया कि अंत में मैं वैसे भी फ़ाइल की सामग्री का बहुत ज्यादा में दिलचस्पी नहीं थी तो मैं एक ByteBuffer में धारा का हिस्सा पढ़ने और फिर से समाधान के साथ चला गया

Encoding.ASCII.GetString() 
स्ट्रिंग्स के लिए

और

का उपयोग कर इसे परिवर्तित
BitConverter.ToInt32() 

पूर्णांक के लिए।

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

18

समस्या आपकी संरचना में स्ट्रिंग एस है। मैंने पाया कि बाइट/शॉर्ट/इंट जैसे मार्शलिंग प्रकार कोई समस्या नहीं है; लेकिन जब आपको स्ट्रिंग जैसे जटिल प्रकार में मार्शल करने की आवश्यकता होती है, तो आपको एक अप्रबंधित प्रकार की स्पष्ट रूप से नकल करने के लिए अपनी संरचना की आवश्यकता होती है। आप इसे मार्शल एट्रिब के साथ कर सकते हैं।

अपने उदाहरण के लिए, निम्नलिखित काम करना चाहिए:

[StructLayout(LayoutKind.Explicit)] 
struct StructType 
{ 
    [FieldOffset(0)] 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)] 
    public string FileDate; 

    [FieldOffset(8)] 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)] 
    public string FileTime; 

    [FieldOffset(16)] 
    public int Id1; 

    [FieldOffset(20)] 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 66)] //Or however long Id2 is. 
    public string Id2; 
} 
0

सीधे structs में पढ़ना बुराई है - कई एक सी कार्यक्रम क्योंकि विभिन्न बाइट orderings, खेतों के विभिन्न संकलक कार्यान्वयन, पैकिंग, शब्द आकार से अधिक गिर गया है .......

आप बाइट द्वारा क्रमबद्ध और deserialising बाइट के सर्वश्रेष्ठ हैं। यदि आप चाहें तो सामान में निर्माण का उपयोग करें या बस बाइनरी रीडर में उपयोग करें।

+6

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

+3

मैं भी असहमत हूं। जब प्रदर्शन महत्वपूर्ण होता है, या जब आपको बाइनरी सी ++/सी # इंटरऑप की आवश्यकता होती है, तो सादे 'स्ट्रक्चर' लिखने का तरीका है। –

5

जैसा कि रोनी ने कहा, मैं बाइनरी रीडर का उपयोग करता हूं और प्रत्येक फ़ील्ड को व्यक्तिगत रूप से पढ़ता हूं। मुझे इस जानकारी के साथ आलेख का लिंक नहीं मिल रहा है, लेकिन यह देखा गया है कि प्रत्येक व्यक्तिगत क्षेत्र को पढ़ने के लिए बाइनरी रीडर का उपयोग मार्शल से तेज हो सकता है। PtrToStruct, यदि संरचना में 30-40 या उससे कम फ़ील्ड शामिल हैं। जब मैं इसे पाता हूं तो मैं लेख को लिंक पोस्ट करूंगा। http://www.codeproject.com/Articles/10750/Fast-Binary-File-Reading-with-C

जब structs की एक सरणी प्रमुखता, PtrToStruct लाभ ऊपरी हाथ और अधिक तेजी से है, क्योंकि आप जैसे क्षेत्रों * सरणी लंबाई क्षेत्र गिनती के बारे में सोच सकते हैं:

लेख के लिंक पर है।

+2

मैं बस पढ़ रहा था: http://www.codeproject.com/KB/files/fastbinaryfileinput.aspx। क्या यह लेख आप सोच रहे हैं? लेखक नोट करते हैं: "मैंने पाया कि, लगभग 40 क्षेत्रों में, तीन दृष्टिकोणों के परिणाम लगभग बराबर थे, और उससे परे, ब्लॉक पढ़ने के दृष्टिकोण ऊपरी हाथ प्राप्त हुए।" –

+0

वास्तव में यह है! अच्छा खोज :) – nevelis

8

यहां मैं उपयोग कर रहा हूं।
पोर्टेबल निष्पादन योग्य प्रारूप पढ़ने के लिए यह मेरे लिए सफलतापूर्वक काम करता है।
यह एक सामान्य कार्य है, इसलिए T आपका struct प्रकार है।

public static T ByteToType<T>(BinaryReader reader) 
{ 
    byte[] bytes = reader.ReadBytes(Marshal.SizeOf(typeof(T))); 

    GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); 
    T theStructure = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); 
    handle.Free(); 

    return theStructure; 
} 
संबंधित मुद्दे