可以使用 while(file >> ...) C++ 习语在 Cython 中读取文件吗?

Posted

技术标签:

【中文标题】可以使用 while(file >> ...) C++ 习语在 Cython 中读取文件吗?【英文标题】:Can one use the while(file >> ...) C++ idiom to read files in Cython? 【发布时间】:2019-12-30 11:03:41 【问题描述】:

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

我有一个简单的文件阅读器,如下所示:

std::ifstream file(fileName);

while(file >> chromosome >> start >> end >> junk >> junk >> strand)
     ... 

我可以在 Cython 中执行此操作吗?

【问题讨论】:

【参考方案1】:

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

但是,您的方法也可以在 Cython 中使用,但为了使其发挥作用,需要跳过一些障碍:

    整个iostream 层次结构不是the provided libcpp-wrappers 的一部分,因此必须将其包装起来(如果不快速和脏,那就是几行)。 由于std::ifsteam 没有提供默认构造函数,我们无法在 Cython 中将其构造为具有自动生命周期的对象,需要注意内存管理。 另一个问题是包装使用定义的转换。文档中描述的不是很好(见这个SO-question),但是只支持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&gt;&gt;(...) 的返回类型不是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") 会得到与上述相同的结果。

【讨论】:

整洁。我实际上有一个应用程序,其中 IO 是瓶颈,然后使用 C++ 读取文件比 Cython 的 for line in f_handle; line.split()... 更快。期待对您的功能进行基准测试。此外,在 Cython 中从未见过 cdef extern from *。您有文档的简短链接或解释吗? @TheUnfunCat 见cython.readthedocs.io/en/latest/src/userguide/… @TheUnfunCat 我不认为 C++ IO 通常很快。如果您担心速度,可能值得尝试 C IO(因为它不涉及类或运算符重载,所以包装起来更简单)

以上是关于可以使用 while(file >> ...) C++ 习语在 Cython 中读取文件吗?的主要内容,如果未能解决你的问题,请参考以下文章

while ( input >> s ) input是类ifstream的一个实例,这种写法对吗?求解析。

PHP dir() 函数

java 罕见的依赖报错 jstat: error while loading shared libraries: libjli.so: cannot open shared object file

读取文件内容

Python_报错:SyntaxError: EOL while scanning string literal

Python_报错:SyntaxError: EOL while scanning string literal