Python &引用;获取文件位置失败";将ndarray.tofile()和numpy.fromfile()与FIFO一起使用时
我正在编写一些虚拟代码,以了解FIFO如何在python中工作(稍后在我正在进行的项目中使用它们)。当我尝试写入或读取时,会收到“OSError:获取文件位置失败”消息 我试图在两个python代码之间传输复杂的数据。我使用FIFO,因为我需要更多不同的通道,以便在运行的模块之间进行通信。我使用bash脚本运行它们,您可以在下面看到Python &引用;获取文件位置失败";将ndarray.tofile()和numpy.fromfile()与FIFO一起使用时,python,python-3.x,numpy,fifo,Python,Python 3.x,Numpy,Fifo,我正在编写一些虚拟代码,以了解FIFO如何在python中工作(稍后在我正在进行的项目中使用它们)。当我尝试写入或读取时,会收到“OSError:获取文件位置失败”消息 我试图在两个python代码之间传输复杂的数据。我使用FIFO,因为我需要更多不同的通道,以便在运行的模块之间进行通信。我使用bash脚本运行它们,您可以在下面看到 #first.py 将numpy作为np导入 数据=np.complex64([1,2,3]) fifo=打开(“fifoka”、“wb”) 数据文件(fifo)
#first.py
将numpy作为np导入
数据=np.complex64([1,2,3])
fifo=打开(“fifoka”、“wb”)
数据文件(fifo)
fifo.flush()
fifo.close()
#second.py
将numpy作为np导入
fifo=打开(“fifoka”、“rb”)
数据=np.fromfile(fifo,数据类型=np.complex64)
fifo.close()
打印(数据)
#/bin/bash
mkfifofifoka
python3 first.py|\
python3秒.py
菲福卡酒店
如果我使用fifo.write(data.tobytes())
而不是data.tofile(fifo)
,那么它工作得很好,但根据规则,它应该以同样的方式工作
当我试图从同一个fifo读取数据时,我也有同样的问题,所以我认为我也犯了同样的错误
所以我的问题是,在这种情况下,我应该如何正确地使用
np.fromfile()
和ndarray.tofile()
。我认为这是由于numpy.ndarray.tofile的工作原理
当fid是文件对象时,数组内容直接写入
文件,绕过文件对象的写入方法。因此,托菲尔
不能与支持压缩的文件对象一起使用(例如。,
gzip文件)或不支持fileno()的类文件对象(例如。,
BytesIO)
不可能在FIFO中进行搜索
在系统调用级别,
lseek(2)
也用于获取文件位置。所以这也不起作用。似乎是numpy的一个缺陷。我刚刚遇到了这个问题,将一些代码从Py2.7(numpy版本未知)移动到Py3.8.2(numpy 1.17.4)。将arr.tofile(fout)
更改为fout.write(arr.tobytes())
使其正常工作
更好的解决方案:如果要写入的数组是连续的,请使用fout.write(memoryview(arr))
,这样可以避免复制。如果可能,下面的实用程序将使用memoryview
,否则tobytes
def arr_tofile(a,outfile):
if a.flags['C_CONTIGUOUS']:
b = memoryview(a)
else:
b = a.tobytes()
outfile.write(b)
十多年来,我一直通过管道使用arr.tofile(f)
将数据发送到2.x下的其他进程,所以这是一个新缺陷,可能是python 3.x特有的
诚然,文档中说tofile
绕过write
方法并使用fd-但没有理由为了执行tofile
而寻找或告知,也没有理由不在管道上工作
更新-由于兼容性问题,它在python3中不起作用
对于python2操作,tofile中的过程是从python文件
对象获取文件*
;然后,要刷新该文件,请获取底层文件号,然后使用PyArray\u-ToFile
函数写入该文件
显然,由于文件对象中添加了内部缓冲,Python3打破了这一点
现在,它通过调用npy\u PyFile\u Dup2
从python文件对象生成一个文件*
,然后使用函数PyArray\u-ToFile
从该文件*
写入fd。最后,npy\u PyFile\u DupClose2(file,fd,orig\u pos)
用于关闭新文件并将原始文件搜索到相同位置。对于python2,将npy\u PyFile\u Dup2
和npy\u PyFile\u Dup2
定义为基本存根;如上所述,使用单个基础文件*
在Python3中,他们做的更多。我没有详细介绍,但是npy\u PyFile\u Dup2
实际上使用python机制调用了os.dup
来创建一个新的文件句柄,并且在写入之后,npy\u PyFile\u DupClose2
对新文件执行一个“告诉”,然后对原始python文件执行一个“搜索”,跳过刚刚在另一个句柄上写入的数据
底线-这有点混乱-在python3下,最好避免使用arr.tofile(file)
,即使它可以工作,除非写入的大小足够大,足以证明相当大的开销。而且它对不可查找的文件根本不起作用。在这两种情况下,请使用file.write(memoryview(arr))
或file.write(arr.tobytes())
显而易见的下一个问题-是否可以在管道上解决此问题
也许-它将依赖于能够检测到输出是一个管道,在这种情况下,刷新python文件对象并继续写入其文件句柄(如Python2方法)。写入管道时,无需支持输出文件上的后续“告诉”
抨击 C-API 实用程序函数npy_PyFile_Dup和npy_PyFile_DupClose被应用于其文件对象的内部缓冲python 3破坏。为了修复此问题,在npy_3kcompat.h中声明了两个新函数npy_PyFile_Dup2和npy_PyFile_DupClose2,并且不推荐使用旧函数。由于这些函数的脆弱性,建议尽可能使用python API
为什么在bash中使用pipe
|
?看起来不像是first.py
正在向STDOUT
输出任何内容。只需一个接一个地运行python3 first.py
和python3 second.py
,它就会工作。谢谢你的回答,但在我将|
更改为&
后,它仍然挂起。我不确定这两种方法为什么不同,但我经历了sa
PyObject *file = (from param)
FILE *fd;
npy_off_t orig_pos = 0;
fd = npy_PyFile_Dup2(file, "wb", &orig_pos);
if (fd == NULL) {
goto fail;
}
if (PyArray_ToFile(self, fd, sep, format) < 0) {
goto fail;
}
if (npy_PyFile_DupClose2(file, fd, orig_pos) < 0) {
goto fail;
}
if (own && npy_PyFile_CloseFile(file) < 0) {
goto fail;
}
Py_DECREF(file);
Py_RETURN_NONE;
/*
* Get a FILE* handle to the file represented by the Python object
*/
static NPY_INLINE FILE*
npy_PyFile_Dup2(PyObject *file, char *mode, npy_off_t *orig_pos)
{
int fd, fd2, unbuf;
PyObject *ret, *os, *io, *io_raw;
npy_off_t pos;
FILE *handle;
/* For Python 2 PyFileObject, use PyFile_AsFile */
#if !defined(NPY_PY3K)
if (PyFile_Check(file)) {
return PyFile_AsFile(file);
}
#endif
/* Flush first to ensure things end up in the file in the correct order */
[[[... continue to call os.dup via python interface....]]]
}
/*
* Close the dup-ed file handle, and seek the Python one to the current position
*/
static NPY_INLINE int
npy_PyFile_DupClose2(PyObject *file, FILE* handle, npy_off_t orig_pos)
{
int fd, unbuf;
PyObject *ret, *io, *io_raw;
npy_off_t position;
/* For Python 2 PyFileObject, do nothing */
#if !defined(NPY_PY3K)
if (PyFile_Check(file)) {
return 0;
}
#endif
position = npy_ftell(handle);
/* Close the FILE* handle */
fclose(handle);
....[[more]]...