2

我正在使用 .NET 4.5 在 C# 中编写应用程序。我的应用程序读取和写入硬件设备使用的二进制文件。该文件正好是 5,000,000 字节,由 100,000 个 50 字节的“块”组成。每个 50 字节的块将包含一个 ASCII 编码的字符串(可能只是一个空字符串)。设备需要文件布局,因此可以通过确定偏移量(索引 * 50 字节,然后读取/写入接下来的 50 字节)来访问任何字符串。

我的 WinForms 应用程序需要能够:

  • 从文件中加载所有 100,000 个字符串并在 UI(列表框)中显示它们
  • 添加、编辑或删除字符串
  • 以正确的格式重写二进制文件

注意事项:

  1. 二进制文件中的大量数据最初是我不想向用户显示的空字符串,但仍需要在我的数据结构中,以便我可以正确地重写文件。
  2. 在添加新字符串之前,我需要确保有可用空间来允许它(即,至少有一个 50 字节的空块)。如果没有,那么用户将需要“删除”现有字符串,以便为要添加的新字符串腾出空间。
  3. 在幕后,添加、修改和删除字符串是相同的操作。添加只是将 50 字节的空数据更改为 50 字节的字符串数据,而删除则相反。
  4. 除空字符串外,不应存储重复的字符串,因此我需要某种方法来遍历我的数据结构,以确保在添加或编辑字符串以匹配现有字符串之前字符串不存在。

所以我需要一个数据结构来保存文件中的所有数据,我正在努力在字典、列表或数组之间做出决定。鉴于上述警告,我不认为直接将任何数据结构绑定到 UI 是一个可行的解决方案。所以我认为我需要在该数据结构和列表框之间使用大量代码来实现某种伪绑定。如果是这种情况,从功能的角度来看,哪种数据结构(字典、列表、数组等)最有用,并提供最佳折衷:使用这种大小的数据集(100,000 个最多 50 个 ASCII 字符的字符串)的速度每个)?

4

4 回答 4

3

如果性能很关键,最好的方法是测试它。编写一个快速而肮脏的应用程序,以所有三种方式完成关键工作,然后将其包装在一个循环中,完成 10,000 次,看看哪个更快。

于 2012-12-11T22:42:30.150 回答
3

字典在这里似乎没有必要,因为您没有任何键来索引您的数据。
列表适用于添加/删除项目,但这显然也不是必需的。
所以我会去一个字符串数组

编辑:重新考虑存在的多个空字符串,如果空字符串与填充字符串的比率不低,我可以建议可能的优化。
我们可以使用整数数组作为映射,而不是只包含填充字符串的字典

警告:需要测试

int[] keys = new int[100];  // Just 100 to test the idea
Dictionary<int, string> data = new Dictionary<int, string>();

AddItem(keys, 32, data, "Position 32 34567890123456789012345678901234567890");
AddItem(keys, 40, data, "Position 40 34567890123456789012345678901234567890");
AddItem(keys, 10, data, "Position 10 34567890123456789012345678901234567890");
AddItem(keys, 25, data, "Position 25 34567890123456789012345678901234567890");
AddItem(keys, 99, data, "Position 99 34567890123456789012345678901234567890");
AddItem(keys, 0, data, "Postion 00 234567890123456789012345678901234567890");
AddItem(keys, 18, data, "Position 18 34567890123456789012345678901234567890");

foreach(int x in keys)
{
    if(x == 0)
        Console.WriteLine("Empty string");
    else
        Console.WriteLine(data[x]);
}

void AddItem(int[] keys, int keyPos, Dictionary<int, string> data, string message)
{
    int count = data.Count;
    data.Add(count, message);
    keys[keyPos] = count;
}
void RemoveItem(int[] keys, int keyPos, Dictionary<int, string> data)
{
    int x = keys[keyPos];
    data.Remove(x);
    keys[keyPos] = 0;
}
void UpdateItem(int[] keys, int keyPos, Dictionary<int, string> data, string message)
{
    int x = keys[keyPos];
    data[x] = message;
}
于 2012-12-11T22:43:23.737 回答
1

即使有 100,000 个条目,我认为您也不必过于担心性能。(编辑:我的意思是,在 I/O 或数据更改方面的性能。您的 GUI 绑定可能会遇到问题)

以最简单的方式对其进行编程,使您可以最轻松地更改业务逻辑和 GUI 绑定。甚至可以考虑创建您自己的类,该类简单地为您的 GUI 包装一个ListArray或其他)具有标准公共接口的隐藏此实现细节的 GUI。

一旦您的 GUI 运行并且所有 I/O 都运行良好(理想情况下,有一些不错的单元测试套件),那么您就可以开始进行基准测试/分析并找出瓶颈所在。

编辑:考虑到您的要求,这种自定义/包装的数据结构可能是理想的。它可以主动了解您数据的某些方面。例如,当它被加载/读取时,它可以检查是否有空间可用于新字符串,所以当用户去添加更多时,你已经知道是否可以。它可以维护一个HashSet使用过的唯一字符串,因此您可以很好地 O(1) 查找重复的字符串,依此类推。

于 2012-12-11T22:53:43.997 回答
0

实际上,字典是存储数据的最佳选择。键是要存储的字符串,值是它的位置。您可以通过字典的大小来跟踪您的可用空间。

对于您的列表框,您首先将字典转换为数组,然后将该数组用作列表框的后备存储。这将是您在应用程序启动时支付的一次性速度惩罚,但会大大提高您的 UI 响应速度并满足基础数据存储的其他要求。

添加/删除操作在字典上执行,该字典快速处理重复检查,如果您对底层字典进行更改而不是重建数组,您可以快速直接更新数组。

于 2013-06-24T16:46:40.967 回答