在C#中保存字典 – 序列化?

我正在编写一个C#应用程序,需要在启动时读取大约130,000(String,Int32)对到Dictionary。 这些对存储在.txt文件中,因此很容易被任何人修改,这在上下文中是危险的。 我想问一下是否有办法保存这个字典,以便可以合理安全地存储信息,而不会在启动时失去性能。 我已经尝试过使用BinaryFormatter ,但问题是原始程序在启动时需要125ms到250ms来读取txt中的信息并构建字典,反序列化生成的二进制文件需要2s,这不是太多本身但与原始性能相比,速度降低了8-16倍。

注意:加密很重要,但最重要的应该是从磁盘保存和读取字典的方法 – 可能来自二进制文件 – 而不必在每一行上使用Convert.ToInt32,从而提高性能。

有趣的问题。 我做了一些快速测试,你说得对 – BinaryFormatter的速度非常慢:

  • 序列化130,000个字典条目: 547ms
  • 反序列化130,000个字典条目: 1046ms

当我使用逗号分隔值的StreamReader / StreamWriter对其进行编码时,我得到了:

  • 序列化130,000个词典条目: 121ms
  • 反序列化130,000个字典条目: 111ms

但后来我尝试使用BinaryWriter / BinaryReader:

  • 序列化130,000个词典条目: 22ms
  • 反序列化130,000个字典条目: 36ms

代码看起来像这样:

 public void Serialize(Dictionary dictionary, Stream stream) { BinaryWriter writer = new BinaryWriter(stream); writer.Write(dictionary.Count); foreach (var kvp in dictionary) { writer.Write(kvp.Key); writer.Write(kvp.Value); } writer.Flush(); } public Dictionary Deserialize(Stream stream) { BinaryReader reader = new BinaryReader(stream); int count = reader.ReadInt32(); var dictionary = new Dictionary(count); for (int n = 0; n < count; n++) { var key = reader.ReadString(); var value = reader.ReadInt32(); dictionary.Add(key, value); } return dictionary; } 

正如其他人所说,如果你担心用户篡改文件,加密而不是二进制格式化就是前进的方向。

如果要相对安全地存储数据,可以加密内容。 如果您只是将其加密为字符串并在当前解析逻辑之前解密它,那么您应该是安全的。 而且,这不应该对性能产生太大影响。

有关详细信息,请参阅加密和解密字符串 。

加密是以密钥管理为代价的。 当然,即使是最快的加密/解密算法也比没有加密慢。 与压缩相同,只有在受I / O约束时才有用。

如果性能是您的主要考虑因素,请开始查看瓶颈实际上的位置。 如果罪魁祸首真的是Convert.ToInt32()调用,我想你可以直接存储Int32位并通过简单的转换来逃避,这应该比解析字符串值更快。 为了对字符串进行模糊处理,您可以使用一些固定值对每个字节进行xor,这很快,但只为确定的攻击者提供了一个道路爆破。

也许是这样的:

  static void Serialize(string path, IDictionary data) { using (var file = File.Create(path)) using (var writer = new BinaryWriter(file)) { writer.Write(data.Count); foreach(var pair in data) { writer.Write(pair.Key); writer.Write(pair.Value); } } } static IDictionary Deserialize(string path) { using (var file = File.OpenRead(path)) using (var reader = new BinaryReader(file)) { int count = reader.ReadInt32(); var data = new Dictionary(count); while(count-->0) { data.Add(reader.ReadString(), reader.ReadInt32()); } return data; } } 

请注意,这不会对加密做任何事情; 这是一个单独的问题。 您可能还会发现在混合中添加deflate会减少文件IO并提高性能:

  static void Serialize(string path, IDictionary data) { using (var file = File.Create(path)) using (var deflate = new DeflateStream(file, CompressionMode.Compress)) using (var writer = new BinaryWriter(deflate)) { writer.Write(data.Count); foreach(var pair in data) { writer.Write(pair.Key); writer.Write(pair.Value); } } } static IDictionary Deserialize(string path) { using (var file = File.OpenRead(path)) using (var deflate = new DeflateStream(file, CompressionMode.Decompress)) using (var reader = new BinaryReader(deflate)) { int count = reader.ReadInt32(); var data = new Dictionary(count); while(count-->0) { data.Add(reader.ReadString(), reader.ReadInt32()); } return data; } } 

使用BinaryFormatter而不是将内容直接存储在文本文件中是否足够安全? 显然不是。 因为其他人可以通过记事本打开文件并添加内容来轻松“破坏”文件,即使他只能看到奇怪的字符。 如果将它存储在数据库中会更好。 但是,如果你坚持使用C#4.0中的Parallel Programming ,那么你可以通过使用C#4.0中的Parallel Programming轻松地提高解决方案的性能(通过Google搜索可以轻松获得很多有用的示例)。 看起来像这样:

 //just an example Dictionary source = GetTheDict(); var grouped = source.GroupBy(x => { if (x.Key.First() >= 'a' && x.Key.First() <= 'z') return "File1"; else if (x.Key.First() >= 'A' && x.Key.First() <= 'Z') return "File2"; return "File3"; }); Parallel.ForEach(grouped, g => { ThreeStreamsToWriteToThreeFilesParallelly(g); }); 

Parallel另一个替代解决方案是创建多个线程,从/写入不同文件将更快。

好吧,使用BinaryFormatter实际上并不是一种存储对的安全方法,因为你可以编写一个非常简单的程序来反序列化它(比如说,在你的代码上运行reflection器以获得类型)

如何加密txt? 比如这样的东西? (为了获得最佳性能,请尝试不压缩)