2008-10-27 206 views
4

将数据存储到网络上的文件的最佳方式是什么,稍后将以编程方式再次读入。该程序的目标平台是Linux(Fedora),但它需要将文件写入Windows(XP)机器什么是将数据写入文件的“最佳”方法,以后再读入。

这需要使用C++,因此会有大量的写/读事件它需要高效,并且数据需要以可以轻松读回的方式写出来。

整个文件可能不会被读回,我需要搜索的文件中的数据的特定块,并阅读该回来了。

将简单的二进制流的作家呢? 我应该如何存储数据 - XML?

还有什么我需要担心的?


UPDATE:要澄清一下,这里有一些答案peterchen的

请澄清:

*你只追加块,或者你 还需要删除/更新它们?

我只需要追加到文件的末尾,但需要在它

*** are all blocks of the same size?** 

没有,数据可能会有所不同,通过它来搜索和检索任意点大小 - 一些将是自由文本评论(如在这里的帖子)其他将是特定的对象类数据(参数集)

*** is it necessary to be a single file?** 

否,但期望

*** by which criteria do you need to locate blocks?** 

通过数据类型和时间戳。例如,如果我定期写出一组特定的参数,在识别其他数据(如自由文本)时,我想在某个日期/时间查找这些参数的值 - 所以我需要搜索时间I写了最近的那个日期这些参数,并宣读他们回来。

*** must the data be readable for other applications?** 

*** do you need concurrent access?** 

是的,我可能会继续写,因为我读。但一次只能写一个。

*** Amount of data (per block/total) - kilo, mega, giga, tera?** 

的数据量会很低每写......从字节数的轿跑车几百个字节 - 总应该看到比几百千字节可能的一个FWE兆而已。 (仍然不确定尚未)

**>如果你需要这一切,滚动你自己是一个挑战,我肯定会

建议使用一个数据库。如果您需要小于,请注明所以我们可以 建议。**

系统,以便不遗憾的是一种选择数据库将在未来复杂化。

+0

谢谢你的澄清,我会建议更多或更少JoãoAugusto所描述的。我giess我cna现在删除我的回复:) – peterchen 2008-10-27 16:11:45

回答

5

你的问题太笼统了。我首先定义我的需求,然后定义文件的记录结构,然后使用文本表示来保存它。看看Eric Stone Raymond's data metaformat,在JSON,也许CSVXML。 peterchen的所有观点都显得相关。

1

你需要看看你正在写出的数据类型。一旦处理对象而不是POD,只需写出对象的二进制表示形式就不一定会导致任何可以成功反序列化的内容。

如果您只是“写出文本,那么如果您使用相同的文本表示法编写文本,那么读取数据应该相对容易。如果你想写出更复杂的数据类型,你可能需要看看boost :: serialization。

+0

我确实需要存储特定对象的'值'或'状态',但不能确定序列化是答案或如果我应该手动将它们解析成键值对,或数据的向量。 – Krakkos 2008-10-27 22:09:24

+0

一些对象的数据相当复杂,因为它们包含其他对象,其中包含其他对象等 – Krakkos 2008-10-27 22:10:00

+0

如果您试图存储相当复杂的数据,我肯定会调查可用的序列化库,因为它们将为您节省大量的头痛和迟到通过滚动自己的夜间调试。 – 2008-10-29 09:07:23

1

您的应用程序听起来像它需要一个数据库。如果你负担得起,使用一个。但不要使用像sqlite这样的嵌入式数据库引擎通过网络存储文件,因为它可能对您而言太不稳定。如果你仍然想使用类似的东西,你必须通过自己的访问协议通过自己的读写器进程来使用它,如果你使用基于文本的文件格式如XML,稳定性问题仍然适用,所以你必须做他们一样。

虽然我不能确定你的工作量。

3

会有大量的读/写事件,所以它需要有效率,

这不会是有效的。

我做了很多时间在这个早在Win2K的日子里,当我不得不实施一项计划,在它本质上有一个文件副本。我发现,到目前为止,我的程序中最大的瓶颈似乎是每个I/O操作的开销。我在减少总体运行时发现的最有效的事情是减少我请求的I/O操作数量。

我开始做相当流的I/O,但是这并不好,因为愚蠢的编译器为每个单个字符发出一个I/O。它的性能与shell的“copy”命令相比只是可怜的。然后我试着写出一整行,但这只是稍微好一点。

最终,我最终编写了程序,试图将整个文件读入内存,这样在大多数情况下只有2个I/O:一个读入内存,另一个写入内存。这是我看到巨额储蓄的地方。处理手动缓冲所涉及的额外代码在等待I/O完成所需的时间较少的情况下得到弥补。

当然这是7年前,所以我想现在可能会有很大的不同。如果你想确定的话,请自己来一次。

0

如果您没有进行文本存储,请将其存储为二进制文件。文本效率非常低下; XML更糟糕。存储格式效率的缺乏预示着更大的文件传输,这意味着更多的时间。如果您不得不存储文本,请通过zip库进行过滤。

您的主要问题将是文件锁定和并发性。当你必须以并发的方式写入/读取/写入时,所有东西都会开始变得平坦。在这一点上,得到某种安装的数据库和BLOB文件了,或者什么,因为你会写在这一点上你自己的数据库...和没有人想要重新发明那轮(你知道,如果他们不是自己做自己的DB公司,或者是博士生,或者有一个奇怪的爱好......)

