【问题标题】:numpy.array.tofile() binary file looks "strange" in notepad++numpy.array.tofile() 二进制文件在记事本++中看起来“奇怪”
【发布时间】:2015-04-22 22:21:30
【问题描述】:

我只是想知道该函数实际上是如何存储数据的。因为对我来说,它看起来完全陌生。假设我有以下代码:

import numpy as np
filename = "test.dat"
print(filename)
fileobj = open(filename, mode='wb')
off = np.array([1, 300], dtype=np.int32)
off.tofile(fileobj)
fileobj.close()

fileobj2 = open(filename, mode='rb')
off = np.fromfile(fileobj2, dtype = np.int32)
print(off)
fileobj2.close()

现在我希望文件中有 8 个字节,其中每个元素由 4 个字节表示(我可以接受任何字节序)。但是,当我在十六进制编辑器中打开文件(使用带有十六进制编辑器插件的记事本++)时,我得到以下字节:

01 00 C4 AC 00

5 个字节,我完全不知道它代表什么。第一个字节看起来像是数字,但接下来的内容很奇怪,肯定不是“300”。

但重新加载会显示原始数组。

这是我在 python 中不理解的东西,还是 notepad++ 中的问题? - 如果我选择不同的“编码”,我注意到十六进制看起来不同(嗯?)。另外:Windows 确实报告它有 8 个字节长。

【问题讨论】:

  • 首先,int32 占用 4 个字节,而不是 2 个。
  • 接下来,您是否尝试过在除 Notepad++ 之外的任何其他程序中读取文件?你可以在 Python 本身中很容易地做到这一点;而不是off = np.fromfile(fileobj2, dtype=np.int32),只需执行off = fileobj2.read(),然后打印字节。你应该看到类似b'\x01\x00\x00\x00,\x01\x00\x00';如果您看到的是b'\x01\x00\xc4\xac\x00',那么您就知道是文件损坏了,而不是 Notepad++。
  • @abarnert 这实际上是一个错字(注意我已经说过“我期望 8 个字节......”)。嗯,notepad++ 似乎确实坏了,这很奇怪,以前从未发生过这种情况:/,我可以问/将这个问题转换为“如何使 notepad++ 与 hex 插件一起工作”还是这里太离题了?
  • 您不应尝试将问题转换为不同的问题。只问一个新的。我认为新版本会在 SuperUser 之类的地方更受关注,但您应该阅读这两个站点(以及其他一些听起来相关的 Stack Exchange 站点)上的帮助并自行决定。
  • 会不会跟notepad++版本或者插件有关系? sourceforge.net/p/notepad-plus/discussion/482781/thread/… 提到几年前 Npp 插件中的一个空字符问题。

标签: python numpy notepad++ hexdump


【解决方案1】:

您可以很容易地知道该文件实际上确实有 8 个字节,与您期望的相同的 8 个字节 (01 00 00 00 2C 01 00 00) 只需使用除 Notepad++ 之外的任何东西来查看文件,包括用 off = fileobj2.read()ing the bytes (which will give youb'\x01\x00\x00\x00,\x01\x00\x00'`*) 替换你的 off = np.fromfile(fileobj2, dtype=np.int32) .

而且,从你们的 cmets 那里,在我建议之后,你们尝试了,并且看到了。

这意味着这要么是 Notepad++ 中的错误,要么是您使用它的方式有问题; Python、NumPy 和你自己的代码都很好。


* 如果不清楚:'\x2c'',' 是同一个字符,bytes 使用可打印的 ASCII 表示来表示可打印的 ASCII 字符,以及熟悉的转义符,如 '\n' ,如果可能,仅对其他值使用十六进制反斜杠转义。

【讨论】:

  • 为什么我们只需要 8 个字节?没有保存数组维数的表示吗?如果不是,例如,如果 5 维数组和 10 维数组具有相同数量的元素,如何区分它们?
  • @dbliss:简短的回答是,不,没有,它们没有区别,这就是我们期望 8 个字节的原因。 tofile/fromfile 文档对此进行了解释。但是您可以通过np.array([[1,2], [3,4]], dtype=np.int8).tofile(f),然后a = np.fromfile(f, dtype=np.int8) 轻松测试它;你回来[1,2,3,4],而不是[[1,2],[3,4]]
  • @dbliss:请注意,它甚至没有存储数据类型。这意味着除了丢失有关维度(以及 C 与 Fortran 跨步)的信息外,您还会丢失有关字节序、平台浮点实现差异等的信息。它用于“快速存储”,您可以在其中转储数据并将其读回在同一个会话中——例如,您没有足够的内存来一次存储所有数组,或者您想将它们传递给 multiprocessing 孩子。
【解决方案2】:

您希望300 看起来像什么?

写入数组,并以二进制形式读回(在 ipython 中):

In [478]: np.array([1,300],np.int32).tofile('test')

In [479]: with open('test','rb') as f: print(f.read())
b'\x01\x00\x00\x00,\x01\x00\x00'

有8个字节,,只是一个可显示的字节。

实际上,我不必通过文件来获得这个:

In [505]: np.array([1,300]).tostring()
Out[505]: b'\x01\x00\x00\x00,\x01\x00\x00'

做同样的事情:

[255]    
b'\xff\x00\x00\x00'

[256]
b'\x00\x01\x00\x00'

[300]
b',\x01\x00\x00'

[1,255]
b'\x01\x00\x00\x00\xff\x00\x00\x00'

使用 2 的幂(和 1 的幂),很容易识别字节中的模式。


frombuffer 将字节字符串转换回数组:

In [513]: np.frombuffer(np.array([1,300]).tostring(),int)
Out[513]: array([  1, 300])

In [514]: np.frombuffer(np.array([1,300]).data,int)
Out[514]: array([  1, 300])

从最后一个表达式来看,tofile 只是将数组缓冲区作为字节写入文件。

【讨论】:

  • 但他的问题是为什么他得到 5 个字节 01 00 C4 AC 00 而不是 8 个字节 01 00 00 00 2C 01 00 00;这根本没有回答。
  • 但它确实为他提供了一种从 Python 中检查文件的方法。假设他得到同样的东西,那么问题显然出在notepad++ 上。我让其他人解决这个问题,因为我的机器的 linux 端没有那个编辑器。另外,使用易于识别的值(例如 255 或 256)进行测试可能会有所帮助。
  • 如果您阅读 cmets,他已经在您写答案前 7 小时进行了等效测试。是的,如果他编辑问题以明确这一点而不是仅仅写评论会更好,但这仍然不意味着这是对问题的有用答案,无论是按要求还是按预期。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-02
  • 1970-01-01
  • 2015-09-12
  • 2016-03-02
  • 1970-01-01
相关资源
最近更新 更多