【发布时间】:2021-08-13 07:06:01
【问题描述】:
我必须处理包含路径和状态信息的文件行,并为该行/路径启动上传操作。在某些情况下上传可能失败,所以我必须保留该行,在其他情况下,可以在上传成功时删除该行。主要问题是,一切都在后台运行,用户可以随时关闭软件。在这种情况下,我设置了一个 Cancellation-token 并且文件操作完成。 到现在为止,文件总是很小。所以我将所有仍然需要的行复制到一个新文件中并替换了旧文件。 简化代码:
bool valid=false;
bool cancelled=false;
using (StreamWriter sw = new StreamWriter(filename_tmp, false))
{
try
{
using (StreamReader sr = new StreamReader(filename)) //alternative:
// foreach (string line in File.ReadLines(filename))
{
// process each line of file
while (sr.Peek() >= 0)
{
string line = sr.ReadLine();
rowCnt++;
//separate line into content:
string[] content = line.Split(delimiter);
if (canceltoken.IsCancellationRequested && (rowCnt > 3))
{
cancelled = true;
}
else
{
data_path = content[0];
//start upload:
valid = UploadData(data_path);
}
if( cancelled || valid==false)
{
sw.WriteLine("{0},{1},{2},{3}", data_path, uploadCnt,
DateTime.Now.ToString(), errorMsg);
}
}
}
}
}
File.Replace(filename_tmp, filename, filename_backup);
现在我们遇到文件可能变得非常大的情况,我担心将所有内容复制到新文件中会花费太长时间。用户当前收到一条消息,表明仍有进程在运行,软件将在之后关闭。 1-5 秒后,软件关闭。现在需要更长的时间,我不希望用户使用任务管理器来终止进程。
处理行并在之后删除它的最佳方法是什么?我对文件有完全的控制权,因为我写了它。所以我可以自己定义格式和编写器(例如StreamWriter vs. BinaryWriter)。
我想到了两种可能的选择:
- 处理整个文件。为每一行设置一个状态标志(如 1=删除我,2=必须处理/保留)。处理完文件后,再次遍历行并复制所需的行。如果取消,请保留旧文件。
我想做这样的事情:
var linesToKeep = File.ReadLines(fileName).Where(l => l.Contains("remove me") ==false);
File.WriteAllLines(tempFile, linesToKeep);
但这需要我写到同一行来更改状态。我不确定那是否有效。我可以使用 BinaryWriter 来覆盖“标志”,但是我不能使用上面的行并且需要再次遍历每一行。
- 使用 seek 从末尾处理文件。如果我使用
BinaryWriter,我会确切地知道行的长度,所以这不是问题。在额外文件中写入需要再次处理的错误行。使用FileStream.SetLength在最后处理的行“剪切”原始文件。这将产生 2 个文件(原始文件包含未处理的行,第二个文件包含需要再次处理的行)。但我还不知道如何处理额外的文件。我可以在下次开始时先处理这个文件,但随后我可能会得到越来越多的文件,这似乎是错误的。
我不知何故被困在这里,我不知道如何进一步进行。任何提示将不胜感激。
【问题讨论】:
-
与其把还没上传的每一行都记录下来,不如只记录最后上传成功的那一行?然后如果程序重新启动,则从该行继续。
-
问题是,我会在两者之间松散线。可能是我上传4行成功,然后后面两行有问题,后来又上传了100行成功。如何跟踪出现错误的 2 行?
-
出错的行仍会记录到不同的文件中。
-
处理完主文件中的所有行后,将处理错误文件中的行。
标签: c# winforms filestream cancellation-token binaryreader