0

我有一个从文本文件中读取以确定应生成哪些报告的应用程序。它在大多数情况下都可以正常工作,但有时,程序会删除它读取/写入的文本文件之一。然后抛出异常(“找不到文件”)并且进度停止。

这是一些相关的代码。

首先,从文件中读取:

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

然后,写入文件——它将该文件中的记录/行标记为已处理,以便下次检查文件时不会重新生成相同的报告:

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”出现在记录/行/行的末尾,它会被忽略 - 不会被处理。

此外,如果第二个元素(在索引 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% 的情况下解决了问题,但从我在这里发现的情况来看,似乎 File.Delete() 无论如何都是多余/多余的,所以我用 File.Delete 进行了测试() 注释掉了,它工作正常;所以,我现在只是在做这个偶尔有问题的电话。我希望这能解决问题。

4

1 回答 1

1
// Will this automatically overwrite the existing?
File.Delete(fileToUpdate);
File.WriteAllLines(fileToUpdate, fileContents);

我会简单地添加一个额外的参数WriteAllLines()(可以默认为false)来告诉函数以覆盖模式打开文件,然后根本不调用File.Delete()

您当前是否检查打开文件的返回值?


更新:好的,它看起来像WriteAllLines()一个 .Net Framework 功能,因此无法更改,所以我删除了这个答案。然而,现在这出现在评论中,作为另一个论坛上的建议解决方案:

“只需使用 File.WriteAllText 之类的东西,如果文件存在,数据就会被覆盖,如果文件不存在,它将被创建。”

这正是我的意思(虽然认为WriteAllLines()是用户定义的函数),因为我过去也遇到过类似的问题。

因此,这样的解决方案可以解决一些棘手的问题(而不是删除/快速重新打开,只是覆盖文件) - 也减少了操作系统的工作,并且可能减少了文件/磁盘碎片。

于 2017-03-15T22:11:10.993 回答