在 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 个名字。
在这种情况下,deque
或 vector
将比哈希映射更快并且使用更少的内存。
我很想听听一个好的动机。搜索向量和双端队列是一个 O(N) 操作。一个好的哈希表摊销 O(1)。向量的插入可能更快。但这通常只在启动时完成一次。然后我们希望查找是一种快速的操作。哈希表也不会比向量使用更多的内存。用于表的额外内存可以忽略不计。所有这些解决方案的内存要求都是 O(N)。以上是关于在 C++ 中保存/存储/导出大型对象的主要内容,如果未能解决你的问题,请参考以下文章