簡體   English   中英

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

[英]C# Serialization to file, overwrite if exists

我有以下方法(如下所示),因為您可以看到它將對象序列化為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);
        }
    }

使用帶有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文件保存在臨時文件中:

./directory/myNewObject.xml.temp

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

你可以做以下事情。 將您的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());
    }

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM