操作
open() 函数: string filename = “I.xml”; FileStorage fs(filename,
FileStorage::WRITE); \… fs.open(filename, FileStorage::READ);
无论以哪种方式绑定,函数中的第二个参数都以常量形式指定你要对文件进行操作的类型,包括:WRITE, READ 或
APPEND。文件扩展名决定了你将采用的输出格式。如果你指定扩展名如 .xml.gz ,输出甚至可以是压缩文件。 当 FileStorage
对象被销毁时,文件将自动关闭。当然你也可以显示调用 release 函数: fs.release();
输入\输出文本和数字
。 数据结构使用与STL相同的 << 输出操作符。输出任何类型的数据结构时,首先都必须指定其标识符,这通过简单级联输出标识符即可实现。基本类型数据输出必须遵循此规则:
fs << “iterationNr” << 100;
读入则通过简单的寻址(通过 [] 操作符)操作和强制转换或 >> 操作符实现:
int itNr;
fs[“iterationNr”] >> itNr;
itNr = (int) fs[“iterationNr”];
输入\输出 vectors(数组)和相应的maps
. 之前提到我们也可以输出maps和序列(数组, vector)。同样,首先输出变量的标识符,接下来必须指定输出的是序列还是map。
对于序列,在第一个元素前输出”[“字符,并在最后一个元素后输出”]“字符:
fs << “strings” << “[”; // 文本 - 字符串序列
fs << “image1.jpg” << “Awesomeness” << “baboon.jpg”;
fs << “]”; // 序列结束
对于maps使用相同的方法,但采用”{“和”}“作为分隔符。
fs << “Mapping”; // 文本 - mapping
fs << “{” << “One” << 1;
fs << “Two” << 2 << “}”;
注意,map为1个string,一个变量交替传入。
对于数据读取,可使用 FileNode 和 FileNodeIterator 数据结构。 FileStorage 的[] 操作符将返回一个 FileNode 数据类型。如果这个节点是序列化的,我们可以使用 FileNodeIterator 来迭代遍历所有元素。
FileNode n = fs[“strings”]; // 读取字符串序列 - 获取节点
if (n.type() != FileNode::SEQ)
{
cerr << “strings is not a sequence! FAIL” << endl;
return 1;
}
FileNodeIterator it = n.begin(), it_end = n.end(); // 遍历节点
for (; it != it_end; ++it)
cout << (string)*it << endl;
对于maps类型,可以用 [] 操作符访问指定的元素(或者 >> 操作符):
n = fs[“Mapping”]; // 从序列中读取map
cout << "Two " << (int)(n[“Two”]) << "; ";
cout << "One " << (int)(n[“One”]) << endl << endl;
读写自定义数据类型
。 假设你定义了如下数据类型:
class MyData
{
public:
MyData() : A(0), X(0), id() {}
public: // 数据成员
int A;
double X;
string id;
};
添加内部和外部的读写函数,就可以使用OpenCV I/O XML/YAML接口对其进行序列化(就像对OpenCV数据结构进行序列化一样)。内部函数定义如下:
void write(FileStorage& fs) const //对自定义类进行写序列化
{
fs << “{” << “A” << A << “X” << X << “id” << id << “}”;
}
void read(const FileNode& node) //从序列读取自定义类
{
A = (int)node[“A”];
X = (double)node[“X”];
id = (string)node[“id”];
}
接下来在类的外部定义以下函数:
void write(FileStorage& fs, const std::string&, const MyData& x)
{
x.write(fs);
}
void read(const FileNode& node, MyData& x, const MyData& default_value = MyData())
{
if(node.empty())
x = default_value;
else
x.read(node);
}
这儿可以看到,如果读取的节点不存在,我们返回默认值。更复杂一些的解决方案是返回一个对象ID为负值的实例。
一旦添加了这四个函数,就可以用 >> 操作符和 << 操作符分别进行读,写操作:
MyData m(1);
fs << “MyData” << m; // 写自定义数据结构
fs[“MyData”] >> m; // 读自定义数据结构
或试着读取不存在的值:
fs[“NonExisting”] >> m; // 请注意不是 fs << “NonExisting” << m
cout << endl << "NonExisting = " << endl << m << endl;
最终效果:
%YAML:1.0
iterationNr: 100
strings:
- “image1.jpg”
- Awesomeness
- “baboon.jpg”
Mapping:
One: 1
Two: 2
R: !!opencv-matrix
rows: 3
cols: 3
dt: u
data: [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ]
T: !!opencv-matrix
rows: 3
cols: 1
dt: d
data: [ 0., 0., 0. ]
MyData:
A: 97
X: 3.1415926535897931e+000
id: mydata1234