1

如果你只是在谈论几兆字节,我不会存储在磁盘上在所有。在网络上有一个接受数据并将其存储在内部的进程,并接受对该数据的查询。如果您需要数据记录,则此过程也可以将其写入磁盘。请注意,这听起来很像数据库,这确实可能是最好的方式。我不明白这是如何使系统复杂化。事实上,它使得它更容易。只需编写一个抽象数据库的类,并让代码的其余部分使用它。

我过去自己也经历过这个过程,包括把数据库视为过于复杂。它开始相当简单,但几年后,我们写了自己的,执行不力,错误,难以使用的数据库。那时,我们把我们的代码废掉了,转移到了postgres。我们从未后悔改变。

+0

是的,我越想到它,我越是期待扩展,它听起来像一个适当的数据库越是答案..最初我将不得不实施某种手动文件写作,但我希望我需要最终提出一个数据库解决方案。 – Krakkos 2008-10-27 22:12:39

3

也许你应该有另一个文件,将被读入具有固定大小数据的向量。

struct structBlockInfo 
    { 
     int iTimeStamp; // TimeStamp 
     char cBlockType; // Type of Data (PArameters or Simple Text) 
     long vOffset;  // Position on the real File 
    }; 

你添加一个新的块每次你也将它添加到这个矢量对应的信息,并保存。

现在,如果你想读取一个特定的块,你可以在这个向量上搜索,使用fseek(或其他)将自己定位在“真实文件”上,并读取X字节(此偏移量为其他的或文件 的)结束的开始,做一个铸件的东西取决于cBlockType,例:

struct structBlockText 
    { 
     char cComment[]; 
    }; 

    struct structBlockValuesExample1 
    { 
     int iValue1; 
     int iValue2; 
    }; 

    struct structBlockValuesExample2 
    { 
     int iValue1; 
     int iValue2; 
     long lValue1; 
     char cLittleText[]; 
    }; 

阅读一些字节....

fread(cBuffer, 1, iTotalBytes, p_File); 

如果是一个BLockText ...

structBlockText* p_stBlock = (structBlockText*) cBuffer; 

如果这是一个structBlockValuesExample1 ...

structBlockValuesExample1* p_stBlock = (structBlockValuesExample1*) cBuffer; 

注意:cBuffer可以持有多单座。

+0

我会推荐一个类似的解决方案。一些条款可能需要并发(附加数据后索引的原子更新),当然应该禁用自动填充,而使用手动填充。 – peterchen 2008-10-27 16:14:13

1

这是我对数据的读/写:

template<class T> 
    int write_pod(std::ofstream& out, T& t) 
{ 
    out.write(reinterpret_cast<const char*>(&t), sizeof(T)); 
    return sizeof(T); 
} 

template<class T> 
    void read_pod(std::ifstream& in, T& t) 
{ 
    in.read(reinterpret_cast<char*>(&t), sizeof(T)); 
} 

这并不为载体,双端队列的工作等。但它很容易通过简单地写出项目之后的数据的数量,做到了:

struct object { 
    std::vector<small_objects> values; 

    template <class archive> 
    void deserialize(archive& ar) { 
     size_t size; 
     read_pod(ar, size); 
     values.resize(size); 
     for (int i=0; i<size; ++i) { 
      values[i].deserialize(ar); 
     } 
    } 
} 

当然,你将需要实现序列化&反序列化功能,但它们很容易实现......

1

我会检查出Boost Serialization library

他们的一个例子是:

#include <fstream> 

// include headers that implement a archive in simple text format 
#include <boost/archive/text_oarchive.hpp> 
#include <boost/archive/text_iarchive.hpp> 

///////////////////////////////////////////////////////////// 
// gps coordinate 
// 
// illustrates serialization for a simple type 
// 
class gps_position 
{ 
private: 
    friend class boost::serialization::access; 
    // When the class Archive corresponds to an output archive, the 
    // & operator is defined similar to <<. Likewise, when the class Archive 
    // is a type of input archive the & operator is defined similar to >>. 
    template<class Archive> 
    void serialize(Archive & ar, const unsigned int version) 
    { 
     ar & degrees; 
     ar & minutes; 
     ar & seconds; 
    } 
    int degrees; 
    int minutes; 
    float seconds; 
public: 
    gps_position(){}; 
    gps_position(int d, int m, float s) : 
     degrees(d), minutes(m), seconds(s) 
    {} 
}; 

int main() { 
    // create and open a character archive for output 
    std::ofstream ofs("filename"); 

    // create class instance 
    const gps_position g(35, 59, 24.567f); 

    // save data to archive 
    { 
     boost::archive::text_oarchive oa(ofs); 
     // write class instance to archive 
     oa << g; 
     // archive and stream closed when destructors are called 
    } 

    // ... some time later restore the class instance to its orginal state 
    gps_position newg; 
    { 
     // create and open an archive for input 
     std::ifstream ifs("filename"); 
     boost::archive::text_iarchive ia(ifs); 
     // read class state from archive 
     ia >> newg; 
     // archive and stream closed when destructors are called 
    } 
    return 0; 
} 
相关问题