使用 ofstream 在 cython 中写下 2-D 向量
using ofstream to write down a 2-D vector in cython
我用cython编写了一个class
,它使用c ++中的vector
来创建二维数组。我目前的问题是,我想write
和read
我的数组/矩阵的内容到文本文件中和从文本文件中。我想让矩阵的每一行都写在同一行中。我也想知道我如何给每个写入值一个format
?
矩阵.pyx
from libcpp.vector cimport vector
import cython
import numpy as np
import ctypes
cimport numpy as np
cimport cython
from libcpp.string cimport string
cdef extern from "<iostream>" namespace "std" nogil:
cdef cppclass ostream:
ostream& write(const char*, int) except +
cdef cppclass istream:
istream& read(const char*, int) except +
cdef cppclass ifstream(istream):
ifstream(const char *) except +
cdef extern from "<fstream>" namespace "std" nogil:
cdef cppclass filebuf:
pass
cdef cppclass fstream:
void close()
bint is_open()
void open(const char*, openmode)
void open(const char&, openmode)
filebuf* rdbuf() const
filebuf* rdbuf(filebuf* sb)
cdef cppclass ofstream(ostream):
ofstream(const char*) except +
ofstream(const char*, openmode) except+
cdef cppclass ifstream(istream):
ifstream(const char*) except +
ifstream(const char*, openmode) except+
cdef extern from "<iostream>" namespace "std::ios_base" nogil:
cdef cppclass openmode:
pass
cdef open_mode binary
cdef extern from "<iterator>" namespace "std" nogil:
cdef cppclass ostream_iterator[T,charT,traits](iterator[output_iterator_tag, void, void, void, void]):
basic_ostream[charT,traits]* out_stream
ctypedef charT char_type
ctypedef traits traits_type
ctypedef basic_ostream[charT,traits] ostream_type
ostream_iterator (ostream_type& )
ostream_iterator (ostream_type& , const charT* )
cdef class Matrix:
def __cinit__(self, int rows=0, int columns=0):
self._rows=rows
self._columns=columns
self.matrix=new vector[double]()
self.matrix.resize(rows*columns)
def __dealloc__(self):
del self.matrix
@cython.boundscheck(False)
@cython.wraparound(False)
cpdef double getVal(self, int r, int c):
return self.matrix[0][r*self._columns+c]
@cython.boundscheck(False)
@cython.wraparound(False)
cpdef void setVal(self, int r, int c, double v):
self.matrix[0][r*self._columns+c] = v
@cython.boundscheck(False)
@cython.wraparound(False)
cpdef void _write(self, char *filename):
cdef ofstream* outputter
outputter = new ofstream(filename, binary)
cdef int j
cdef ostream_iterator[double] os(outputter," ")
cdef ostream_iterator[double] oi(outputter,"n")
for j from 0 <= j < self._rows:
copy(self.matrix.begin()+ j*self._columns,self.matrix.begin()+ (j+1)*self._columns,os)
copy(self.matrix.begin(),self.matrix.begin(),oi)
矩阵.pxd
from libcpp.vector cimport vector
cdef class Matrix:
cdef vector[double] *matrix
cdef int _rows
cdef int _columns
cpdef double getVal(self, int r, int c)
cpdef void setVal(self, int r, int c, double v)
cpdef void _write(self, char *filename)
错误消息是:
cdef ofstream out1(filename)
cdef int j
cdef ostream_iterator[double] os(out1," ")
^
------------------------------------------------------------
matrix.pyx:: Expected an identifier, found 'BEGIN_STRING'
Error compiling Cython file:
------------------------------------------------------------
...
cdef ofstream out1(filename)
cdef int j
cdef ostream_iterator[double] os(out1," ")
^
------------------------------------------------------------
matrix.pyx:: Expected ')', found 'CHARS'
任何使此代码工作的建议将不胜感激。
更新:
基于@DavidW答案,我编写了以下函数,以便将文件读入matrix
对象。
from libcpp.string cimport string
cdef extern from "<sstream>" namespace "std" nogil:
cdef cppclass istringstream(istream):
istringstream() except +
istringstream(const string&) except +
void str(const string&)
cdef class Matrix:
def __cinit__(self, size_t rows=0, size_t columns=0):
self._rows=rows
self._columns=columns
self.matrix=new vector[double]()
self.matrix.resize(rows*columns)
cpdef void _read(self, str filename):
cdef ifstream* infile = new ifstream(filename)
cdef string line
cdef size_t i = 0
cdef size_t columns = 0
while (getline(infile[0], line, 'n')):
istringstream iss(line)
self.matrix.insert(self.matrix.begin()+i*columns,istream_iterator[double](line),istream_iterator[double]())
if (i==0):
columns= self.matrix.size()
del infile
return
我认为您的主要问题是ofstream
和ostream_iterator
不能默认构造(没有参数构造)或分配,因此您不能使用它们在 Cython 中分配的堆栈(即您需要使用new
分配它们)。
我构建了一个非常简单的示例来演示如何执行此操作。我试图通过忽略不必要的模板参数(默认值是正确的)并仅包含您实际使用的函数来尽可能简化C++声明。
我将ofstream
分配为带有new
的指针,并将ostream_iterator
分配为我直接传递到copy
的临时指针。也可以将ostream_iterator
分配为指针,尽管这似乎没有必要。
#distutils: language=c++
from libcpp.vector cimport vector
cdef extern from "<ostream>" namespace "std":
cdef cppclass ostream:
ostream& put(char c) # just to write the newlines
cdef extern from "<istream>" namespace "sts":
cdef cppclass istream:
pass
cdef extern from "<fstream>" namespace "std":
cdef cppclass ofstream(ostream):
ofstream(const char*)
cdef cppclass ifstream(istream):
ifstream(const char*)
cdef extern from "<iterator>" namespace "std":
cdef cppclass ostream_iterator[T]:
ostream_iterator(ostream&, const char*)
cdef cppclass istream_iterator[T]:
istream_iterator(istream&)
istream_iterator()
cdef extern from "<algorithm>" namespace "std":
OutputIterator copy[InputIterator,OutputIterator](InputIterator, InputIterator, OutputIterator)
def test_func_write(l):
"Takes a list/tuple, converts it to a vector
and then prints that twice"
cdef vector[int] v = l
cdef ofstream* fout = new ofstream("output.txt");
try:
copy(v.begin(),v.end(),ostream_iterator[int](fout[0]," "))
fout.put("n")
copy(v.begin(),v.end(),ostream_iterator[int](fout[0]," "))
fout.put("n")
finally:
del fout
def test_func_read():
cdef vector[int] v
cdef ifstream* fin = new ifstream("output.txt")
try:
v.insert(v.end(),istream_iterator[int](fin[0]),istream_iterator[int]())
return v
finally:
del fin
我使用put
函数将换行符直接写入fout
。
阅读总是比写作复杂一些。我们可以直接insert
向量,它会一直读取直到到达终点。不幸的是,它对换行符和空格的处理方式相同(这很难在C++流中更改),因此很难在我们进行时计算出矩阵形状。最简单的解决方案是写入文件,以便第一个元素给出列数。更复杂的方法是使用getline
将每行作为字符串获取,然后为每行创建一个istringstream
。
控制格式对ostream_iterator
不起作用。ostream
具有多种功能来控制格式(例如width
,fill
和setf
。但是,它们仅适用于下一个输出,然后被重置。因此,对于编写多个输出的迭代器,它们非常有用。一个常见的解决方案(1 2)似乎是编写一个包装类来应用于每个元素的格式化程序,但这在Cython中并不实用。
以防万一你想使用格式标志(一次写一个元素),你会这样做
cdef extern from "<ostream>" namespace "std":
cdef cppclass fmtflags "std::ios_base::fmtflags":
pass
fmtflags left "std::ios_base::left"
fmtflags right "std::ios_base::left"
# etc...
cdef cppclass ostream:
#...
fmtflags setf(fmtflags)
int width(int)
char fill(char)
然后你只需打电话:
fout.width(10)
fout.fill("x")
fout.setf(left)
对于它的价值,我真的不认为尝试使用 Cython 中的 C++ 标准库编写矩阵类是一个好主意 - 你总是会与 Cython 对C++模板的有限支持作斗争。
希望最终编辑:您使用getline
和istringstream
的"读取"示例并不遥远。只是为了列出我必须进行的更改
# istream needs a "bool" operator for you to use it in a while loop.
# You could also use the function "good()"
from libcpp cimport bool
cdef extern from "<istream>" namespace "std":
cdef cppclass istream:
bool operator bool()
# You need to declare getline. I'm using the simpler version without
# the delimiter but it doesn't really matter
cdef extern from "<string>" namespace "std":
istream& getline(istream&, string& s)
# the loop looks like:
while (getline(infile[0], line)):
self.matrix.insert(self.matrix.end(), # use "end" to insert at the back (this was a mistake in my original example
istream_iterator[double](istringstream(line)), # just make the istringstream as a temporary
istream_iterator[double]())
if (i==0):
columns= self.matrix.size()
i += 1 # you forgot this
- 写入向量<向量<bool>>
- 函数向量_指针有不同的原型,我可以构建一个吗
- std::向量与传递值的动态数组
- 将值指定给向量(2D)的向量中的某个位置
- 找不到成员对象:没有名为get_event()的成员,也处理多态性和向量
- 如何使用向量的template_back函数
- 尝试通过多个向量访问变量时,向量下标超出范围
- 如何通过派生类函数更改基类中的向量
- C++从另一个类访问公共静态向量的正确方法是什么
- 如何将ampl中的集合表示为c++中的向量
- 变量没有改变?通过向量的函数调用
- 迭代时从向量和内存中删除对象
- 向量 <int> a {N, 0} 和 int arr a[N] = {0} 的时间复杂度有什么区别
- 如何为模板化对象创建模板向量?VS正在投掷C3203
- 计算排序向量的向量中唯一值的计数
- 矩阵向量乘法(cublasDgemv)返回零
- 一对向量构造函数:初始值设定项列表与显式构造
- 将结构向量排序为子组
- 在C++中调整向量中的索引
- 向量元素的引用地址与它所指向的向量元素的地址不同.为什么