C#Serialization to file,覆盖如果存在

我有以下方法(如下所示),因为您可以看到它将对象序列化为XML文件。 我遇到的主要问题是我想让函数覆盖文件(如果存在)。 我知道如果它确实存在,我可以先删除该文件,但这也意味着我可能会在我的应用程序中引入一些错误。 所以我想要一个全有或全无,覆盖方法……

这是函数,关于如何实现这一点的任何想法?

///  /// Serializes an object to an xml file. ///  ///  /// The object to serialize. ///  ///  /// The class type of the object being passed. ///  ///  /// The filename where the object should be saved to. ///  ///  /// Pass a null if not required. ///  public static void SerializeToXmlFile(object obj, Type type, string fileName, string xsltPath ) { var ns = new XmlSerializerNamespaces(); ns.Add(String.Empty, String.Empty); var serializer = new XmlSerializer(type); var settings = new XmlWriterSettings {Indent = true, IndentChars = "\t"}; using (var w = XmlWriter.Create(fileName,settings)) { if (!String.IsNullOrEmpty(xsltPath)) { w.WriteProcessingInstruction("xml-stylesheet", "type=\"text/xsl\" href=\"" + xsltPath + "\""); } serializer.Serialize(w, obj, ns); } } 

使用带有Stream而不是字符串的XmlWriter.Create的重载版本,并使用File.Create创建/覆盖该文件:

 using (var w = XmlWriter.Create(File.Create(fileName), settings)) ... 
  1. 使用File.Open()和FileMode.Create,FileAccess.Write和FileShare.None打开文件。
  2. 将从File.Open()返回的流传递给XmlWriter.Create()。

 FileStream stream = File.Open(filename, FileMode.Create, FileAccess.Write, FileShare.None); using (XmlWriter writer = XmlWriter.Create(stream)) { ... } 

FileStream和XMLWriter应放在using块中

 using (FileStream fs = File.Create(filename)) using (var w = XmlWriter.Create(fs, settings)) { // your code } 

我相信使用下面的代码将无法释放文件流。 因此,如果您在一个会话中运行代码两次,它将失败

 using (var w = XmlWriter.Create(File.Create(filename), settings)) 

XmlWriter.Create(filename,settings)将覆盖该文件。 如果您对此有例外,那么还有其他事情要发生。 另请参阅: 文件已存在时创建XmlWriter时出错

备份目标文件(如果存在),如果发生错误,则写回文件。

你可以做以下事情。 将xml写入StringBuilder(),然后将stringBuilder的内容写入file。

  public static void SerializeToXmlFile(object obj, Type type, string fileName, string xsltPath) { var ns = new XmlSerializerNamespaces(); ns.Add(String.Empty, String.Empty); var serializer = new XmlSerializer(type); var settings = new XmlWriterSettings { Indent = true, IndentChars = "\t" }; StringBuilder sb = new StringBuilder(); using (var w = XmlWriter.Create(sb, settings)) { if (!String.IsNullOrEmpty(xsltPath)) { w.WriteProcessingInstruction("xml-stylesheet", "type=\"text/xsl\" href=\"" + xsltPath + "\""); } serializer.Serialize(w, obj, ns); } File.WriteAllText(fileName, sb.ToString()); } 

您可以将新XML文件保存在临时文件中:

./directory/myNewObject.xml.temp

然后使用File.MoveTo在myNewObject.xml中重命名myNewObject.xml.temp

注意FileMode,如果使用FileMode.OpenOrCreate,它将不会删除旧文件内容,如果新内容小于旧内容,则xml将被破坏。 确保使用FileMode.Create。

这是一个扩展,它首先写入本地.tmp文件,如果成功,它将替换所需的文件名。 我选择使用File.Copy来允许.NET。

如果你更偏执,你可以在网上找到如何为文件交换创建NTFS事务的例子,尽管它需要外部调用。 例如https://improve.dk/utilizing-transactional-ntfs-through-dotnet/

根据它失败的位置(阶段),它将尝试清理.tmp文件。

 ///  /// asynchronous serializing of an object at the path specified by the FileInfo. ///  /// Type of the object to serialize /// FileInfo to the target path /// object to serialize /// File sharing mode during write public static void SerializeXmlFile(this FileInfo fi, T ObjectToSerialize, FileShare fileShare) //where T:IXmlSerializable { XmlSerializer serializer = new XmlSerializer(typeof(T)); var TargetFile = fi.FullName; var fiTemp = new FileInfo(fi.FullName + ".tmp"); int Stage = 0; try { try { using (StreamWriter writer = new StreamWriter(fiTemp.Open(FileMode.Create, FileAccess.Write, fileShare))) { serializer.Serialize(writer, ObjectToSerialize); } } catch (Exception e) { throw new IOException("Unable to serialize to temp file, Error: " + e.Message, e); } Stage = 1; try { fiTemp.CopyTo(TargetFile, true); Stage = 2; } catch (Exception e) { throw new IOException("Unable to serialize to final file, Error replacing from temp: " + e.Message, e); } try { fiTemp.Delete(); } catch (FileNotFoundException) { } catch (Exception e) { throw new IOException("Unable to cleanup temp file, Error: " + e.Message, e); } Stage = 3; fi.Refresh(); } catch (Exception) { throw; } finally { switch (Stage) { case 1: // temp is written case 2: // temp is copied to destination, not yet deleted { try { fiTemp.Delete(); } catch (FileNotFoundException) { } } break; } } }