基本上,听起来像是要使用数组的tofile方法或直接使用ndarray.data缓冲区对象。

对于您的具体用例,使用数组的data缓冲区是最有效的,但是对于一般用途,您需要注意许多注意事项。我稍后再详细说明。

不过,首先让我回答您的几个问题,并提供一些澄清:buf[:N] allocates memory for a new array object, having the length N+1, right?

这取决于你所说的“新数组对象”是什么意思。不管所涉及的数组大小,只分配很少的额外内存。在

它确实为一个新的数组对象分配内存(几个字节),但它不为数组的数据分配额外的内存。相反,它创建一个共享原始数组数据缓冲区的“视图”。对y = buf[:N]所做的任何更改也将影响buf。在buf[:N].tostring() allocates memory for a new string, and the bytes from buf are copied into this string

是的,没错。

另一方面,实际上,您可以按照相反的方式(字符串到数组),而无需分配任何额外的内存:

somestring = 'This could be a big string'
arr = np.frombuffer(buffer(somestring), dtype=np.uint8)

但是,由于python字符串是不可变的,arr将是只读的。在Is there a way to just tell f.write to access directly the memory address of "buf" from 0 to N bytes and write them onto the disk?

是的!

基本上,你需要:

^{2}$

这是非常有效的,将适用于任何类似文件的对象。在这种情况下,这几乎是你想要的。但是,有几个注意事项!

首先,请注意N将在数组中的项中,而不是直接以字节为单位。它们在示例代码中是等价的(由于dtype=np.int8,或任何其他8位数据类型)。

如果你想写一些字节,你可以这样做f.write(buf.data[:N])

…但是切片arr.data缓冲区将分配一个新的字符串,因此它在功能上类似于buf[:N].tostring()。无论如何,请注意,对于大多数数据类型,执行f.write(buf[:N].tostring())操作与执行f.write(buf.data[:N])操作不同,但两者都将分配一个新的字符串。

接下来,numpy数组可以共享数据缓冲区。在您的例子中,您不需要担心这一点,但一般来说,使用somearr.data可能会因此而导致意外。

例如:

x = np.arange(10, dtype=np.uint8)
y = x[::2]

现在,y与x共享相同的内存缓冲区,但它在内存中不是连续的(请看一下x.flagsvsy.flags)。相反,它引用x内存缓冲区中的项(比较x.strides和{})。

如果我们试图访问y.data,我们会得到一个错误,告诉我们这不是内存中的连续数组,并且我们无法为它获得一个单段缓冲区:In [5]: y.data

-
AttributeError Traceback (most recent call last)
 in ()
> 1 y.data
AttributeError: cannot get single-segment buffer for discontiguous array

这是numpy数组有一个tofile方法的很大一部分原因(它也早于python的buffer方法,但这是另一个故事)。在

tofile将在不分配额外内存的情况下将数组中的数据写入文件。但是,由于它是在C级实现的,它只适用于真正的file对象,而不是文件类对象(例如socket、StringIO等)。在

例如:buf[:N].tofile(f)

但是,这是在C级实现的,只适用于实际的file对象,而不是sockets、StringIO和其他类似文件的对象。

但是,这允许您使用任意数组索引。在buf[someslice].tofile(f)

将生成一个新视图(相同的内存缓冲区),并有效地将其写入磁盘。在您的确切情况下,它将比切片arr.data缓冲区并直接将其写入磁盘稍慢。

如果您希望使用数组索引(而不是字节数),那么ndarray.tofile方法将比f.write(arr.tostring())更有效。