优化大型字典以便在.NET中读取

时间:2016-09-04 09:07:11

标签: c# .net vb.net dictionary

我有一个与数字字符串相关的夫妇列表,其中有22k。 (它是MAC地址供应商列表)。

在我的代码中,我通过前三个字节的MAC地址搜索供应商名称。

我知道,我可以使用字典,甚至可以使用数组,但每次运行程序时都需要初始化字典,但程序只使用少量翻译(项目不到百分之一)在字典中)并且在程序运行时字典的初始化需要花费大量时间。

你能想象其他方法吗?在旧的VB6中,有可能读取二进制文件并查找记录,这对我来说已经足够了,因为我只会加载我实际需要的值。

我更喜欢项目内的解决方案 - 因此没有包含数据的外部文件。我正在尝试使用以下代码: -

Vendors.add("00125A","Microsoft Corporation") 
'... this in another 22000 times '
Vendors.add("00124E","XAC AUTOMATION CORP.")

2 个答案:

答案 0 :(得分:1)

不确定最适合您的行为应该是什么,或者这实际上对您有什么帮助,但是......

您似乎正在寻找一种方法来搜索和读取结构化文件中的某条记录。

为此,您可以定义一个类来封装记录字段以及访问方法。

这是一个例子。在我的机器上创建,存储22k +记录并在大约20ms内搜索所有记录。 Otoh做100次随机搜索需要3.5秒,显然是因为它总是从开始时开始。进行顺序搜索的速度相当快......

当然,总时间取决于您的机器以及您要寻找和阅读的记录数量。

这是一个包含字节,长整数和字符串的记录类:

class aRecord
{
    byte aByte { get; set; }
    long aLong { get; set; }
    string aString { get; set; }

    public aRecord() { }

    public aRecord(byte b_, long l_, string s_)
    { aByte = b_; aLong = l_; aString = s_; }

    public void writeToStream(BinaryWriter bw )
    {
        bw.Write(aByte);
        bw.Write(aLong);
        bw.Write(aString);
    }

    public void readFromStream(BinaryReader br)
    {
        aByte = br.ReadByte();
        aLong = br.ReadInt64();
        aString = br.ReadString();
    }

    static public aRecord readFromStream(BinaryReader br, int record)
    {
        int r = 0;
        aRecord  rec = new aRecord();
        br.BaseStream.Position = 0;
        while (br.PeekChar() != -1 & r <= record  )
        {
            rec.readFromStream(br);
            r++;
        }
        return rec;
    }

    static public aRecord readFromStream(BinaryReader br, string search)
    {
        aRecord rec = new aRecord();
        while (br.PeekChar() != -1 )
        {
            rec.readFromStream(br);
            if (rec.aString.Contains(search)) return rec;
        }
        return null;
    }

}

我测试过这样:

Console.WriteLine(DateTime.Now.ToString("ss,ffff") + "  init ");

List<aRecord> data = new List<aRecord>();

Random rnd = new Random(9);

int count = 23000;
for (int i = 1000; i < count; i++ )
{
    data.Add(new aRecord((byte)(i%128), i, "X" + rnd.Next(13456).ToString()));
}

Console.WriteLine(DateTime.Now.ToString("ss,ffff") + "  write ");

string fileName = "D:\\_DataStream.dat";

FileStream sw = new FileStream(fileName, FileMode.Create);
BinaryWriter bw = new BinaryWriter(sw);

foreach(aRecord r in data)
{
    r.writeToStream(bw);

}
bw.Flush();
sw.Close();
bw.Close();

FileStream sr = new FileStream(fileName, FileMode.Open);
BinaryReader br = new BinaryReader(sr);

List<aRecord> data2 = new List<aRecord>();
Console.WriteLine(DateTime.Now.ToString("ss,ffff") + "  begin search");
for (int i = 0; i < 100; i++)
{
    aRecord  rec = aRecord.readFromStream(br, "911");
    if (rec != null) data2.Add(rec);
}
Console.WriteLine(DateTime.Now.ToString("ss,ffff") + "  done. found " + data2.Count);


Console.WriteLine(DateTime.Now.ToString("ss,ffff") + "  seek ");

aRecord ar = aRecord.readFromStream(br, 0);
Console.WriteLine(DateTime.Now.ToString("ss,ffff") + " 0 ");

aRecord ar1 = aRecord.readFromStream(br, 1);
Console.WriteLine(DateTime.Now.ToString("ss,ffff") + " 1 ");

aRecord ar2 = aRecord.readFromStream(br, 13000);
Console.WriteLine(DateTime.Now.ToString("ss,ffff") + " 13000 ");

aRecord ar3 = aRecord.readFromStream(br, 23000-1);
Console.WriteLine(DateTime.Now.ToString("ss,ffff") + " 23000 end ");

br.Close();
sr.Close();

您的标题与优化Dictionary 有关。这取决于主要用途:阅读还是写作?如果您在字典中阅读了很多内容,最好创建一个SortedDictionary。如果你需要创建许多mor条目而不是你期望阅读的正常Dictionary会更好..

..并且有更多的收集类,但第一件事是找出真正的瓶颈。上述搜索和读取例程不会浪费时间将数据插入Dictionary,而只是丢弃它们直到找到正确的记录。我还添加了一个搜索方法,在每次点击相同位置后继续。扩展课程以满足您自己的需求非常简单。

27,2208 init

  

27,2297写

     

27,2438寻求

     

27,2438开始搜索

     完成了27,3097次。发现38

     

27,3097 0结束

     

27,3097 1结束

     

27,3457 13000 end

     

27,4037 23000结束

答案 1 :(得分:0)

您可以将数据嵌入为资源,然后使用ResourceManager的实例来检索值。

var rm = new ResourceManager(baseName, assembly);
string vendor = rm.GetString(macAddress);

要创建资源文件(无需将其键入Visual Studio),您可以创建一个可执行文件来读取源文件并从中创建.resources文件:

string path = Path.GetFullPath(Path.Combine(outputPath, "..\\MyData.resources"));

using (IResourceWriter rsxw = new ResourceWriter(path))
{
    foreach (var x ...)
    {
       rsxw.AddResource(x.name, x.value);
    }
    rsxw.Close();
}

在项目中包含此MyData.resources文件,它将作为资源进行编译。