Ruby - 从文件中读取字节,转换为整数

3

我正在尝试从文件中读取无符号整数(按连续的字节存储),并将它们转换为整数。我尝试了以下代码:

file = File.new(filename,"r")
num = file.read(2).unpack("S") #read an unsigned short
puts num #value  will be less than expected

这里我做错了什么?
6个回答

5
你读取的字节数不够。如你在tadman答案下的评论所说,你获得的是202而不是3405691582
请注意,0xCAFEBABE的前两个字节是0xCA=202
如果你真的想要一个由8个字节组成的单一数字,那么你需要读取更多比无符号短整型更多的字节。
尝试一下:
num = file.read(8).unpack("L_")

下划线假设本机的long型将是8字节,这绝对不能保证。

我尝试了一下,但是结果得到了3199925962(这个结果仍然不正确!)。另外,有没有跨平台的实现方式? - user130076
2
第一个字节是 0xCA,前两个字节是 0xCAFE。 - rampion
2
3199925962 = 0xBEBAFECA,看起来你可能遇到了字节顺序的问题。为了实现跨平台性,我通常依赖于网络字节顺序,而不是主机字节顺序。 - rampion
1
0xCA = 两个4位nybble = 1个8位字节,正如rampion所指出的那样。然而,得到202与file.read[0]相同,即第一个字符的ASCII值,这可能是问题所在。 - tadman
1
哎呀,是的,当我数第一个两位十六进制字符与两个字节时,我把自己搞混了。我的一般概念是正确的,现在你只需要处理字节顺序问题。 - bobDevil

4
看看《Ruby编程语言》(Ruby 1.9,第44页)中的内容如何?
File.open("testfile") 
do |file|
    file.each_byte {|ch| print "#{ch.chr}:#{ch} " }
end

each_byte以字节为单位迭代文件。


2
有一些Ruby库可帮助解析二进制数据,它们允许您在简单的高级声明性DSL中声明数据格式,然后自动完成所有打包、解包、位操作、位移和大小端转换等操作。
我从未使用过其中之一,但以下是两个示例(还有更多,但我不知道):

1

好的,我搞定了:

num = file.read(8).unpack("N")

感谢您的所有帮助。


对我来说不起作用,我得到了读取显示为未定义方法的错误 https://pastebin.com/raw/7LS75P2R - barlop

0
处理二进制数据时,如果你在Windows系统上操作,需要确保以二进制模式打开文件。这适用于读取和写入操作。
open(filename, "rb") do |file|
  num = file.read(2).unpack("S")
  puts num
end

根据源平台,"endian"编码也可能存在问题。例如,基于PowerPC的机器,包括旧的Mac系统、IBM Power服务器、PS3集群或Sun Sparc服务器。

你能举个例子说明它是如何“不同”的吗?通常数据中会有明显的模式。

例如,如果你想要0x1234,但得到的是0x3412,那就是一个字节序问题。


我正在尝试读取Java .class文件的魔数。我的代码产生的魔数是202,而它应该是3405691582(0xCAFEBABE)。即使我使用了"rb",它也没有改变。 - user130076
另外,我在使用Linux,我需要仍然以二进制模式打开文件吗? - user130076
在Unix上,显式使用二进制模式仍然是一种好的形式。这不会有任何影响(只是一个空操作),但a.)可以让您的代码更清晰;b.)如果有人在Windows上运行您的代码,这还可以为您节省大量的调试工作。 - Jörg W Mittag

0
文件中的数字是以什么格式存储的?是十六进制吗?你的代码看起来对我来说是正确的。

根据虚拟机规范:“多字节数据项始终以大端序存储,高位字节先出现。” - user130076

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接