【发布时间】:2013-10-16 16:31:49
【问题描述】:
我有一个dictionary<string, int[]>,我需要尽可能高效地从磁盘存储和检索它。
密钥长度(字符串)通常会在 1 到 60 个字符(unicode)之间变化,但可能会超过该长度(但是这是边际的,这些值可能会被丢弃)。数组中的整数将在 1 到 1 亿之间。 (通常为 1 到 5M)
我的第一个想法是使用分隔格式:
key [tab] int,int,int,int,...
key2 [tab] int,int,int,int,...
...
并按如下方式加载字典:
string[] Lines = File.ReadAllLines(sIndexName).ToArray();
string[] keyValues = new string[2];
List<string> lstInts = new List<string>();
// Skip the header line of the index file.
for (int i = 1; i < Lines.Length; i++)
{
lstInts.Clear();
keyValues = Lines[i].Split('\t');
if (keyValues[1].Contains(','))
{
lstInts.AddRange(keyValues[1].Split(','));
}
else
{
lstInts.Add(keyValues[1]);
}
int[] iInts = lstInts.Select(x => int.Parse(x)).ToArray();
Array.Sort(iInts);
dic.Add(keyValues[0], iInts);
}
它可以工作,但是考虑到潜在的大小要求,很明显这种方法永远无法很好地扩展。
对于这个问题是否有现成的解决方案,还是我需要完全重新设计算法?
编辑:我有点不好意思承认,但我不知道字典可以序列化为二进制。我对其进行了测试,这正是我所需要的。
这是代码(欢迎提出建议)
public static void saveToFile(Dictionary<string, List<int>> dic)
{
using (FileStream fs = new FileStream(_PATH_TO_BIN, FileMode.OpenOrCreate))
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(fs, dic);
}
}
public static Dictionary<string, List<int>> loadBinFile()
{
FileStream fs = null;
try
{
fs = new FileStream(_PATH_TO_BIN, FileMode.Open);
BinaryFormatter bf = new BinaryFormatter();
return (Dictionary<string, List<int>>)bf.Deserialize(fs);
}
catch
{
return null;
}
}
对于一个包含 100k 条目的字典,每个条目包含一个 4k 整数数组,序列化需要 14 秒,反序列化需要 10 秒,结果文件为 1.6gb。
@Patryk:请将您的评论转换为答案,以便我将其标记为已批准。
【问题讨论】:
-
“有效”是指“尺寸有效”?
-
@Stefan - 尺寸/速度似乎不是问题,因为 OP 将其存储在文本文件中......但确实有必要知道需要什么类型的“规模足够好”才可以得到答复。
-
一些旁注;而不是让您的列表在循环之外并不断清除它,只需在循环内定义列表即可。拆分不带分隔符的字符串只会返回一个大小为 1 且具有该值的数组,因此您无需检查字符串是否包含
,,只需每次拆分它并将所有值添加到列表中,即使“全部”只是一个。你需要对数组进行排序吗?如果您要重新创建现有结构,为什么它们还没有排序? -
@AlexeiLevenkov (非常有效的)问题是这里优化了什么,程序的速度、文件的大小、代码的可读性等等?
-
注意:
Dictionary被标记为[Serializable],因此您可以使用BinaryFormatter轻松地将其序列化/反序列化到二进制文件。我不知道它是否适合您的用例...
标签: c# performance file-access