什么可能导致XML文件填充空字符?
这是一个棘手的问题。 我怀疑它需要一些文件系统的高级知识才能回答。
我有一个针对.NET framework 4.0的WPF应用程序“App1”。 它有一个Settings.settings
文件,用于生成标准App1.exe.config
文件,其中存储了默认设置。 当用户修改设置时,修改将进入AppData\Roaming\MyCompany\App1\XX0.0\user.config
。 这是所有标准的.NET行为。 但是,有时,我们发现客户机器上的user.config
文件不是它应该是的,这会导致应用程序崩溃。
问题看起来像这样: user.config
大小与XML填充时的大小相同,但是它只是一堆NUL字符而不是XML。 它的字符0一遍又一遍地重复。 我们没有关于导致此文件修改的内容的信息。
如果我们只是删除user.config
,我们可以在客户的设备上修复该问题,因为公共语言运行时只会生成一个新的。 他们将失去他们对设置所做的更改,但可以再次进行更改。
但是,我在另一个WPF应用程序“App2”中遇到了这个问题,另一个XML文件是info.xml
。 这次是不同的,因为文件是由我自己的代码而不是CLR生成的。 常见的主题是两个都是C#WPF应用程序,都是XML文件,在这两种情况下,我们完全无法在测试中重现问题。 这可能与C#应用程序与XML文件或文件交互的方式有关吗?
我们不仅无法在当前的应用程序中重现该问题,而且我甚至无法通过编写有意产生错误的自定义代码来重现该问题。 我找不到单个XML序列化错误或文件访问错误导致文件填充空值。 那么可能会发生什么?
App1通过调用Upgrade()
和Save()
以及获取和设置属性来访问user.config
。 例如:
if (Settings.Default.UpgradeRequired) { Settings.Default.Upgrade(); Settings.Default.UpgradeRequired = false; Settings.Default.Save(); }
App2通过序列化和反序列化XML来访问info.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上都遇到过这个问题。在研究这个问题时,我遇到了这个post,其中在Windows 8.1中遇到了相同的XML问题: 保存的文件有时只包含NUL字符
有什么东西可以在我的代码中改变以防止这种情况,或者在.NET的行为中是否存在问题?
在我看来,有三种可能性:
- CLR正在将空字符写入XML文件。
- 文件的内存地址指针切换到另一个位置而不移动文件内容。
- 文件系统尝试将文件移动到另一个内存地址,文件内容被移动但指针不会更新。
我觉得2和3比1更可能。这就是为什么我说它可能需要先进的文件系统知识。
我非常感谢任何可能帮助我复制,修复或解决问题的信息。 谢谢!
没有记录这种行为的原因,因为这发生在用户身上,但没有人能够说出这种奇怪情况的根源。
它可能是CLR问题,虽然这是非常不可能的,但CLR不只是写空字符,如果没有为节点定义xsi:nil ,则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 Properties.Settings.Default.Upgrade();
再次没有空值。
我有类似的问题,我能够将我的问题追溯到损坏的硬盘。
我的问题描述(所有相关信息) :
-
磁盘连接到主板(SATA):
-
SSD (系统) ,
-
3 *硬盘。
其中一个HDD有坏块,甚至在读取磁盘结构(目录和文件列表)方面存在问题 。
-
-
操作系统:Windows 7 x64
-
文件系统(在所有磁盘上) :NTFS
当系统尝试读取或写入损坏的磁盘(用户请求或自动扫描或任何其他原因)并且尝试失败时,所有写入操作(到其他磁盘)都不正确。 在直接检查文件内容时,系统磁盘上创建的文件(主要是其他应用程序的配置文件)是有效的(可能是因为文件在RAM中兑现) 。
不幸的是,重启后,所有文件(在损坏的驱动器上写入/读取访问失败后写入)都具有正确的大小,但文件的内容为“零字节” (与您的情况完全相同) 。
尝试排除与硬件相关的问题。 您可以尝试将文件(更改后)“复制”到另一台计算机(上传到web / ftp) 。 或者尝试将特定内容保存到固定文件。 当不同的检查文件是正确的,或者当固定的内容文件为“空”时,原因可能是在本地机器上。 尝试更改硬件组件,或重新安装系统。
我遇到了类似的问题,但它是在服务器上。 当程序写入文件时服务器重新启动,该文件导致文件包含所有空字符,并且对于从中写入/读取的程序变得不可用。
所以文件看起来像这样:
日志显示服务器已重新启动:
损坏的文件显示它在重新启动时最后更新:
众所周知,如果出现断电,就会发生这种情况。 这是在扩展文件(可以是新文件或现有文件)的缓存写入之后发生的,此后不久就会发生断电。 在这种情况下,当机器重新启动时,该文件有3种预期的可能状态:
1)文件根本不存在或具有原始长度,就好像写入从未发生过一样。
2)文件具有预期长度,就像写入发生一样,但数据为零。
3)文件具有预期的长度和写入的正确数据。
状态2就是你所描述的。 这是因为当您执行缓存写入时,NTFS最初只是相应地扩展文件大小,但保持VDL(有效数据长度)不变。 VDL之外的数据始终读回为零。 您打算写入的数据位于文件缓存中的内存中。 它最终将被写入磁盘,通常在几秒钟内,然后VDL将在磁盘上升级以反映写入的数据。 如果在写入数据之前或VDL增加之前发生断电,您将最终处于状态2。
这很容易重现,例如通过复制文件(复制引擎使用缓存写入),然后立即拔出计算机上的电源插头。