Enregistrement d’un dictionnaire en C # – Sérialisation?

J’écris une application C # qui doit lire environ 130 000 paires (Ssortingng, Int32) au démarrage dans un dictionnaire. Les paires sont stockées dans un fichier .txt et sont donc facilement modifiables par tout le monde, ce qui est dangereux dans le contexte. Je voudrais demander s’il existe un moyen de sauvegarder ce dictionnaire afin que les informations puissent être stockées de manière raisonnable en toute sécurité, sans perte de performance au démarrage. J’ai essayé d’utiliser BinaryFormatter , mais le problème est que, bien que le programme original prenne entre 125 ms et 250 ms au démarrage pour lire les informations du txt et construire le dictionnaire, la désérialisation des fichiers binarys résultants prend jusqu’à 2 secondes, ce qui n’est pas trop lui-même, mais par rapport à la performance initiale, correspond à une diminution de la vitesse de 8 à 16 fois.

Remarque: Le chiffrement est important, mais le plus important devrait être un moyen de sauvegarder et de lire le dictionnaire à partir du disque, éventuellement à partir d’un fichier binary, sans avoir à utiliser Convert.ToInt32 sur chaque ligne, ce qui améliore les performances.

    question interessante. J’ai fait quelques tests rapides et vous avez raison – BinaryFormatter est étonnamment lent:

    • Sérialiser 130 000 entrées de dictionnaire: 547ms
    • Désérialiser 130 000 entrées de dictionnaire: 1046ms

    Lorsque je l’ai codé avec un StreamReader / StreamWriter avec des valeurs séparées par des virgules, j’ai obtenu:

    • Sérialiser 130 000 entrées de dictionnaire: 121ms
    • Désérialiser 130 000 entrées de dictionnaire: 111 ms

    Mais ensuite, j’ai juste essayé d’utiliser un BinaryWriter / BinaryReader:

    • Sérialiser 130 000 entrées de dictionnaire: 22ms
    • Désérialiser 130 000 entrées de dictionnaire: 36 ms

    Le code pour cela ressemble à ceci:

     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; } 

    Comme d’autres l’ont dit, si vous craignez que les utilisateurs falsifient le fichier, le chiffrement plutôt que le formatage binary est la voie à suivre.

    Si vous souhaitez que les données soient stockées de manière relativement sûre, vous pouvez chiffrer le contenu. Si vous ne faites que le chiffrer en tant que chaîne et le déchiffrer avant votre logique d’parsing actuelle, vous devriez être en sécurité. Et cela ne devrait pas avoir autant d’impact sur les performances.

    Voir Crypter et décrypter une chaîne pour plus d’informations.

    Le chiffrement se fait au désortingment de la gestion des clés. Et, bien sûr, même les algorithmes de cryptage / décryptage les plus rapides sont plus lents que l’absence de cryptage. Même chose avec la compression, qui n’aidera que si vous êtes lié à l’entrée / sortie.

    Si la performance est votre principale préoccupation, commencez par regarder où se trouve réellement le goulot d’étranglement. Si le coupable est vraiment l’appel Convert.ToInt32 (), j’imagine que vous pouvez stocker les bits Int32 directement et vous en tirer avec une conversion simple, ce qui devrait être plus rapide que l’parsing d’une valeur de chaîne. Pour obscurcir les chaînes, vous pouvez xor chaque octet avec une valeur fixe, qui est rapide mais qui ne fournit rien de plus qu’un obstacle rapide à un attaquant déterminé.

    Peut-être quelque chose comme:

      static void Serialize(ssortingng 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(ssortingng 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.ReadSsortingng(), reader.ReadInt32()); } return data; } } 

    Notez que cela ne fait rien sur le cryptage; c’est une préoccupation distincte. Vous pouvez également constater que l’ajout de deflate dans le mixage réduit les E / S de fichier et augmente les performances:

      static void Serialize(ssortingng 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(ssortingng 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.ReadSsortingng(), reader.ReadInt32()); } return data; } } 

    Est-il suffisamment sûr d’utiliser BinaryFormatter au lieu de stocker le contenu directement dans le fichier texte? Évidemment pas. Parce que d’autres peuvent facilement “détruire” le fichier en l’ouvrant avec le bloc-notes et en ajoutant quelque chose, même s’il ne peut voir que des caractères étranges. C’est mieux si vous le stockez dans une firebase database. Mais si vous insistez sur votre solution, vous pouvez facilement améliorer considérablement les performances en utilisant la Parallel Programming en C # 4.0 (vous pouvez facilement obtenir de nombreux exemples utiles en la recherchant sur Google). Quelque chose ressemble à ceci:

     //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); }); 

    Une autre solution alternative de Parallel est la création de plusieurs threads, la lecture / écriture dans différents fichiers sera plus rapide.

    Bien, utiliser un BinaryFormatter n’est pas vraiment un moyen sûr de stocker les paires, car vous pouvez écrire un programme très simple pour le désérialiser (après, par exemple, utiliser un réflecteur sur votre code pour obtenir le type)

    Que diriez-vous de chiffrer le txt? Avec quelque chose comme ça par exemple? (pour une performance maximale, essayez sans compression)