如何将A类数据写入B类格式
How to write data of type A to format of type B
我正在实现一个生成结果并将它们写入特定格式的文件的东西。
相当简单,但我希望它是动态的。
我会安排一些课程。
Data
-所有结果的基类
DataFile -所有文件格式类型的基类,具有方法addData(Data * data)
ErrorData
—源自Data,包含有关错误的数据。
InfoData—派生自Data,包含泛型信息。
XmlFile
-派生自DataFile,包含XML格式的数据
BinaryFile -从DataFile派生,包含二进制格式的数据
我的问题是:
我在哪里把实现如何写ErrorData到一个XmlFile?
我不喜欢看到的答案:
- Data 、DataFile、ErrorData或XmlFile(因为这意味着我需要在每次添加新的Data或DataFile派生类时添加这些)
- 类型转换到派生类型。
- 一般的丑陋:)
我知道基本的c++虚拟化和东西,不需要特别具体。
我确实欣赏一些代码片段,它们留下了较少的歧义。
我有一些想法,使DataWriter基类和派生类,将知道如何编写数据特定类型的到特定类型的DataFile,但我有点不确定的细节。
编辑:我将以一个示例的形式进一步说明。
让我们有两种新的文件格式,FormatATxtFile和FormatBTxtFile。
让我们假设我们有一个InfoData对象,它有参数:
留言行号:34
消息内容:Hello World
对象写入FormatATxtFile,在文件中如下所示:
: 34; Txt: Hello World;类型:信息
在FormatBTxtFile它看起来像这样:
34岁的@Info Hello World
一种将数据导出为不同格式的方法。我不需要导入,至少现在不需要。
使用它的代码应该是这样的:
DataFile * file = DataFileFactory::createFile(type);
std::vector<Data*> data = generateData();
file->setData(data);
file->writeTo("./FileName"); // correct end is added by DataFile type, ie .txt
编辑:似乎我没有弄清楚Xml和二进制文件格式会产生什么问题。我很抱歉。
让我们使用与上面相同的InfoData对象,并将其推入XmlFile格式。它可能会在某个元素下产生如下内容:
<InfoLog>
<Info Line="34">Hello World</Info>
</InfoLog>
让我们假设ErrorData类有这些参数:
错误行号:56
错误文本:LINK: fatal Error LNK1168
错误信息前10行:text1…
错误信息后10行:text2…
发生了什么事的完整日志:text3…
现在,当它被推入XML格式时,它将需要完全不同的东西。
<Problems>
<Error>
<TextBefore>text1...</TextBefore>
<Text line = 56>
LINK : fatal error LNK1168
</Text>
<TextAfter>text1...</TextAfter>
</Error>
...
</Problems>
整个文件可能看起来像这样:
<Operation>
<InfoLog>
<Info Line="34">Hello World</Info>
<Info Line="96">Goodbye cruel World</Info>
</InfoLog>
<Problems>
<Error>
<TextBefore>text1...</TextBefore>
<Text line = 56>
LINK : fatal error LNK1168
</Text>
<TextAfter>text1...</TextAfter>
</Error>
<Error>
<TextBefore>sometext</TextBefore>
<Text line = 59>
Out of cheese error
</Text>
<TextAfter>moretext</TextAfter>
</Error>
</Problems>
</Operation>
而不是试图找到一个地方把这个类,关于一个新的功能?
void copyData(const ErrorData *data, DataFile *output)
{
// ...
}
你可以为任何你想转换的数据类型重载这个函数。
或者,您也可以使用模板:
template<typename A, typename B> copyData(const A *data, const B *output);
然后你可以为你需要支持的特定类型特殊化模板。
像标准库一样使用virtual
函数/操作符。我们都可以使用istream&
并从operator>>
中提取我们想要的东西,而我们完全不关心底层流,无论是cin
, fstream
还是stringstream
。而把你的data
参考然后(Data& data
)。
如果您考虑下面的代码,它提供了如何任意组合通用字段访问和通用字段流的最小示例-分解您的各种需求。如果适用性或实用程序不清楚,请告诉我....
#include <iostream>
#include <string>
struct X
{
int i;
double d;
template <typename Visitor>
void visit(Visitor& visitor)
{
visitor(i, "i");
visitor(d, "d");
}
};
struct XML
{
XML(std::ostream& os) : os_(os) { }
template <typename T>
void operator()(const T& x, const char name[]) const
{
os_ << '<' << name << '>' << x << "</" << name << ">n";
}
std::ostream& os_;
};
struct Delimiter
{
Delimiter(std::ostream& os,
const std::string& kvs = "=", const std::string& fs = "|")
: os_(os), kvs_(kvs), fs_(fs)
{ }
template <typename T>
void operator()(const T& x, const char name[]) const
{
os_ << name << kvs_ << x << fs_;
}
std::ostream& os_;
std::string kvs_, fs_;
};
int main()
{
X x;
x.i = 42;
x.d = 3.14;
XML xml(std::cout);
Delimiter delimiter(std::cout);
x.visit(xml);
x.visit(delimiter);
}
我一直在思考你的问题,这就是我的想法:
#include <iostream>
#include <list>
#include <map>
#include <string>
using namespace std;
class DataFile;
class Data {
public:
virtual void serializeTo(DataFile*) = 0;
};
class DataFile {
public:
void addData(Data* d) {
_data.push_back(d);
}
virtual void accept(string paramName, string paramValue) {
_map[paramName] = paramValue;
}
virtual void writeTo(string const& filename) = 0;
protected:
list<Data*> _data;
map<string, string> _map;
};
class FormatATxtFile: public DataFile {
public:
void writeTo(string const& filename) {
cout << "writing to " << filename << ".txt:" << endl;
for(list<Data*>::iterator it = _data.begin(); it != _data.end(); ++it) {
(*it)->serializeTo(this);
cout << "Line:" << _map["Line"] << "; "
<< "Txt:" << _map["Txt"] << "; "
<< "Type: " << _map["Type"]
<< endl;
}
cout << endl;
}
};
class FormatBTxtFile: public DataFile {
public:
void writeTo(string const& filename) {
cout << "writing to " << filename << ".b-txt" << endl;
for(list<Data*>::iterator it = _data.begin(); it != _data.end(); ++it) {
(*it)->serializeTo(this);
cout << "@" << _map["Type"] << "," << _map["Line"] << "," << _map["Txt"]
<< endl;
}
cout << endl;
}
};
class InfoData: public Data {
public:
void serializeTo(DataFile* storage) {
storage->accept("Line", line);
storage->accept("Txt", txt);
storage->accept("Type", "Info");
}
string line;
string txt;
};
int main()
{
FormatATxtFile fileA;
FormatBTxtFile fileB;
InfoData info34;
info34.line = "34";
info34.txt = "Hello World";
InfoData info39;
info39.line = "39";
info39.txt = "Goodbye cruel World";
fileA.addData(&info34);
fileA.addData(&info39);
fileB.addData(&info34);
fileB.addData(&info39);
fileA.writeTo("./Filename");
fileB.writeTo("./Filename");
}
实际上,它并没有真正写入文件,但是很容易修改以满足您的需要。
示例代码的输出是:
write to ./Filename.txt: Line:34;Txt: Hello World;类型:信息行:39;
再见,残酷的世界;类型:Info写入。/Filename.b-txt
34岁的@Info Hello World
@Info,39,再见残酷的世界
如您所见,Data
需要向DataFile
提供由名称和值标识的参数,DataFile
的每个专门化将以自己喜欢的方式处理它。
HTH
- 当使用比格式支持的精度更高的精度来显示数字时,会写出什么数据
- 将复杂的非基元C++数据类型转换为 Erlang/Elixir 格式,以使用 NIF 导出方法
- 如何为QImage检测足够的格式(数据类型)以消耗最少的RAM
- 为什么使用 C++ 中的类对象写入文件中的数据以非文本格式存储?
- 在 c++ libusb 中将数据写入得利捷 PM9500 扫描仪的正确格式
- 如何以正确的格式沿第二个管道发送回数据?
- C++ 将字符串数据包转换为 iphdr语言 - 字符串数据包的格式应该是什么?
- TCP/IP - 以 C/C++ 格式发送十六进制数据包以控制中继板
- 将数据保存在C++中,从 Python 加载 - 推荐的数据格式
- Python API用于解析包含数组格式的protobuf数据的二进制文件
- protobuf与rapidjson数据格式
- 使用访问器以两种格式打印数据
- C :如何从格式的文本文件中读取许多数据到程序中
- 基于向量的数据格式的分割故障误差
- 如何以json格式保存弹性搜索的数据
- qDebug - 如何以位(二进制格式)输出数据
- 表示命令数据包格式的数据结构
- 我如何使用错别字读取格式的数据
- 如何从内存中读取原始图像 (YUV 4:2:2) 格式的图像数据
- strstr无法搜索八进制格式数据中的字符串