2010-10-26 23 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另一種替代的解決方案是創建多個線程,讀取/寫入到不同的文件會更快。

相關問題