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