在 C++ 中保存/存储/导出大型对象

Posted

技术标签:

【中文标题】在 C++ 中保存/存储/导出大型对象【英文标题】:Saving/storing/exporting large objects in C++ 【发布时间】:2013-03-05 14:40:24 【问题描述】:

背景:

我是一名新的 C++ 程序员,正在尝试构建一个程序,该程序返回一个字符串,说明给定十六进制颜色代码的颜色。总体功能是请求鼠标指针所在像素的十六进制代码,并返回一个描述颜色的字符串(如 #8B0000 的“深红色”)。 (我是色盲,这将是一个很大的帮助)

作为第一次尝试,我创建了一个 .txt 文件,其中包含换行符上所有可能的颜色代码。不用说,该文档有 16777216 行,大小为 134.2MB。我搜索了互联网,发现在 C++ 中读取 .txt 文件的唯一方法是逐行,从头到尾。这将导致对字符串“Black”的“getline()”调用 16777216 次。这种方法现在让我“绝望”了。

想法:

我想创建一个包含 16777216 个 (String colour) 实例的向量,并使用十六进制到整数的转换作为索引来定位正确的字符串。这个向量也会变得很大,构建或使用起来很不方便。

问题:

我需要找到最好的方法(如果可能的话)来保存/保存一个大型对象以及我的 c++ 类,这样我就可以导入该对象并立即使用它。

提前致谢。

【问题讨论】:

这不是在 C++ 中读取文件的唯一方法……而且该向量会很大!你真的会有 16777216 种不同的颜色名称吗? 所有颜色都有名称吗? (是的,可能,但在现实生活中不是很实用)你确定你真的想要存储所有可用颜色的颜色 RGB 值吗?为什么不只存储最常见的颜色并决定对颜色进行分组的方法? (请参阅 html 默认颜色或 X11 默认颜色(请参阅msdn.microsoft.com/en-us/library/ie/aa358802%28v=vs.85%29.aspx) 听起来像是模糊逻辑的工作!很少有人(如果有的话)能够真正分辨出#00aaab 和#00aaac 之间的区别。 XKCD 对人们使用颜色的名称进行了研究,它可能会帮助您对范围进行分类。 对于这么大的数据集,使用双端队列而不是向量。 【参考方案1】:

A) 您的文件包含超过 16777216 行,这意味着它包含的单词数量超过了英语单词的数量,并且可能是俄语、希腊语、中文和日语的总和。

B)您需要将事物放入范围,然后对正确的范围进行二进制扫描。换句话说,将海军蓝的范围作为具有低值和高值的对象映射到范围中。

C) 将所有范围放入一个大列表中并对列表进行排序。

D) 然后对任何特定颜色进行二进制扫描,它将与正确的范围相交。

例如:

// Navy blue might be this range
Low  = RGB(0,0,170)
High = RGB(0,0,200)

// Light Red might be this range
Low  = RGB(240,0,0)
High = RGB(255,0,0)

我的意思是,如果可以命名范围,为什么还要命名每种颜色?

【讨论】:

我曾考虑使用范围,但我认为需要编写一个巨大的二叉树才能进入正确的分支。我发现使用 hexToInt 整数作为索引值的想法,在某种“数据库”中立即指向正确的颜色是最吸引人的。不过还是谢谢。 :) 如果你只是使用二叉排序列表(不是二叉树),那么它会小得多,而且速度仍然非常快。你有多少个文字颜色名称?【参考方案2】:

发布的 OP:

我搜索了互联网,我发现在 C++ 中读取 .txt 文件的唯一方法是逐行,从头到尾。

这是不正确的。我不确定您使用的是什么 C++ 文件读/写类,但如果您使用的类不支持随机访问,则另找一个。

如果您重新设置并使用 fopen,您可以使用 fseek 转到文件中的特定位置。

如果您将文件中的所有记录格式化为相同的长度,那么您可以轻松地将文件中的偏移量计算为recordnumber*recordlength(假设第一条记录是数字 0)。

【讨论】:

作为支持动态访问的其他文件读取机制的说明:ifstream 有一个seekg 函数来设置当前读取位置【参考方案3】:

感谢大卫和亚历克斯的讨论:)

一种方法查找值来命名的简单解决方案

所以我建议首先根据每个颜色值的四个 MSB 量化颜色空间。

val = ((hexval & 0xf00000) >> 12) | ((hexval & 0x00f000) >> 8) | ((hexval & 0x0000f0) >> 4)

同时创建一个std::vector<std::string>,其中包含您读取颜色名称的 4096 个条目。

std::vector<std::string> names(4096);

//Read file and do for each line
names[val] = /*name for the value*/ 

//Lookup
const std::string& name = names[val];

对于双向查找,我仍然会查看boost::bimap,它可以配置为在从颜色值中查找名称时看起来像一个向量。并在查找与某个命名颜色匹配的颜色值时配置为哈希表。

