我有以下方法(如下所示),因为您可以看到它将对象序列化为XML文件。我遇到的主要问题是我想让函数覆盖文件(如果存在)。 我知道如果它确实存在,我可以先删除该文件,但这也意味着我可能会在我的应用程序中引入一些错误。所以我想要一个全有或全无的覆盖方法...
这是函数,关于如何实现这一点的任何想法?
/// <summary>
/// Serializes an object to an xml file.
/// </summary>
/// <param name="obj">
/// The object to serialize.
/// </param>
/// <param name="type">
/// The class type of the object being passed.
/// </param>
/// <param name="fileName">
/// The filename where the object should be saved to.
/// </param>
/// <param name="xsltPath">
/// Pass a null if not required.
/// </param>
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);
}
}
答案 0 :(得分:14)
使用XmlWriter.Create
的重载版本,其中包含Stream
而不是字符串,并使用File.Create
创建/覆盖该文件:
using (var w = XmlWriter.Create(File.Create(fileName), settings))
...
答案 1 :(得分:4)
-
FileStream stream = File.Open(filename, FileMode.Create, FileAccess.Write, FileShare.None);
using (XmlWriter writer = XmlWriter.Create(stream))
{
...
}
答案 2 :(得分:2)
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))
答案 3 :(得分:1)
XmlWriter.Create(filename,settings)将覆盖该文件。如果你对此有例外,那么还有其他事情要发生。另见:Error creating an XmlWriter when file already exists
答案 4 :(得分:0)
备份目标文件(如果存在),如果发生错误,请写回文件。
答案 5 :(得分:0)
您可以将新的XML文件保存在临时文件中:
./目录/ myNewObject.xml.temp
然后使用File.MoveTo在myNewObject.xml中重命名myNewObject.xml.temp
答案 6 :(得分:0)
您可以执行以下操作。将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());
}
答案 7 :(得分:0)
请注意FileMode,如果使用FileMode.OpenOrCreate,它将不会删除旧文件内容,如果新内容较小,则xml的旧内容将被破坏。确保使用FileMode.Create。
这是一个扩展名,它将首先写入本地.tmp文件,如果成功,它将替换所需的文件名。我选择使用File.Copy来允许.NET。
如果您更偏执,可以在线找到一些示例,该示例说明如何为文件交换创建NTFS事务,尽管它需要外部调用。 例如https://improve.dk/utilizing-transactional-ntfs-through-dotnet/
根据失败的位置(阶段),它将尝试清除.tmp文件。
/// <summary>
/// asynchronous serializing of an object at the path specified by the FileInfo.
/// </summary>
/// <typeparam name="T">Type of the object to serialize</typeparam>
/// <param name="fi">FileInfo to the target path</param>
/// <param name="ObjectToSerialize">object to serialize</param>
/// <param name="fileShare">File sharing mode during write</param>
public static void SerializeXmlFile<T>(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;
}
}
}