21

这是一个棘手的问题。我怀疑这需要一些文件系统的高级知识才能回答。

我有一个面向 .NET 框架 4.0 的 WPF 应用程序“App1”。它有一个Settings.settings生成标准App1.exe.config文件的文件,其中存储了默认设置。当用户修改设置时,修改进入AppData\Roaming\MyCompany\App1\X.X.0.0\user.config。这都是标准的 .NET 行为。但是,有时我们会发现user.config客户机器上的文件不是应有的文件,这会导致应用程序崩溃。

问题看起来像这样:user.config如果用 XML 填充它应该是大小,但不是 XML,它只是一堆 NUL 字符。这是字符 0 一遍又一遍地重复。我们没有关于导致此文件修改的原因的信息。

在此处输入图像描述

如果我们只是删除,我们可以在客户的设备上解决这个问题,user.config因为公共语言运行时只会生成一个新的。他们将丢失对设置所做的更改,但可以再次进行更改。

但是,我在另一个带有另一个 XML 文件的 WPF 应用程序“App2”中遇到了这个问题,info.xml. 这次不同了,因为文件是由我自己的代码生成的,而不是由 CLR 生成的。共同的主题是两者都是 C# WPF 应用程序,都是 XML 文件,并且在这两种情况下,我们都完全无法在测试中重现问题。这可能与 C# 应用程序与 XML 文件或一般文件交互的方式有关吗?

我们不仅不能在我们当前的应用程序中重现问题,而且我什至无法通过编写故意生成错误的自定义代码来重现问题。我找不到导致文件被空值填充的单个 XML 序列化错误或文件访问错误。那么可能会发生什么?

App1user.config通过调用Upgrade()Save()获取和设置属性来访问。例如:

if (Settings.Default.UpgradeRequired)
{
    Settings.Default.Upgrade();
    Settings.Default.UpgradeRequired = false;
    Settings.Default.Save();
}

App2info.xml通过序列化和反序列化 XML 进行访问:

public Info Deserialize(string xmlFile)
{
    if (File.Exists(xmlFile) == false)
    {
        return null;
    }

    XmlSerializer xmlReadSerializer = new XmlSerializer(typeof(Info));

    Info overview = null;

    using (StreamReader file = new StreamReader(xmlFile))
    {
        overview = (Info)xmlReadSerializer.Deserialize(file);
        file.Close();
    }

    return overview;
}

public void Serialize(Info infoObject, string fileName)
{
    XmlSerializer writer = new XmlSerializer(typeof(Info));

    using (StreamWriter fileWrite = new StreamWriter(fileName))
    {
        writer.Serialize(fileWrite, infoObject);
        fileWrite.Close();
    }
}

我们在 Windows 7 和 Windows 10 上都遇到过这个问题。在研究这个问题时,我遇到了这篇文章,在 Windows 8.1 中遇到了同样的 XML 问题:Saved files sometime only contains NUL-characters

是否可以在我的代码中更改某些内容以防止这种情况发生,或者问题是否存在于 .NET 的行为中?

在我看来,有三种可能:

  1. CLR 正在将空字符写入 XML 文件。
  2. 文件的内存地址指针在不移动文件内容的情况下切换到另一个位置。
  3. 文件系统尝试将文件移动到另一个内存地址并且文件内容被移动但指针没有得到更新。

我觉得 2 和 3 比 1 更有可能。这就是为什么我说它可能需要高级文件系统知识。

我将非常感谢任何可能帮助我重现、修复或解决问题的信息。谢谢!

4

5 回答 5

18

众所周知,如果出现功率损耗,就会发生这种情况。这发生在扩展文件(它可以是新文件或现有文件)的缓存写入之后,并且此后不久发生断电。在这种情况下,当机器重新启动时,文件有 3 种预期的可能状态:

1)该文件根本不存在或具有其原始长度,就好像写入从未发生过一样。

2)文件具有预期的长度,就像写入发生一样,但数据为零。

3) 文件具有预期的长度和写入的正确数据。

