Przeczytaj plik binarny do struct

głosy
42

Próbuję odczytać dane binarne przy użyciu C #. Mam wszystkie informacje na temat układu danych w plikach chcę czytać. Jestem w stanie odczytać danych „kawałek za kawałkiem”, czyli uzyskanie pierwszych 40 bajtów danych przekształcenie go na łańcuch, dostać kolejne 40 bajtów.

Ponieważ istnieją co najmniej trzy nieco inna wersja danych, chciałbym odczytać dane bezpośrednio do struktury. To po prostu czuje się tak znacznie bardziej w prawo niż czytając to „linia po linii”.

Próbowałem następujące podejście, ale bezskutecznie:

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();

Strumień jest otwarty FileStream z którego ja zaczął czytać z. Otrzymuję AccessViolationException podczas używania Marshal.PtrToStructure.

Strumień zawiera więcej informacji niż ja staram się czytać, ponieważ nie jestem zainteresowany danych na końcu pliku.

Struct definiuje się następująco:

[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;
}

Kod przykłady zmienia się od oryginału, aby ta kwestia krótszy.

Jak czytam dane binarne z pliku do struct?

Utwórz 05/08/2008 o 15:28
źródło użytkownik
W innych językach...                            


7 odpowiedzi

głosy
19

Problemem jest ciąg s w swojej struktury. Okazało się, że Organizowanie typy jak bajtów / short / INT nie jest problemem; ale kiedy trzeba zebrać do typu złożonego, takiego jak łańcuch, trzeba swój struct jawnie naśladować typ niezarządzanej. Można to zrobić z attrib MarshalAs.

Na swoim przykładzie, co następuje powinno działać:

[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;
}
Odpowiedział 21/08/2008 o 20:02
źródło użytkownik

głosy
8

Oto co używam.
To działało pomyślnie dla mnie do czytania Portable wykonywalnego formatu.
Jest to funkcja rodzajowy, więc Tjest twój structtyp.

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;
}
Odpowiedział 02/11/2010 o 03:40
źródło użytkownik

głosy
5

Jak powiedział Ronnie, użyję BinaryReader i odczytać każde pole indywidualnie. Nie mogę znaleźć link do artykułu z tej informacji, ale to zaobserwowano, że przy użyciu BinaryReader czytać każdy indywidualny pole może być szybsze niż Marshal.PtrToStruct, jeśli struktura zawiera mniej niż 30-40 lub tak pola. wyślę link do artykułu, kiedy go znaleźć.

W artykule w link jest pod adresem: http://www.codeproject.com/Articles/10750/Fast-Binary-File-Reading-with-C

Kiedy Organizowanie tablicę kodowanym, PtrToStruct zyskuje przewagę strony szybciej, ponieważ można pomyśleć o liczbie pola jako pola * długość tablicy.

Odpowiedział 06/05/2010 o 02:04
źródło użytkownik

głosy
3

Nie miałem szczęścia używając BinaryFormatter Chyba muszę mieć pełną struct, który pasuje do zawartości pliku dokładnie. Zdałem sobie sprawę, że w końcu nie był zainteresowany bardzo dużo treści pliku tak więc poszłam z rozwiązaniem czytając część strumienia do ByteBuffer a następnie przekształcenie go przy użyciu

Encoding.ASCII.GetString()

na smyczki i

BitConverter.ToInt32()

dla liczb całkowitych.

będę musiał być w stanie przetworzyć więcej pliku później, ale dla tej wersji I uciekł z zaledwie kilku linii kodu.

Odpowiedział 06/08/2008 o 10:03
źródło użytkownik

głosy
1

Nie widzę żadnego problemu z kodem.

tylko z mojej głowy, co jeśli spróbujesz zrobić to ręcznie? Czy to działa?

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));
...
...
...

także spróbować

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();

a następnie za pomocą buforu [] w BinaryReader zamiast odczytu danych z FileStream, aby zobaczyć, czy wciąż wyjątek AccessViolation.

Nie miałem szczęścia używając BinaryFormatter Chyba muszę mieć pełną struct, który pasuje do zawartości pliku dokładnie.

Ma to sens, BinaryFormatter ma własny format danych, całkowicie niezgodną z naszą.

Odpowiedział 05/08/2008 o 16:31
źródło użytkownik

głosy
0

Czytając prosto w elemencie jest zła - niejeden program C spadła ponad powodu różnych porządku bajtów, różnych implementacji kompilatorów pól, pakowania, wielkości słowo .......

Jesteś najlepszym z SZEREGOWANIE i deserialising bajt po bajcie. Skorzystać z wbudowanych w rzeczy, jeśli chcesz lub po prostu przyzwyczaić się do BinaryReader.

Odpowiedział 23/09/2008 o 22:43
źródło użytkownik

głosy
0

Spróbuj tego:

using (FileStream stream = new FileStream(fileName, FileMode.Open))
{
    BinaryFormatter formatter = new BinaryFormatter();
    StructType aStruct = (StructType)formatter.Deserialize(filestream);
}
Odpowiedział 05/08/2008 o 15:56
źródło użytkownik

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more