Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 用C语言存储/检索词典的最有效方法是什么?_C#_Performance_File Access - Fatal编程技术网

C# 用C语言存储/检索词典的最有效方法是什么?

C# 用C语言存储/检索词典的最有效方法是什么?,c#,performance,file-access,C#,Performance,File Access,我有一本字典,我需要尽可能高效地从磁盘上存储和检索它 键长度字符串通常在1到60个字符的unicode范围内变化,但可能会超过该长度,但这是一个边缘值,这些值可能会被丢弃。数组中的整数将在1到1亿之间。通常为1至5米 我的第一个想法是使用分隔格式: key [tab] int,int,int,int,... key2 [tab] int,int,int,int,... ... 并按如下方式加载字典: string[] Lines = File.ReadAllLines(sIndexName).

我有一本字典,我需要尽可能高效地从磁盘上存储和检索它

键长度字符串通常在1到60个字符的unicode范围内变化,但可能会超过该长度,但这是一个边缘值,这些值可能会被丢弃。数组中的整数将在1到1亿之间。通常为1至5米

我的第一个想法是使用分隔格式:

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


@帕特里克:请将您的评论转换为答案,以便我将其标记为已批准。

我猜您希望在加载期间减少内存占用。现在,您正在将所有内容加载到数组中的内存中,然后将所有内容复制到字典中。在原始数组超出作用域并被垃圾回收之前,将有一段时间需要大约2倍的内存使用。如果它是一个非常大的文件,那么可能会有很多。。。如果只有几兆字节,那也没什么大不了的

如果您想更有效地执行此操作,可以从如下流中读取数据:

string fileName = @"C:\...";
var dict = new Dictionary<string, int[]>();

using (var fs = new FileStream(fileName, FileMode.Open))
using (var reader = new StreamReader(fs))
{
    string line;
    while ((line = reader.ReadLine()) != null)
    {
        var values = line.Split(',');
        dict.Add(values[0], values.Skip(1).Select(x => Convert.ToInt32(x)).ToArray());
    }       
}
或者您可以使用Jim建议的快捷方式:

string fileName = @"C:\...";
var dict = new Dictionary<string, int[]>();

foreach (string line in File.ReadLines(fileName))
{
    var values = line.Split(',');
    dict.Add(values[0], values.Skip(1).Select(x => Convert.ToInt32(x)).ToArray());
}
这对文件格式做出了一些严格的假设。值得注意的是,每一行都是格式键int1、int2、int3、int4,。。。而且密钥不包含逗号。每行还必须以Environment.NewLine字符结尾

虽然值得注意的是,你应该考虑这样一个事实,即当你的当前代码不是非常有效的时候,它不是你的主要瓶颈。文件读取速度通常是最大的瓶颈。如果您的代码确实遇到性能问题,那么很可能与您同步读取文件有关。任何文件I/O都应该在具有用户界面的应用程序中异步完成。

字典被标记为[Serializable],并实现ISerializable


这意味着您可以使用,例如,执行与流之间的二进制序列化和反序列化。比如说,文件流:

“高效”是指大小高效?@Stefan-大小/速度似乎不是一个问题,因为OP将其存储在文本文件中。。。但事实上,在回答这个问题之前,有必要充分了解需要什么样的量表;与其让列表在循环之外并不断清除它,不如在循环内部定义列表。拆分一个没有分隔符的字符串只会返回一个大小为1且具有该值的数组,因此您无需检查该字符串是否包含,只需每次拆分该字符串并将所有值添加到列表中,即使所有值仅为一。您需要对数组进行排序吗?如果你正在创建一个现有的结构,为什么它们还没有排序?@AlexeiLevenkov一个非常有效的问题是这里优化了什么,程序的速度,文件的大小,代码的可读性等等?注意:字典被标记为[可序列化],因此,您可以使用BinaryFormatter轻松地将其序列化/反序列化为二进制。我不知道它是否适合您的用例…+1。请注意,您可以用File.ReadLinesfileName中的foreach字符串行替换大量代码