2010-10-26 24 views
17

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

注:加密是很重要的,但最重要的应该是一种保存和从磁盘读取字典 - 可能从二进制文件 - 无需使用Convert.ToInt32在每一行,从而提高性能。

+0

比tp慢8-16倍什么,你现在在用什么?如果BinaryFormatter不是最快的,我会感到惊讶。 – Aliostad 2010-10-26 08:36:00

+0

我正在使用StreamReader的ReadLine()方法从.txt文件读取字符串,并使用Convert.ToInt32作为整数。这两项操作中的每一项在启动时都会完成约131,000次。 – Miguel 2010-10-26 08:37:39

回答

26

有趣的问题。我做了一些快速测试,你是对的 - BinaryFormatter的是慢得出奇:

  • 序列化130000词典条目:547ms
  • 反序列化130000个词典条目:1046ms

当我编码它与一个StreamReader/StreamWriter与逗号分隔值我得到:

  • 个序列化130000词典条目:121ms
  • 反序列化130000个词典条目:111ms

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

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

操作的代码如下所示:

public void Serialize(Dictionary<string, int> 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<string, int> Deserialize(Stream stream) 
{ 
    BinaryReader reader = new BinaryReader(stream); 
    int count = reader.ReadInt32(); 
    var dictionary = new Dictionary<string,int>(count); 
    for (int n = 0; n < count; n++) 
    { 
     var key = reader.ReadString(); 
     var value = reader.ReadInt32(); 
     dictionary.Add(key, value); 
    } 
    return dictionary;     
} 

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

+0

非常感谢你的建议! – Miguel 2010-10-26 10:09:12

+0

你是怎么用BinaryReader/BinaryWriter得到这样的区别的?我使用FileReader/FileWriter和BinaryReader/BinaryWriter获得大致相同的时间... – Miguel 2010-10-26 12:01:47

+1

@Miguel - 这是我的单元测试文件:http://pastie.org/1249910 - 可能是因为我的StreamReader/StreamWriter代码不是和你一样高效 – 2010-10-26 12:37:41

1

好,使用BinaryFormatter的是不是真的来存储对安全的方式,你可以写一个非常简单的程序来反序列化(之后,也就是说,在你的代码运行的反射器,以获得式)

如何加密txt? 例如this? (为了获得最大性能,请尝试不压缩)

+0

非常感谢您的建议。对使用加密的性能有什么影响?而且,如果我理解的很好,那也是不安全的,因为任何用户都可以解压缩它,更改.txt文件并将其再压缩一次,对吧? – Miguel 2010-10-26 08:39:59

+1

我不知道,你应该测试你的情况。也注意到彼得的回答,可能是一个更好的想法加密(我链接到一个压缩库,也可以加密) – 2010-10-26 08:42:01

+0

@Miguel - 请注意,当你将压缩和加密结合起来时,你的性能影响会更低因为你的IO会更低。正如@ ohadsc所说,试试看看它给了你什么。 – 2010-10-26 09:42:38

3

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

查看Encrypt and decrypt a string了解更多信息。

3

加密是以密钥管理为代价的。当然,即使是最快的加密/解密算法也比完全不加密慢。与压缩一样,只有在I/O绑定时才会有所帮助。

如果性能是您主要关心的问题,请开始考虑瓶颈实际存在的位置。如果罪魁祸首真的是Convert.ToInt32()调用,我想你可以直接存储Int32位,并通过一个简单的强制类型转换,这应该比解析一个字符串值更快。为了混淆字符串,你可以用一些固定的值对每个字节进行异或,这很快,但是对于一个确定的攻击者来说,它只能提供一个roadbump。

1

也许是这样的:

static void Serialize(string path, IDictionary<string, int> 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<string,int> Deserialize(string path) 
    { 
     using (var file = File.OpenRead(path)) 
     using (var reader = new BinaryReader(file)) 
     { 
      int count = reader.ReadInt32(); 
      var data = new Dictionary<string, int>(count); 
      while(count-->0) { 
       data.Add(reader.ReadString(), reader.ReadInt32()); 
      } 
      return data; 
     } 
    } 

注意,这并不做任何事情再次加密;这是一个单独的问题。您可能还会发现,添加缩小到混合减少文件IO和提高性能:

static void Serialize(string path, IDictionary<string, int> 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<string,int> 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<string, int>(count); 
      while(count-->0) { 
       data.Add(reader.ReadString(), reader.ReadInt32()); 
      } 
      return data; 
     } 
    } 
1

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

//just an example 
Dictionary<string, int> 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另一种替代的解决方案是创建多个线程,读取/写入到不同的文件会更快。

相关问题