为什么我的文件有时会在读取或写入文件的过程中消失?
Why does my file sometimes disappear in the process of reading from it or writing to it?
我有一个应用程序可以读取文本文件以确定应生成哪些报告。它在大多数时间都可以正常工作,但偶尔,程序会删除它读取 from/writes 的其中一个文本文件。然后抛出异常(“找不到文件”)并且进度停止。
这是一些相关的代码。
首先,从文件中读取:
List<String> delPerfRecords = ReadFileContents(DelPerfFile);
. . .
private static List<String> ReadFileContents(string fileName)
{
List<String> fileContents = new List<string>();
try
{
fileContents = File.ReadAllLines(fileName).ToList();
}
catch (Exception ex)
{
RoboReporterConstsAndUtils.HandleException(ex);
}
return fileContents;
}
然后,写入文件 -- 它会将该文件中的 record/line 标记为已处理,以便下次检查该文件时不会重新生成相同的报告:
MarkAsProcessed(DelPerfFile, qrRecord);
. . .
private static void MarkAsProcessed(string fileToUpdate, string
qrRecord)
{
try
{
var fileContents = File.ReadAllLines(fileToUpdate).ToList();
for (int i = 0; i < fileContents.Count; i++)
{
if (fileContents[i] == qrRecord)
{
fileContents[i] = string.Format("{0}{1} {2}"
qrRecord, RoboReporterConstsAndUtils.COMPLETED_FLAG, DateTime.Now);
}
}
// Will this automatically overwrite the existing?
File.Delete(fileToUpdate);
File.WriteAllLines(fileToUpdate, fileContents);
}
catch (Exception ex)
{
RoboReporterConstsAndUtils.HandleException(ex);
}
}
所以我确实删除了文件,但立即替换了它:
File.Delete(fileToUpdate);
File.WriteAllLines(fileToUpdate, fileContents);
正在读取的文件内容如下:
Opas,20170110,20161127,20161231-COMPLETED 1/10/2017 12:33:27 AM
Opas,20170209,20170101,20170128-COMPLETED 2/9/2017 11:26:04 AM
Opas,20170309,20170129,20170225-COMPLETED
Opas,20170409,20170226,20170401
如果“-COMPLETED”出现在 record/row/line 的末尾,它会被忽略 - 不会被处理。
此外,如果第二个元素(在索引 1 处)是未来的日期,则不会处理(尚未)。
因此,对于上面显示的这些示例,前三个已经完成,随后将被忽略。第四个要到2017年4月9日或之后才会执行(届时会调取最后两个日期数据范围内的数据)。
为什么文件有时会被删除?我能做些什么来防止它发生?
如果有帮助,在更多上下文中,逻辑是这样的:
internal static string GenerateAndSaveDelPerfReports()
{
string allUnitsProcessed = String.Empty;
bool success = false;
try
{
List<String> delPerfRecords = ReadFileContents(DelPerfFile);
List<QueuedReports> qrList = new List<QueuedReports>();
foreach (string qrRecord in delPerfRecords)
{
var qr = ConvertCRVRecordToQueuedReport(qrRecord);
// Rows that have already been processed return null
if (null == qr) continue;
// If the report has not yet been run, and it is due, add i
to the list
if (qr.DateToGenerate <= DateTime.Today)
{
var unit = qr.Unit;
qrList.Add(qr);
MarkAsProcessed(DelPerfFile, qrRecord);
if (String.IsNullOrWhiteSpace(allUnitsProcessed))
{
allUnitsProcessed = unit;
}
else if (!allUnitsProcessed.Contains(unit))
{
allUnitsProcessed = allUnitsProcessed + " and "
unit;
}
}
}
foreach (QueuedReports qrs in qrList)
{
GenerateAndSaveDelPerfReport(qrs);
success = true;
}
}
catch
{
success = false;
}
if (success)
{
return String.Format("Delivery Performance report[s] generate
for {0} by RoboReporter2017", allUnitsProcessed);
}
return String.Empty;
}
我如何固定此代码以防止文件被定期丢弃?
更新
我无法真正测试这个,因为这个问题很少发生,但我想知道在 File.Delete() 和 File.WriteAllLines() 之间添加一个“暂停”是否可以解决有问题吗?
更新 2
我不确定我的问题的答案是什么,所以我不会添加这个作为答案,但我的猜测是 File.Delete() 和 File.WriteAllLines( ) 之间的距离太近,因此删除有时会同时发生在文件的旧副本和新副本上。
如果是这样,两次调用之间的暂停可能已经解决了 99.42% 的问题,但根据我发现的 here,似乎 File.Delete() 是 redundant/superfluous 无论如何,所以我用注释掉的 File.Delete() 进行了测试,它工作正常;所以,我现在只是在没有那个偶尔有问题的电话。我希望这能解决问题。
// Will this automatically overwrite the existing?
File.Delete(fileToUpdate);
File.WriteAllLines(fileToUpdate, fileContents);
我会简单地向 WriteAllLines()
添加一个额外的参数(默认为 false
)来告诉函数以覆盖模式打开文件,而不是调用 File.Delete()
就这样吧。
您当前是否检查打开文件的 return 值?
Update:好的,看起来 WriteAllLines()
是一个 .Net Framework 函数,因此无法更改,所以我删除了这个答案。但是现在这显示在评论中,作为另一个论坛上的建议解决方案:
"just use something like File.WriteAllText where if the file exists,
the data is just overwritten, if the file does not exist it will be
created."
这正是我的意思(虽然认为 WriteAllLines()
是用户定义的函数),因为我过去也遇到过类似的问题。
所以,这样的解决方案可以解决一些棘手的问题(而不是 deleting/fast 重新打开,只是覆盖文件)- OS 的工作也更少,可能 file/disk碎片化。
我有一个应用程序可以读取文本文件以确定应生成哪些报告。它在大多数时间都可以正常工作,但偶尔,程序会删除它读取 from/writes 的其中一个文本文件。然后抛出异常(“找不到文件”)并且进度停止。
这是一些相关的代码。
首先,从文件中读取:
List<String> delPerfRecords = ReadFileContents(DelPerfFile);
. . .
private static List<String> ReadFileContents(string fileName)
{
List<String> fileContents = new List<string>();
try
{
fileContents = File.ReadAllLines(fileName).ToList();
}
catch (Exception ex)
{
RoboReporterConstsAndUtils.HandleException(ex);
}
return fileContents;
}
然后,写入文件 -- 它会将该文件中的 record/line 标记为已处理,以便下次检查该文件时不会重新生成相同的报告:
MarkAsProcessed(DelPerfFile, qrRecord);
. . .
private static void MarkAsProcessed(string fileToUpdate, string
qrRecord)
{
try
{
var fileContents = File.ReadAllLines(fileToUpdate).ToList();
for (int i = 0; i < fileContents.Count; i++)
{
if (fileContents[i] == qrRecord)
{
fileContents[i] = string.Format("{0}{1} {2}"
qrRecord, RoboReporterConstsAndUtils.COMPLETED_FLAG, DateTime.Now);
}
}
// Will this automatically overwrite the existing?
File.Delete(fileToUpdate);
File.WriteAllLines(fileToUpdate, fileContents);
}
catch (Exception ex)
{
RoboReporterConstsAndUtils.HandleException(ex);
}
}
所以我确实删除了文件,但立即替换了它:
File.Delete(fileToUpdate);
File.WriteAllLines(fileToUpdate, fileContents);
正在读取的文件内容如下:
Opas,20170110,20161127,20161231-COMPLETED 1/10/2017 12:33:27 AM
Opas,20170209,20170101,20170128-COMPLETED 2/9/2017 11:26:04 AM
Opas,20170309,20170129,20170225-COMPLETED
Opas,20170409,20170226,20170401
如果“-COMPLETED”出现在 record/row/line 的末尾,它会被忽略 - 不会被处理。
此外,如果第二个元素(在索引 1 处)是未来的日期,则不会处理(尚未)。
因此,对于上面显示的这些示例,前三个已经完成,随后将被忽略。第四个要到2017年4月9日或之后才会执行(届时会调取最后两个日期数据范围内的数据)。
为什么文件有时会被删除?我能做些什么来防止它发生?
如果有帮助,在更多上下文中,逻辑是这样的:
internal static string GenerateAndSaveDelPerfReports()
{
string allUnitsProcessed = String.Empty;
bool success = false;
try
{
List<String> delPerfRecords = ReadFileContents(DelPerfFile);
List<QueuedReports> qrList = new List<QueuedReports>();
foreach (string qrRecord in delPerfRecords)
{
var qr = ConvertCRVRecordToQueuedReport(qrRecord);
// Rows that have already been processed return null
if (null == qr) continue;
// If the report has not yet been run, and it is due, add i
to the list
if (qr.DateToGenerate <= DateTime.Today)
{
var unit = qr.Unit;
qrList.Add(qr);
MarkAsProcessed(DelPerfFile, qrRecord);
if (String.IsNullOrWhiteSpace(allUnitsProcessed))
{
allUnitsProcessed = unit;
}
else if (!allUnitsProcessed.Contains(unit))
{
allUnitsProcessed = allUnitsProcessed + " and "
unit;
}
}
}
foreach (QueuedReports qrs in qrList)
{
GenerateAndSaveDelPerfReport(qrs);
success = true;
}
}
catch
{
success = false;
}
if (success)
{
return String.Format("Delivery Performance report[s] generate
for {0} by RoboReporter2017", allUnitsProcessed);
}
return String.Empty;
}
我如何固定此代码以防止文件被定期丢弃?
更新
我无法真正测试这个,因为这个问题很少发生,但我想知道在 File.Delete() 和 File.WriteAllLines() 之间添加一个“暂停”是否可以解决有问题吗?
更新 2
我不确定我的问题的答案是什么,所以我不会添加这个作为答案,但我的猜测是 File.Delete() 和 File.WriteAllLines( ) 之间的距离太近,因此删除有时会同时发生在文件的旧副本和新副本上。
如果是这样,两次调用之间的暂停可能已经解决了 99.42% 的问题,但根据我发现的 here,似乎 File.Delete() 是 redundant/superfluous 无论如何,所以我用注释掉的 File.Delete() 进行了测试,它工作正常;所以,我现在只是在没有那个偶尔有问题的电话。我希望这能解决问题。
// Will this automatically overwrite the existing?
File.Delete(fileToUpdate);
File.WriteAllLines(fileToUpdate, fileContents);
我会简单地向 WriteAllLines()
添加一个额外的参数(默认为 false
)来告诉函数以覆盖模式打开文件,而不是调用 File.Delete()
就这样吧。
您当前是否检查打开文件的 return 值?
Update:好的,看起来 WriteAllLines()
是一个 .Net Framework 函数,因此无法更改,所以我删除了这个答案。但是现在这显示在评论中,作为另一个论坛上的建议解决方案:
"just use something like File.WriteAllText where if the file exists, the data is just overwritten, if the file does not exist it will be created."
这正是我的意思(虽然认为 WriteAllLines()
是用户定义的函数),因为我过去也遇到过类似的问题。
所以,这样的解决方案可以解决一些棘手的问题(而不是 deleting/fast 重新打开,只是覆盖文件)- OS 的工作也更少,可能 file/disk碎片化。