2009-05-22 38 views
7

Tôi đang cố đọc một tệp nhị phân với lớp BinaryReader và tôi cần đọc nó dưới dạng các khối của UInt32 và sau đó thực hiện một số thay đổi bit sau.Tại sao BinaryReader.ReadUInt32() đảo ngược mẫu bit?

Nhưng, vì lý do nào đó, thứ tự bit được đảo ngược khi tôi sử dụng phương pháp ReadUInt32.

Nếu tôi ví dụ có tệp trong đó bốn byte đầu tiên trông giống như thế này trong hex, 0x12345678, chúng kết thúc như sau sau khi được đọc bởi ReadUInt32: 0x78563412.

Nếu tôi sử dụng ReadBytes (4) phương pháp, tôi nhận được mảng dự kiến:

[0x00000000] 0x12 byte 
[0x00000001] 0x34 byte 
[0x00000002] 0x56 byte 
[0x00000003] 0x78 byte 

Tại sao điều này? Nó chỉ là cách. Net đại diện cho uints trong bộ nhớ? Có giống nhau trên các nền tảng khác nhau không (tôi đang chạy Windows 7 64 bit, .net 3.5 sp1)?

+0

Bạn có thể dập tắt sự tò mò của chúng tôi bằng cách cho chúng tôi biết cách bạn khắc phục sự cố không? :) –

+1

Tất nhiên :) Trong thực tế nó không quan trọng theo cách thứ tự byte, miễn là nó nhất quán trên platfroms (x64, x86), tôi vẫn có thể trích xuất các bit tôi cần, tôi chỉ cần thay đổi bit của tôi dịch chuyển. Theo như tôi có thể thấy, uint nói chung được lưu trữ như là một chút ít, không chỉ là uint xây dựng bởi ReadUInt32, để làm cho mọi thứ dễ dàng hơn. –

Trả lời

8

Điều này dường như là một vấn đề endianness. The docs đọc ReadUint32 đọc ở mức nhỏ để byte đầu tiên là ít quan trọng nhất để nó đi đến vị trí bộ nhớ thấp nhất. Nhà văn của bạn phải là người lớn tuổi?

BinaryWriter.Write(UInt32)says it writes cũng chưa được kết thúc. Nguồn dữ liệu nhị phân của bạn không phải là BinaryWriter?

Về cơ bản những gì bạn cần phải làm gì để khắc phục nó là thế này:

uint a = 0x12345678; 
uint b = ((a & 0x000000FF) << 24) + ((a & 0x0000FF00) << 8) + ((a & 0x00FF0000) >> 8) + ((a & 0xFF000000) >> 24); 

này thay đổi các byte kém đáng kể lên 24 bit, thứ 2 LSB lên 8 bit, thứ 3 LSB xuống 8 bit, và LSB thứ 4 (MSB) giảm 24 bit. Việc này được bao gồm trong một số thư viện.

Có lẽ sử dụng BitConverter sẽ được rõ ràng hơn một chút:

uint a = 0x12345678; 
byte[] bytes = BitConverter.GetBytes(a); 
// Swap byte order 
uint b = BitConverter.ToUInt32(new byte[] { bytes[3], bytes[2], bytes[1], bytes[0] }, 0); 
8

Có, điều này liên quan đến cách phần cứng máy tính lưu trữ các u gợi trong bộ nhớ. Nó có thể khác nhau trên các nền tảng khác nhau, mặc dù hầu hết các máy tính để bàn đều giống nhau.

này được gọi là endianness - xem wikipedia ở đây:

http://en.wikipedia.org/wiki/Endian

1

Đây là vấn đề của nền tảng Endianess. Khi bạn đọc dữ liệu từ một luồng, bạn phải đọc nó cho phù hợp với endianess nó được viết như. Nếu bạn đã tạo dữ liệu trong .Net, thì .Net sẽ đọc nó một cách chính xác.

+0

lol 3 liên kết wikipedia dưới 1 phút. nên có một huy hiệu cho điều đó! –

0

đọc Generic BinaryReader and BinaryWriter Extensions, một cách tuyệt vời để xử lý chung đúc cách không được quản lý.

Đối với VB.NET (mã an toàn mà thôi, cũng có thể đạt được trong C#) sử dụng như sau:

Imports System.IO Imports System.Runtime.CompilerServices Imports System.Runtime.InteropServices

<HideModuleName()> 
Public Module BinaryReaderExtensions 

<Extension()> 
Public Function Read(Of T As Structure)(br As BinaryReader) As T 
    Dim bytes = br.ReadBytes(Marshal.SizeOf(GetType(T))) 
    Dim handle = GCHandle.Alloc(bytes, GCHandleType.Pinned) 
    Return Marshal.PtrToStructure(handle.AddrOfPinnedObject, GetType(T)) 
End Function 

<Extension()> 
Public Function ReadReverse(Of T As Structure)(br As BinaryReader) As T 
    Dim bytes = br.ReadBytes(Marshal.SizeOf(GetType(T))).Reverse.ToArray 
    Dim handle = GCHandle.Alloc(bytes, GCHandleType.Pinned) 
    Return Marshal.PtrToStructure(handle.AddrOfPinnedObject, GetType(T)) 
End Function 

End Module 

Bạn có thể thực hiện tại cùng một chức năng cho BitConverter, cho BinaryWriter v.v.