【讨论】:

一个潜在的解决方案,但在处理人类感知的细微差别时失败了。 “绿色”的范围与“红色”的范围不同。尝试为确切的颜色值取一个悦耳的名称是一项非常复杂的挑战。【参考方案4】:

如果你想“保留”一个类的对象,那么我建议你腌制它!这是我认为适用于 c++ 的library

这些例程来自该库中的选择器.h,应该很有用

// C++
DumpValToFile (const Val& thing_to_serialize,
           const string& output_filename,
           Serialization_e how_to_dump_the_data);

LoadValFromFile (const string& input_filename,
             Val& result,
             Serialization_e how_data_was_dumped);

我相信参数 Val& 是你传递需要腌制的对象的地方

这些工具的作用是serialize 一个对象,以便可以轻松地将其存储在硬盘上。

我从来没有亲自使用过这个工具,但是我在 python 中使用过类似的东西,所以我建议先在 Python 中尝试酸洗东西。谷歌“python pickle”了解更多信息。

【讨论】:

【参考方案5】:

我认为您实际上只想“命名”一个非常少数可能的 2^24 8 位 RGB 值,所以std::map 是你的朋友:

std::map<int, string> colors;

colors[0x000000] = "Black";
...
colors[0xFFFFFF] = "White";

您可以从这里开始使用 HTML 颜色名称:http://www.w3schools.com/html/html_colornames.asp

您还需要编写一个“findNearest”函数(当然,除非您实际上有 1600 万个不同的颜色名称)。您的 findNearest 将计算 RGB 空间中每种命名颜色和目标颜色之间的距离。

【讨论】:

这是一个灾难性的想法!地图非常适合稀疏数据,但对于像这样的密集数据,您需要vector。有太多的事情要明智地去做。在我们想出一个合理的解决方案之前,OP 需要决定他将如何压缩色彩空间。 另外,你有一个内置的映射方案……如果他真的有16M的颜色名称,他的索引已经为他建立了。 @AlexChamberlain - 深深地叹了口气。所以你真的相信 OP 有 2^24 个合理的颜色名称吗?我确信这个 是稀疏数据,并且由于人眼/大脑组合,名称不会在 RGB 色彩空间中均匀分布,因此需要上述 findNearest 方法多于。我会试着澄清一下答案...... 我确实说过... 在我们想出一个合理的解决方案之前,OP 需要决定他将如何压缩色彩空间。 @AlexChamberlain - 地图的一个优点是它基本上与精度无关。您的密钥可以是 R、G、B 双精度的三元组,而不是 24 位 int。【参考方案6】:

我会在程序开始时将其全部读入std::map。然后使用该地图进行快速查找。如果读取文本文件需要很长时间,请考虑将其转换为某种二进制表示。为每次查找解析文本文件会很慢。

如果您想要双向查找,即从值到名称以及从名称到值。检查boost::multi_index http://www.boost.org/doc/libs/1_53_0/libs/multi_index/doc/index.html 或boost::bimap http://www.boost.org/doc/libs/1_53_0/libs/bimap/doc/html/index.html

我还会考虑使用 boost::serialization 在运行之间存储和检索地图的数据。 http://www.boost.org/doc/libs/1_53_0/libs/serialization/doc/index.html

【讨论】:

这是一个灾难性的想法!地图非常适合稀疏数据,但对于像这样的密集数据,您需要一个向量。有太多的事情要明智地去做。在我们想出一个合理的解决方案之前,OP 需要决定他将如何压缩色彩空间。 好吧,我想这是真的。但后来我会看散列地图。然后我们得到一个紧凑的表示和快速的查找。或者如果查找时间无关紧要,则使用 soretd deque。双端队列将消耗更少的连续内存。再次查看boost::bimap,如果您想要两种方式查找,则有它的版本。 但我同意 2^24 个名称需要一些时间才能写下来 ;) 我是否建议只使用每种颜色的 4 MSB 来量化颜色空间。那么“只有”4096 个名字。 在这种情况下,dequevector 将比哈希映射更快并且使用更少的内存。 我很想听听一个好的动机。搜索向量和双端队列是一个 O(N) 操作。一个好的哈希表摊销 O(1)。向量的插入可能更快。但这通常只在启动时完成一次。然后我们希望查找是一种快速的操作。哈希表也不会比向量使用更多的内存。用于表的额外内存可以忽略不计。所有这些解决方案的内存要求都是 O(N)。

以上是关于在 C++ 中保存/存储/导出大型对象的主要内容,如果未能解决你的问题,请参考以下文章

在 BigQuery 中订购大型时间序列数据集以进行导出

c++

如何导出ORACLE指定存储过程

Oracle怎么导出存储过程

将导出的 csv 保存到应用存储上的某个位置

将大型数据查询(60k+ 行)导出到 Excel