可以使用while(文件>>...C++成语在 Cython 中读取文件?

Can one use the while(file >> ...) C++ idiom to read files in Cython?

本文关键字:gt 文件 Cython 读取 成语 while 可以使 C++      更新时间:2023-10-16

我想使用C++方式在Cython中读取文件。

我有一个简单的文件阅读器,看起来像这样:

std::ifstream file(fileName);
while(file >> chromosome >> start >> end >> junk >> junk >> strand)
{ ... }

我可以在Cython这样做吗?

可能更好的选择是使用 python 解析功能(例如 pandas' 或 numpy's(,或者,如果第一个解决方案不够灵活,则用纯C++对阅读器进行编码,然后从 Cython 调用该功能。

但是,您的方法在 Cython 中也是可能的,但为了使它起作用,需要跳过一些障碍:

  1. 整个iostream层次结构不是提供的libcpp包装器的一部分,因此必须包装它(如果没有,则快速和肮脏,那就是几行(。
  2. 由于std::ifsteam没有提供默认构造函数,因此我们无法将其构造为 Cython 中具有自动生存期的对象,并且需要注意内存管理。
  3. 另一个问题是使用定义的转换的包装。文档中没有很好地描述它(请参阅此 SO 问题(,但仅支持operator bool()]3,因此我们需要使用 C++11(否则operator void*() const;(。

所以这里有一个快速和肮脏的概念证明:

%%cython  -+ -c=-std=c++11
cdef extern from "<fstream>" namespace "std" nogil:
cdef cppclass ifstream:
# constructor
ifstream (const char* filename)
# needed operator>> overloads:
ifstream& operator>> (int& val)
# others are
# ifstream& operator>> (unsigned int& val)
# ifstream& operator>> (long& val)
# ...
bint operator bool() # is needed, 
# so while(file) can be evaluated

def read_with_cpp(filename):
cdef int a=0,b=0
cdef ifstream* foo = new ifstream(filename)
try:
while (foo[0] >> a >> b):
print(a, b)
finally: # don't forget to call destructor!
del foo

实际上,operator>>(...)的返回类型不是std::ifstream而是std::basic_istream- 我也懒得包装它。

现在:

>>> read_with_cpp(b"my_test_file.txt")

将文件内容打印到控制台。


但是,如上所述,我会用纯C++编写解析并从 Cython 使用它(例如,通过传递函子,因此 cpp 代码可以使用 Python 功能(,这是一个可能的实现:

%%cython  -+
cdef extern from *:
"""
#include <fstream>
void read_file(const char* file_name, void(*line_callback)(int, int)){
std::ifstream file(file_name);
int a,b;
while(file>>a>>b){
line_callback(a,b);
}
}
"""
ctypedef void(*line_callback_type)(int, int)
void read_file(const char* file_name, line_callback_type line_callback)
# use function pointer to get access to Python functionality in cpp-code: 
cdef void line_callback(int a, int b):
print(a,b)
# expose functionality to pure Python:
def read_with_cpp2(filename):
read_file(filename, line_callback)

现在调用read_with_cpp2(b"my_test_file.txt")会导致与上述相同的结果。