状态 2 就是您所描述的。发生这种情况是因为当您执行缓存写入时,NTFS 最初只是相应地扩展文件大小,但保持 VDL(有效数据长度)不变。超出 VDL 的数据总是读回为零。您打算写入的数据位于文件缓存的内存中。它最终会被写入磁盘,通常在几秒钟内,然后 VDL 将在磁盘上得到高级以反映写入的数据。如果在数据写入之前或 VDL 增加之前发生断电,您将最终处于状态 2。

这很容易重现,例如通过复制文件(复制引擎使用缓存写入),然后立即拔掉计算机上的电源插头。

于 2018-10-11T02:19:20.487 回答
3

我有一个类似的问题,我能够将我的问题追溯到损坏的硬盘驱动器。

我的问题描述(所有相关信息)

  • 连接到主板 (SATA) 的磁盘:

    • SSD (系统)

    • 3 * 硬盘。

      其中一个 HDD 有一个坏块,甚至在读取磁盘结构(目录和文件列表)时也出现了问题。

  • 操作系统:Windows 7 x64

  • 文件系统(在所有磁盘上):NTFS

当系统尝试读取或写入损坏的磁盘(用户请求或自动扫描或任何其他原因)并且尝试失败时,所有写入操作(对其他磁盘的)都不正确。在系统磁盘上创建的文件(主要是其他应用程序的配置文件)被写入并且在直接检查文件内容时是有效的(可能是因为这些文件是在 RAM 中兑现的) 。

不幸的是,重新启动后,所有文件(在损坏的驱动器上写入/读取访问失败后写入)具有正确的大小,但文件的内容是“零字节” (与您的情况完全一样)

尝试排除硬件相关问题。您可以尝试检查“复制”文件(更改后)到另一台机器(上传到 web/ftp)。或者尝试将特定内容保存到固定文件。当不同的检查文件正确时,或者当固定内容文件为“空”时,原因可能是在本地机器上。尝试更改硬件组件,或重新安装系统。

于 2018-03-20T11:19:21.647 回答
2

我遇到了类似的问题,但它在服务器上。当程序写入文件时服务器重新启动,导致文件包含所有空字符并且变得无法用于写入/读取它的程序。

所以文件看起来像这样: 在此处输入图像描述

日志显示服务器重新启动: 在此处输入图像描述

损坏的文件显示它是在重新启动时最后更新的: 在此处输入图像描述

于 2018-10-02T15:55:27.160 回答
2

这种行为没有记录在案的原因,因为这发生在用户身上,但没有人能说出这种奇怪情况的起源。

这可能是 CLR 问题,尽管这不太可能发生,但如果没有为节点定义xsi:nil ,CLR 不仅会写入空字符,而且 XML 文档不能包含空字符。

无论如何,解决此问题的唯一记录方法是使用以下代码行删除损坏的文件:

try
{
     ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal);
}
catch (ConfigurationErrorsException ex)
{
    string filename = ex.Filename;
    _logger.Error(ex, "Cannot open config file");

    if (File.Exists(filename) == true)
    {
        _logger.Error("Config file {0} content:\n{1}", filename, File.ReadAllText(filename));
        File.Delete(filename);
        _logger.Error("Config file deleted");
        Properties.Settings.Default.Upgrade();
        // Properties.Settings.Default.Reload();
        // you could optionally restart the app instead
    }
    else
    {
        _logger.Error("Config file {0} does not exist", filename);
    }
}

它将使用 Properties.Settings.Default.Upgrade(); 没有空值的再次恢复 user.config。

于 2018-03-19T08:54:38.990 回答
1

我有同样的问题,序列化的 xml 文件末尾有一个额外的“NUL”字符: 在此处输入图像描述

我正在使用这样的 XMLWriter:

using (var stringWriter = new Utf8StringWriter())
        {
            using (var xmlWriter = XmlWriter.Create(stringWriter, new XmlWriterSettings { Indent = true, IndentChars = "\t", NewLineChars = "\r\n", NewLineHandling = NewLineHandling.Replace }))
            {                    
                xmlSerializer.Serialize(xmlWriter, data, nameSpaces);
                xml =  stringWriter.ToString();
                var xmlDocument = new XmlDocument();
                xmlDocument.LoadXml(xml);
                if (removeEmptyNodes)
                {
                    RemoveEmptyNodes(xmlDocument);
                }
                xml = xmlDocument.InnerXml;
            }
        }
于 2018-11-08T09:07:04.967 回答