C# Note4:XML序列化和反序列化(含加密解密等)
前言
在项目中,我们经常用到各种配置文件,比如xml文件、binary文件等等,这里主要根据实践经验介绍下xml文件的序列化和反序列化(毕竟最常用)。
实践背景:我要做一个用户管理功能,用户账号信息存储在xml/binary文件中,需要对其进行读写,而且为了不让用户修改,必须对其加密,当时想的有3种做法:
(1)实现读写xml配置文件,并将关键信息加密;
(2)实现读写binary配置文件,并将关键信息加密;
(3)直接对配置文件进行加密解密和读写,不管它所使用的文件格式是xml、binary或其它。
这三种做法我都实现了,不过经过最后manager的确认觉得采用第(3)种方法最好。
方法一:
(推荐:Load and save objects to XML using serialization 本方法参考其思路)
(1)在我们将对象序列化为XML之前,对象的类代码必须包含各种自定义元数据属性(例如,[XmlAttributeAttribute(DataType = " date "])告诉编译器类及其字段和/或属性可以被序列化。
using System; using System.Xml.Serialization; using System.Collections.ObjectModel; namespace XXX.GlobalTypes { /// <summary> /// Save user account information /// </summary> [Serializable] [XmlRoot("UserManagement")] public class UserAccountInfo { private readonly Collection<UserInfo> _users = new Collection<UserInfo>(); [XmlElement("UserAccountInfo")] public Collection<UserInfo> Users { get { return this._users; } } } [Serializable] public class UserInfo { [XmlElement("UserName")] public string UserName { get; set; } [XmlElement("UserPwd")] public string UserPwd { get; set; } [XmlElement("UserRole")] public ACCESS_LEVEL UserRole { get; set; } [XmlElement("Description")] public string Description { get; set; } } }
(2)封装XML序列化的类(其中作为样例,我加入了加密解密的参数tDESkey,在将数据对象保存到xml文件后进行加密,从xml文件中读取数据前先进行解密):
1 using System; 2 using System.Xml; 3 using System.Security.Cryptography; 4 using System.Security.Cryptography.Xml; 5 using System.Xml.Serialization; // For serialization of an object to an XML Document file. 6 using System.Runtime.Serialization.Formatters.Binary; // For serialization of an object to an XML Binary file. 7 using System.IO; // For reading/writing data to an XML file. 8 using System.IO.IsolatedStorage; // For accessing user isolated data. 9 10 namespace XXX.Utilities.Common 11 { 12 /// <summary> 13 /// Serialization format types. 14 /// </summary> 15 public enum SerializedFormat 16 { 17 /// <summary> 18 /// Binary serialization format. 19 /// </summary> 20 Binary, 21 22 /// <summary> 23 /// Document serialization format. 24 /// </summary> 25 Document 26 } 27 28 29 /// <summary> 30 /// Facade to XML serialization and deserialization of strongly typed objects to/from an XML file. 31 /// 32 /// References: XML Serialization at http://samples.gotdotnet.com/: 33 /// http://samples.gotdotnet.com/QuickStart/howto/default.aspx?url=/quickstart/howto/doc/xmlserialization/rwobjfromxml.aspx 34 /// </summary> 35 public static class ObjectXMLSerializer<T> where T : class // Specify that T must be a class. 36 { 37 #region Load methods 38 39 /// <summary> 40 /// Loads an object from an XML file in Document format. 41 /// </summary> 42 /// <example> 43 /// <code> 44 /// serializableObject = ObjectXMLSerializer<SerializableObject>.Load(@"C:\XMLObjects.xml"); 45 /// </code> 46 /// </example> 47 /// <param name="path">Path of the file to load the object from.</param> 48 /// <returns>Object loaded from an XML file in Document format.</returns> 49 public static T Load(string path, TripleDESCryptoServiceProvider tDESkey) 50 { 51 T serializableObject = LoadFromDocumentFormat(null, path, null, tDESkey); 52 return serializableObject; 53 } 54 55 /// <summary> 56 /// Loads an object from an XML file using a specified serialized format. 57 /// </summary> 58 /// <example> 59 /// <code> 60 /// serializableObject = ObjectXMLSerializer<SerializableObject>.Load(@"C:\XMLObjects.xml", SerializedFormat.Binary); 61 /// </code> 62 /// </example> 63 /// <param name="path">Path of the file to load the object from.</param> 64 /// <param name="serializedFormat">XML serialized format used to load the object.</param> 65 /// <returns>Object loaded from an XML file using the specified serialized format.</returns> 66 public static T Load(string path, SerializedFormat serializedFormat, TripleDESCryptoServiceProvider tDESkey) 67 { 68 T serializableObject = null; 69 70 switch (serializedFormat) 71 { 72 case SerializedFormat.Binary: 73 serializableObject = LoadFromBinaryFormat(path, null); 74 break; 75 76 case SerializedFormat.Document: 77 default: 78 serializableObject = LoadFromDocumentFormat(null, path, null, tDESkey); 79 break; 80 } 81 82 return serializableObject; 83 } 84 85 /// <summary> 86 /// Loads an object from an XML file in Document format, supplying extra data types to enable deserialization of custom types within the object. 87 /// </summary> 88 /// <example> 89 /// <code> 90 /// serializableObject = ObjectXMLSerializer<SerializableObject>.Load(@"C:\XMLObjects.xml", new Type[] { typeof(MyCustomType) }); 91 /// </code> 92 /// </example> 93 /// <param name="path">Path of the file to load the object from.</param> 94 /// <param name="extraTypes">Extra data types to enable deserialization of custom types within the object.</param> 95 /// <returns>Object loaded from an XML file in Document format.</returns> 96 public static T Load(string path, System.Type[] extraTypes, TripleDESCryptoServiceProvider tDESkey) 97 { 98 T serializableObject = LoadFromDocumentFormat(extraTypes, path, null, tDESkey); 99 return serializableObject; 100 } 101 102 /// <summary> 103 /// Loads an object from an XML file in Document format, located in a specified isolated storage area. 104 /// </summary> 105 /// <example> 106 /// <code> 107 /// serializableObject = ObjectXMLSerializer<SerializableObject>.Load("XMLObjects.xml", IsolatedStorageFile.GetUserStoreForAssembly()); 108 /// </code> 109 /// </example> 110 /// <param name="fileName">Name of the file in the isolated storage area to load the object from.</param> 111 /// <param name="isolatedStorageDirectory">Isolated storage area directory containing the XML file to load the object from.</param> 112 /// <returns>Object loaded from an XML file in Document format located in a specified isolated storage area.</returns> 113 public static T Load(string fileName, IsolatedStorageFile isolatedStorageDirectory, TripleDESCryptoServiceProvider tDESkey) 114 { 115 T serializableObject = LoadFromDocumentFormat(null, fileName, isolatedStorageDirectory, tDESkey); 116 return serializableObject; 117 } 118 119 /// <summary> 120 /// Loads an object from an XML file located in a specified isolated storage area, using a specified serialized format. 121 /// </summary> 122 /// <example> 123 /// <code> 124 /// serializableObject = ObjectXMLSerializer<SerializableObject>.Load("XMLObjects.xml", IsolatedStorageFile.GetUserStoreForAssembly(), SerializedFormat.Binary); 125 /// </code> 126 /// </example> 127 /// <param name="fileName">Name of the file in the isolated storage area to load the object from.</param> 128 /// <param name="isolatedStorageDirectory">Isolated storage area directory containing the XML file to load the object from.</param> 129 /// <param name="serializedFormat">XML serialized format used to load the object.</param> 130 /// <returns>Object loaded from an XML file located in a specified isolated storage area, using a specified serialized format.</returns> 131 public static T Load(string fileName, IsolatedStorageFile isolatedStorageDirectory, SerializedFormat serializedFormat, TripleDESCryptoServiceProvider tDESkey) 132 { 133 T serializableObject = null; 134 135 switch (serializedFormat) 136 { 137 case SerializedFormat.Binary: 138 serializableObject = LoadFromBinaryFormat(fileName, isolatedStorageDirectory); 139 break; 140 141 case SerializedFormat.Document: 142 default: 143 serializableObject = LoadFromDocumentFormat(null, fileName, isolatedStorageDirectory, tDESkey); 144 break; 145 } 146 147 return serializableObject; 148 } 149 150 /// <summary> 151 /// Loads an object from an XML file in Document format, located in a specified isolated storage area, and supplying extra data types to enable deserialization of custom types within the object. 152 /// </summary> 153 /// <example> 154 /// <code> 155 /// serializableObject = ObjectXMLSerializer<SerializableObject>.Load("XMLObjects.xml", IsolatedStorageFile.GetUserStoreForAssembly(), new Type[] { typeof(MyCustomType) }); 156 /// </code> 157 /// </example> 158 /// <param name="fileName">Name of the file in the isolated storage area to load the object from.</param> 159 /// <param name="isolatedStorageDirectory">Isolated storage area directory containing the XML file to load the object from.</param> 160 /// <param name="extraTypes">Extra data types to enable deserialization of custom types within the object.</param> 161 /// <returns>Object loaded from an XML file located in a specified isolated storage area, using a specified serialized format.</returns> 162 public static T Load(string fileName, IsolatedStorageFile isolatedStorageDirectory, System.Type[] extraTypes, TripleDESCryptoServiceProvider tDESkey) 163 { 164 T serializableObject = LoadFromDocumentFormat(null, fileName, isolatedStorageDirectory, tDESkey); 165 return serializableObject; 166 } 167 168 #endregion 169 170 #region Save methods 171 172 /// <summary> 173 /// Saves an object to an XML file in Document format. 174 /// </summary> 175 /// <example> 176 /// <code> 177 /// SerializableObject serializableObject = new SerializableObject(); 178 /// 179 /// ObjectXMLSerializer<SerializableObject>.Save(serializableObject, @"C:\XMLObjects.xml"); 180 /// </code> 181 /// </example> 182 /// <param name="serializableObject">Serializable object to be saved to file.</param> 183 /// <param name="path">Path of the file to save the object to.</param> 184 public static void Save(T serializableObject, string path, TripleDESCryptoServiceProvider tDESkey) 185 { 186 SaveToDocumentFormat(serializableObject, null, path, null, tDESkey); 187 } 188 189 /// <summary> 190 /// Saves an object to an XML file using a specified serialized format. 191 /// </summary> 192 /// <example> 193 /// <code> 194 /// SerializableObject serializableObject = new SerializableObject(); 195 /// 196 /// ObjectXMLSerializer<SerializableObject>.Save(serializableObject, @"C:\XMLObjects.xml", SerializedFormat.Binary); 197 /// </code> 198 /// </example> 199 /// <param name="serializableObject">Serializable object to be saved to file.</param> 200 /// <param name="path">Path of the file to save the object to.</param> 201 /// <param name="serializedFormat">XML serialized format used to save the object.</param> 202 public static void Save(T serializableObject, string path, SerializedFormat serializedFormat, TripleDESCryptoServiceProvider tDESkey) 203 { 204 switch (serializedFormat) 205 { 206 case SerializedFormat.Binary: 207 SaveToBinaryFormat(serializableObject, path, null); 208 break; 209 210 case SerializedFormat.Document: 211 default: 212 SaveToDocumentFormat(serializableObject, null, path, null, tDESkey); 213 break; 214 } 215 } 216 217 /// <summary> 218 /// Saves an object to an XML file in Document format, supplying extra data types to enable serialization of custom types within the object. 219 /// </summary> 220 /// <example> 221 /// <code> 222 /// SerializableObject serializableObject = new SerializableObject(); 223 /// 224 /// ObjectXMLSerializer<SerializableObject>.Save(serializableObject, @"C:\XMLObjects.xml", new Type[] { typeof(MyCustomType) }); 225 /// </code> 226 /// </example> 227 /// <param name="serializableObject">Serializable object to be saved to file.</param> 228 /// <param name="path">Path of the file to save the object to.</param> 229 /// <param name="extraTypes">Extra data types to enable serialization of custom types within the object.</param> 230 public static void Save(T serializableObject, string path, System.Type[] extraTypes, TripleDESCryptoServiceProvider tDESkey) 231 { 232 SaveToDocumentFormat(serializableObject, extraTypes, path, null, tDESkey); 233 } 234 235 /// <summary> 236 /// Saves an object to an XML file in Document format, located in a specified isolated storage area. 237 /// </summary> 238 /// <example> 239 /// <code> 240 /// SerializableObject serializableObject = new SerializableObject(); 241 /// 242 /// ObjectXMLSerializer<SerializableObject>.Save(serializableObject, "XMLObjects.xml", IsolatedStorageFile.GetUserStoreForAssembly()); 243 /// </code> 244 /// </example> 245 /// <param name="serializableObject">Serializable object to be saved to file.</param> 246 /// <param name="fileName">Name of the file in the isolated storage area to save the object to.</param> 247 /// <param name="isolatedStorageDirectory">Isolated storage area directory containing the XML file to save the object to.</param> 248 public static void Save(T serializableObject, string fileName, IsolatedStorageFile isolatedStorageDirectory, TripleDESCryptoServiceProvider tDESkey) 249 { 250 SaveToDocumentFormat(serializableObject, null, fileName, isolatedStorageDirectory, tDESkey); 251 } 252 253 /// <summary> 254 /// Saves an object to an XML file located in a specified isolated storage area, using a specified serialized format. 255 /// </summary> 256 /// <example> 257 /// <code> 258 /// SerializableObject serializableObject = new SerializableObject(); 259 /// 260 /// ObjectXMLSerializer<SerializableObject>.Save(serializableObject, "XMLObjects.xml", IsolatedStorageFile.GetUserStoreForAssembly(), SerializedFormat.Binary); 261 /// </code> 262 /// </example> 263 /// <param name="serializableObject">Serializable object to be saved to file.</param> 264 /// <param name="fileName">Name of the file in the isolated storage area to save the object to.</param> 265 /// <param name="isolatedStorageDirectory">Isolated storage area directory containing the XML file to save the object to.</param> 266 /// <param name="serializedFormat">XML serialized format used to save the object.</param> 267 public static void Save(T serializableObject, string fileName, IsolatedStorageFile isolatedStorageDirectory, SerializedFormat serializedFormat, TripleDESCryptoServiceProvider tDESkey) 268 { 269 switch (serializedFormat) 270 { 271 case SerializedFormat.Binary: 272 SaveToBinaryFormat(serializableObject, fileName, isolatedStorageDirectory); 273 break; 274 275 case SerializedFormat.Document: 276 default: 277 SaveToDocumentFormat(serializableObject, null, fileName, isolatedStorageDirectory, tDESkey); 278 break; 279 } 280 } 281 282 /// <summary> 283 /// Saves an object to an XML file in Document format, located in a specified isolated storage area, and supplying extra data types to enable serialization of custom types within the object. 284 /// </summary> 285 /// <example> 286 /// <code> 287 /// SerializableObject serializableObject = new SerializableObject(); 288 /// 289 /// ObjectXMLSerializer<SerializableObject>.Save(serializableObject, "XMLObjects.xml", IsolatedStorageFile.GetUserStoreForAssembly(), new Type[] { typeof(MyCustomType) }); 290 /// </code> 291 /// </example> 292 /// <param name="serializableObject">Serializable object to be saved to file.</param> 293 /// <param name="fileName">Name of the file in the isolated storage area to save the object to.</param> 294 /// <param name="isolatedStorageDirectory">Isolated storage area directory containing the XML file to save the object to.</param> 295 /// <param name="extraTypes">Extra data types to enable serialization of custom types within the object.</param> 296 public static void Save(T serializableObject, string fileName, IsolatedStorageFile isolatedStorageDirectory, System.Type[] extraTypes, TripleDESCryptoServiceProvider tDESkey) 297 { 298 SaveToDocumentFormat(serializableObject, null, fileName, isolatedStorageDirectory, tDESkey); 299 } 300 301 #endregion 302 303 #region Private 304 305 private static FileStream CreateFileStream(IsolatedStorageFile isolatedStorageFolder, string path) 306 { 307 FileStream fileStream = null; 308 309 if (isolatedStorageFolder == null) 310 fileStream = new FileStream(path, FileMode.OpenOrCreate); 311 else 312 fileStream = new IsolatedStorageFileStream(path, FileMode.OpenOrCreate, isolatedStorageFolder); 313 314 return fileStream; 315 } 316 317 private static T LoadFromBinaryFormat(string path, IsolatedStorageFile isolatedStorageFolder) 318 { 319 T serializableObject = null; 320 321 using (FileStream fileStream = CreateFileStream(isolatedStorageFolder, path)) 322 { 323 BinaryFormatter binaryFormatter = new BinaryFormatter(); 324 serializableObject = binaryFormatter.Deserialize(fileStream) as T; 325 } 326 327 return serializableObject; 328 } 329 330 private static T LoadFromDocumentFormat(System.Type[] extraTypes, string path, IsolatedStorageFile isolatedStorageFolder, TripleDESCryptoServiceProvider tDESkey) 331 { 332 XmlDocument xmlDoc = new XmlDocument(); 333 try 334 { 335 xmlDoc.PreserveWhitespace = true; 336 337 xmlDoc.Load(path); 338 } 339 catch (Exception e) 340 { 341 Console.WriteLine(e.Message); 342 } 343 344 // Decrypt the "UserManagement" element. 345 EncryptXml.Decrypt(xmlDoc, tDESkey); 346 xmlDoc.Save(path); 347 348 T serializableObject = null; 349 350 using (TextReader textReader = CreateTextReader(isolatedStorageFolder, path)) 351 { 352 XmlSerializer xmlSerializer = CreateXmlSerializer(extraTypes); 353 serializableObject = xmlSerializer.Deserialize(textReader) as T; 354 } 355 356 EncryptXml.Encrypt(xmlDoc, "UserManagement", tDESkey); 357 xmlDoc.Save(path); 358 359 return serializableObject; 360 } 361 362 private static TextReader CreateTextReader(IsolatedStorageFile isolatedStorageFolder, string path) 363 { 364 TextReader textReader = null; 365 366 if (isolatedStorageFolder == null) 367 textReader = new StreamReader(path); 368 else 369 textReader = new StreamReader(new IsolatedStorageFileStream(path, FileMode.Open, isolatedStorageFolder)); 370 371 return textReader; 372 } 373 374 private static TextWriter CreateTextWriter(IsolatedStorageFile isolatedStorageFolder, string path) 375 { 376 TextWriter textWriter = null; 377 378 if (isolatedStorageFolder == null) 379 textWriter = new StreamWriter(path); 380 else 381 textWriter = new StreamWriter(new IsolatedStorageFileStream(path, FileMode.OpenOrCreate, isolatedStorageFolder)); 382 383 return textWriter; 384 } 385 386 private static XmlSerializer CreateXmlSerializer(System.Type[] extraTypes) 387 { 388 Type ObjectType = typeof(T); 389 390 XmlSerializer xmlSerializer = null; 391 392 if (extraTypes != null) 393 xmlSerializer = new XmlSerializer(ObjectType, extraTypes); 394 else 395 xmlSerializer = new XmlSerializer(ObjectType); 396 397 return xmlSerializer; 398 } 399 400 private static void SaveToDocumentFormat(T serializableObject, System.Type[] extraTypes, string path, IsolatedStorageFile isolatedStorageFolder, TripleDESCryptoServiceProvider tDESkey) 401 { 402 using (TextWriter textWriter = CreateTextWriter(isolatedStorageFolder, path)) 403 { 404 XmlSerializer xmlSerializer = CreateXmlSerializer(extraTypes); 405 xmlSerializer.Serialize(textWriter, serializableObject); 406 407 textWriter.Close(); 408 409 XmlDocument xmlDoc = new XmlDocument(); 410 try 411 { 412 xmlDoc.PreserveWhitespace = true; 413 414 xmlDoc.Load(path); 415 } 416 catch (Exception e) 417 { 418 Console.WriteLine(e.Message); 419 } 420 421 EncryptXml.Encrypt(xmlDoc, "UserManagement", tDESkey); 422 423 xmlDoc.Save(path); 424 } 425 } 426 427 private static void SaveToBinaryFormat(T serializableObject, string path, IsolatedStorageFile isolatedStorageFolder) 428 { 429 using (FileStream fileStream = CreateFileStream(isolatedStorageFolder, path)) 430 { 431 BinaryFormatter binaryFormatter = new BinaryFormatter(); 432 binaryFormatter.Serialize(fileStream, serializableObject); 433 } 434 } 435 436 437 #endregion 438 } 439 }
(3)Saving an object to an XML file/Loading an object from an XML file
// Load the userManagement object from the XML file using our UserAccountInfo class... UserAccountInfo userManagement =ObjectXMLSerializer<UserAccountInfo>.Load(path, tDESkey); // Load the userManagement object from the XML file using our userManagement class... ObjectXMLSerializer<UserAccountInfo>.Save(usermanagement, XML_FILE_NAME, tDESkey);
方法二:
其实,要想仅仅实现xml的序列化和反序列化还是很简单的,作为常用的类,可以很简单地将其实现为公共类:
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml; using System.Xml.Serialization; namespace XXX.Common { public static class XmlHelper { public static object DeserializeObject<T>(string filePath) { try { var xs = new XmlSerializer(typeof(T)); using (var fs = new FileStream(filePath, FileMode.Open)) { var reader = XmlReader.Create(fs); return xs.Deserialize(reader); } } catch (Exception exp) { throw new XmlException($"Failed in XML Deserialization {filePath}", exp); } } public static void SerializeObject<T>(string filePath, T o) { try { var x = new XmlSerializer(typeof(T)); using (var fs = new FileStream(filePath, FileMode.Create)) { var writer = XmlWriter.Create(fs); x.Serialize(writer, o); } } catch (Exception exp) { throw new XmlException($"Failed in XML Serialization {filePath}", exp); } } } }
另可参考文章:
1.XML序列化和反序列化
朱颜辞镜花辞树,敏捷开发靠得住!