- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
在编写我的第一个 Django 应用程序时,我遇到了 boost::python 的以下问题。从 python 代码,我需要传递 io.BytesIO到采用 std::istream 的 C++ 类。
我有一个遗留的 C++ 库,用于读取特定格式的文件。让我们调用 somelib。这个库的接口(interface)使用 std::istream 作为输入。像这样:
class SomeReader
{
public:
bool read_from_stream(std::istream&);
};
我想包装它,以便我可以通过以下方式使用 python 中的库:
reader = somelib.SomeReader()
print ">>Pyhton: reading from BytesIO"
buf = io.BytesIO("Hello Stack Overflow")
reader.read(buf)
我找到了如何为实际的 python 文件对象执行此操作。但不清楚如何为任意 file-like 对象执行此操作。这是我目前拥有的 python 绑定(bind)的定义:
using namespace boost::python;
namespace io = boost::iostreams;
struct SomeReaderWrap: SomeReader, wrapper<SomeReader>
{
bool read(object &py_file)
{
if (PyFile_Check(py_file.ptr()))
{
FILE* handle = PyFile_AsFile(py_file.ptr());
io::stream_buffer<io::file_descriptor_source> fpstream (fileno(handle), io::never_close_handle);
std::istream in(&fpstream);
return this->read_from_stream(in);
}
else
{
//
// How do we implement this???
//
throw std::runtime_error("Not a file, have no idea how to read this!");
}
}
};
BOOST_PYTHON_MODULE(somelib)
{
class_<SomeReaderWrap, boost::noncopyable>("SomeReader")
.def("read", &SomeReaderWrap::read);
}
是否有或多或少的通用方法将 python IO 对象转换为 C++ 流?
提前谢谢你。
作为实验的结果,我创建了一个小的 github repo这说明了这个问题。
最佳答案
而不是转换 Python io.BytesIO
对象,考虑实现 Boost.IOStreams 的模型 Source能够从 Python io.BytesIO
对象中读取的概念。这将允许构建一个 boost::iostreams::stream
并可供 SomeReader::read_from_stream()
使用。
这tutorial演示如何创建和使用自定义 Boost.IOStream 源。总的来说,这个过程应该是相当简单的。只需要根据 io.BufferedIOBase.read()
实现 Source 概念的 read()
函数:
/// Type that implements the Boost.IOStream's Source concept for reading
/// data from a Python object supporting read(size).
class PythonInputDevice
: public boost::iostreams::source // Use convenience class.
{
public:
explicit
PythonInputDevice(boost::python::object object)
: object_(object)
{}
std::streamsize read(char_type* buffer, std::streamsize buffer_size)
{
namespace python = boost::python;
// Read data through the Python object's API. The following is
// is equivalent to:
// data = object_.read(buffer_size)
boost::python::object py_data = object_.attr("read")(buffer_size);
std::string data = python::extract<std::string>(py_data);
// If the string is empty, then EOF has been reached.
if (data.empty())
{
return -1; // Indicate end-of-sequence, per Source concept.
}
// Otherwise, copy data into the buffer.
copy(data.begin(), data.end(), buffer);
return data.size();
}
private:
boost::python::object object_;
};
然后使用源设备创建一个boost::iostreams::stream
:
boost::iostreams::stream<PythonInputDevice> input(py_object);
SomeReader reader;
reader.read_from_stream(input);
由于 PythonInputDevice
是根据 object.read()
实现的,duck typing允许 PythonInputDevice
与任何支持具有相同前置条件和后置条件的 read()
方法的 Python 对象一起使用。这包括内置的 Python file
对象,从而不再需要在 SomeReaderWrap::read()
中根据类型进行条件分支。
这是一个基于原始代码的完整的最小示例:
#include <algorithm> // std::copy
#include <iosfwd> // std::streamsize
#include <iostream>
#include <boost/python.hpp>
#include <boost/iostreams/concepts.hpp> // boost::iostreams::source
#include <boost/iostreams/stream.hpp>
class SomeReader
{
public:
bool read_from_stream(std::istream& input)
{
std::string content(std::istreambuf_iterator<char>(input.rdbuf()),
(std::istreambuf_iterator<char>()));
std::cout << "SomeReader::read_from_stream(): " << content << std::endl;
return true;
}
};
/// Type that implements a model of the Boost.IOStream's Source concept
/// for reading data from a Python object supporting:
/// data = object.read(size).
class PythonInputDevice
: public boost::iostreams::source // Use convenience class.
{
public:
explicit
PythonInputDevice(boost::python::object object)
: object_(object)
{}
std::streamsize read(char_type* buffer, std::streamsize buffer_size)
{
namespace python = boost::python;
// Read data through the Python object's API. The following is
// is equivalent to:
// data = object_.read(buffer_size)
boost::python::object py_data = object_.attr("read")(buffer_size);
std::string data = python::extract<std::string>(py_data);
// If the string is empty, then EOF has been reached.
if (data.empty())
{
return -1; // Indicate end-of-sequence, per Source concept.
}
// Otherwise, copy data into the buffer.
copy(data.begin(), data.end(), buffer);
return data.size();
}
private:
boost::python::object object_;
};
struct SomeReaderWrap
: SomeReader,
boost::python::wrapper<SomeReader>
{
bool read(boost::python::object& object)
{
boost::iostreams::stream<PythonInputDevice> input(object);
return this->read_from_stream(input);
}
};
BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;
python::class_<SomeReaderWrap, boost::noncopyable>("SomeReader")
.def("read", &SomeReaderWrap::read)
;
}
交互使用:
$ echo -n "test file" > test_file
$ python
>>> import example
>>> with open('test_file') as f:
... reader = example.SomeReader()
... reader.read(f)
...
SomeReader::read_from_stream(): test file
True
>>> import io
>>> with io.BytesIO("Hello Stack Overflow") as f:
... reaader = example.SomeReader()
... reader.read(f)
...
SomeReader::read_from_stream(): Hello Stack Overflow
True
关于python - 使用 boost::python 时将 python.io 对象转换为 std::istream,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24225442/
我正在尝试弄清楚如何让一个成员变量代表传入的 istream 或类自己创建的成员变量。 我认为,如果我动态分配类创建的 istream,那么使用指向 istream 的指针可能会起作用;然而,问题在于
我正在尝试理解这段代码 istream &read(istream &is, Sales_data &item) { double price = 0; is >> item.b
我编写了一个实现 IStream(COM 接口(interface)而不是 C++ 标准库类)的过滤器。这一切都很好,但我的问题是我不确定何时(如果有的话)我可以确定不会发送进一步的 IStream
我正在测试 C++PL 书中的一段代码并找到了下一段代码(我不想感觉我是在将它从书中复制粘贴到我的 IDE,所以我至少改变了变量名): istream& operator>> (istream& is
我正在阅读 C++ Practical Programming by Example by Andrew Koenig (Author)并在 4.1.3 Reading homework grades
我正在尝试使用 istream& getline 而不是使用 istream& operator 从文件中读取行。 结果cpp #include "Result.h" Result::Result()
我试图通过套接字连接发送图像,但我遇到了以下代码的问题: //stream to char array STATSTG myStreamStats; ULONG bytesSaved; myStrea
这里有两段代码,我起初认为它们应该是等价的: { std::ifstream stream("test.bin", std::ios_base::in | std::ios_base::bin
我在网上查了,但没找到合适的。 怎么可能有这样的主线(原始主线): int main() { Image left; std::ifstream ifs("l
假设我有以下代码: std::ifstream file(name, flags); file.seekg(0, std::ios::beg); // Check for error file.rea
在 Windows 上的 C++ 中,是否有任何简单的方法可以为现有 std::stream 对象创建 (COM) IStream 接口(interface)? 一个示例是使用 IWICStream:
考虑以下简单程序,它将输入拆分为空白并每行打印出一个非空白标记: #include int main(int argc, char* argv[]) { while (std::ci
istream& getline (istream& is, string& str); 此处 str 在换行符后终止。但是,如果我想处理 str cotents 2-3 行的情况,那么还有什么选择呢
这个问题已经有答案了: Java multiple file transfer over socket (3 个回答) 已关闭 5 年前。 我正在编写一个程序在两台计算机之间传输文件,但我没有关闭套接
void transferData(ifstream& input_file, ofstream& output_file) { char ch; while (input_file
我正在读取包含以下行的文本文件: deltaT 0.005; 在字符串中找到正确的行后,我想使用如下代码读出该值: double deltaT;
我正在查看 istream 类,但没有看到可以完全清除缓冲区并将输入设置为为下一个“干净”输入做好准备的方法。 我为我的类定义了提取运算符,在我的主程序中我要求用户输入,如下所示: while (tr
我正在编写一个解析器,之前我在尝试解析标识符(任何对 C++ 变量名有效的东西)和未闭合的字符串文字(任何以 " 开头的东西)时遇到了麻烦,但是在我的输入末尾缺少结束符 ")。我认为这是因为词法分析器
我得到了一个具有以下签名的函数。我无法改变它,我必须接受它。 void parse(std::istream & in); 我应该测试这个函数,所以基本上用预定义的内容调用它并检查值是否被正确解析。因
我的运算符(operator)有问题>> istream& operator>> (istream& is, Matrix& M) { char first; is>>first;
我是一名优秀的程序员,十分优秀!