C# - Big Endian 中的二进制阅读器?
我试图通过使用程序读取所有不同的信息位来提高对 STFS 文件格式的理解。使用一个网站来参考哪些偏移量包含哪些信息,我编写了一些代码,让二进制读取器遍历文件并将值放入正确的变量中。
问题是所有数据都应该是 Big Endian,而二进制读取器读取的所有数据都是 Little Endian。那么,解决这个问题的最佳方法是什么?
我可以创建一个返回反向字节数组的二进制读取器的模拟类吗?我可以在类实例中更改一些内容,使其以大尾数法读取,这样我就不必重写所有内容吗?
任何帮助表示赞赏。
编辑:我尝试添加 Encoding.BigEndianUnicode 作为参数,但它仍然读取小端。
I'm trying to improve my understanding of the STFS file format by using a program to read all the different bits of information. Using a website with a reference of which offsets contain what information, I wrote some code that has a binary reader go through the file and place the values in the correct variables.
The problem is that all the data is SUPPOSED to be Big Endian, and everything the binary reader read is Little Endian. So, what's the best way to go about fixing this?
Can I create a mimic class of Binary reader that returns a reversed array of bytes? Is there something I can change in class instance that will make it read in big endian so I don't have to rewrite everything?
Any help is appreciated.
edit: I tried adding Encoding.BigEndianUnicode as a parameter, but it still reads little endian.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
我通常不会回答自己的问题,但我已经通过一些简单的代码完成了我想要的事情:
我知道这就是我想要的,但我不知道如何编写它。我找到了这个页面,它有帮助: http://www.codekeep.net/snippets/870c4ab3-419b-4dd2-a950-6d45beaf1295.aspx
I'm not usually one to answer my own questions, but I've accomplished exactly what I wanted with some simple code:
I knew that's what I wanted, but I didn't know how to write it. I found this page and it helped: http://www.codekeep.net/snippets/870c4ab3-419b-4dd2-a950-6d45beaf1295.aspx
恕我直言,这是一个稍微好一点的答案,因为它不需要更新不同的类,使大端调用变得明显,并允许大端调用和小端调用在流中混合。
IMHO a slightly better answer as it doesn't require a different class to be newed-up, makes the big-endian calls obvious and allows big- and little-endian calls to be mixed in the stream.
与大多数答案不同,BinaryReader 的基本完整(出于我的目的)替代品可以正确处理字节顺序。默认情况下,它的工作方式与 BinaryReader 完全相同,但可以构造为以所需的字节顺序读取。此外,
Read
方法被重载,允许您指定读取特定值的字节序 - 在您处理混合 LE/BE 流的(不太可能)场景中很有用数据。A mostly-complete (for my purposes) drop-in replacement for
BinaryReader
that handles endianness correctly, unlike most of these answers. By default it works exactly likeBinaryReader
, but can be constructed to read in the required endianness. Additionally theRead<Primitive>
methods are overloaded to allow you to specify the endianness to read a particular value in - useful in the (unlikely) scenario that you're dealing with a stream of mixed LE/BE data.我不熟悉 STFS,但更改字节序相对容易。 “网络顺序”是大端顺序,因此您需要做的就是从网络顺序转换为主机顺序。
这很容易,因为已经有代码可以做到这一点。查看
IPAddress.NetworkToHostOrder
,如下所述:ntohs() 和 ntohl()等价?I'm not familiar with STFS, but changing endianess is relatively easy. "Network Order" is big endian, so all you need to do is translate from network to host order.
This is easy because there's already code that does that. Look at
IPAddress.NetworkToHostOrder
, as explained here: ntohs() and ntohl() equivalent?我认为,这样做要小心。人们想要从 BigEndian 转换为 LittleEndian 的原因是,如果正在读取的字节采用 BigEndian,并且针对它们进行计算的操作系统正在 LittleEndian 中运行。
C# 不再是一种仅限于窗口的语言。具有 Mono 等端口,以及其他 Microsoft 平台,如 Windows Phone 7/8、Xbox 360/Xbox One、Windwos CE、Windows 8 Mobile、Linux With MONO、Apple with MONO 等。操作平台很可能在BigEndian,在这种情况下,如果你在不做任何检查的情况下转换代码,那你就完蛋了。
BitConverter 上已经有一个名为“IsLittleEndian”的字段,您可以使用它来确定操作环境是否为 LittleEndian。然后你可以有条件地进行反转。
因此,我实际上只是编写了一些 byte[] 扩展,而不是创建一个大类:
所以想象一下这个示例代码:
In my opinion, you want to be careful doing this. The reason one would want to Convert from BigEndian to LittleEndian is if the bytes being read are in BigEndian and the OS calculating against them is operating in LittleEndian.
C# isn't a window only language anymore. With ports like Mono, and also other Microsoft Platforms like Windows Phone 7/8, Xbox 360/Xbox One, Windwos CE, Windows 8 Mobile, Linux With MONO, Apple with MONO, etc. It is quite possible the operating platform could be in BigEndian, in which case you'd be screwing yourself if you converted the code without doing any checks.
The BitConverter already has a field on it called "IsLittleEndian" you can use this to determine if the operating environment is in LittleEndian or not. Then you can do the reversing conditionally.
As such, I actually just wrote some byte[] extensions instead of making a big class:
So imagine this example code:
您最好使用 BinaryPrimitives< /a> 类
You better to use BinaryPrimitives class
我扩展了 Ian Kemp 的出色建议,我正在使用新的
BinaryPrimitives
,在 .NET Core 2.1+ 中可用,根据Stephen Toub 的帖子,可以在内部处理字节序和反转。因此,如果您运行的是 .NET Core 2.1+,那么您绝对应该使用此版本:
I've expanded on Ian Kemp's excellent suggestion, I'm using the new
BinaryPrimitives
, available in .NET Core 2.1+, they are more performant according to Stephen Toub's post and can handle the endianness and reversal internally.So if you are running .NET Core 2.1+ you should definitely use this version:
您可能会喜欢这个选项,它受到其他一些答案的启发,但一般性地编写,以便实现更简洁的实现,使我们能够包含所有变体,而无需太多额外的代码。
You might like this option, inspired by some of the other answers but written generically so as to make for a more concise implementation that allows us to include all the variations without too much extra code.
我已将 Big Endian 读取方法实现为
BinaryReader
上的扩展方法。我发现使用
BinaryReader
的派生类没有真正的优势,因为实际有用的内部方法(例如ReadOnlySpanInternalRead()
)被标记为私有
而不是内部
。因此,扩展方法。我尝试尽可能接近 BinaryReader 的 LE 方法的内部行为。这需要实现 BinaryReader.InternalRead() 的替代方案。我已将 Microsoft 的
MemoryStream
优化包含为.TryReadSpanUnsafe()
,尽管我不确定当缓冲区如此小且调用开销如此之大时它有多大用处设置直接缓冲区访问的公共方法。如果您不需要任何浮点方法,则可以简单地使用
BinaryPrimitives.ReverseEndianness()
,因为BinaryReader
方法保证返回小尾数法。在小端系统上,这基本上将具有最佳情况的性能,因为它是BinaryPrimitives.ReadInt16BigEndian()
内部执行的操作。在大端系统上,字节序将反转两次并增加一些开销,但绝大多数运行 .NET 的系统都不是大端。I've implemented Big Endian read methods as extension methods on
BinaryReader
.I found that there's no real advantage to using a derived class of
BinaryReader
due to the actually useful internal methods (likeReadOnlySpan<byte> InternalRead()
) being markedprivate
instead ofinternal
. Hence, extension methods.I have attempted to remain as close to the internal behaviour of
BinaryReader
's LE methods as possible. This requires implementing an alternative toBinaryReader.InternalRead()
. I've included Microsoft'sMemoryStream
optimization as.TryReadSpanUnsafe()
, although I'm not sure it has much use when the buffers are so small and there's so much overhead calling into the public methods to set up the direct buffer access.If you don't need any of the floating point methods, you can simply use
BinaryPrimitives.ReverseEndianness()
, since theBinaryReader
methods are guaranteed to return little endian. On a little endian system, this will have basically best-case performance, since it's whatBinaryPrimitives.ReadInt16BigEndian()
does internally anyway. On a big endian system, the endianness will be reversed twice and add some overhead, but the vast majority of systems running .NET are not big endian.