【发布时间】:2015-07-16 21:17:35
【问题描述】:
我不想在任何时候阅读整个文件,我知道这个问题有答案,我想要 o 阅读第一行或最后一行。
我知道我的代码锁定了它正在读取的文件,原因有两个 1) 当我使用此代码运行我的小应用程序时,写入文件的应用程序会间歇性崩溃,但当我不运行此代码时它永远不会崩溃! 2)有几篇文章会告诉你File.ReadLines会锁定文件。
有一些类似的问题,但该答案似乎涉及读取整个文件,这对于大文件来说很慢,因此不是我想要做的。我大部分时间只阅读最后一行的要求与我所阅读的内容相比也是独一无二的。
我想知道如何阅读第一行(标题行)和最后一行(最后一行)。我不想在代码中的任何时候读取所有行,因为这个文件可能会变得很大并且读取整个文件会变得很慢。
我知道
line = File.ReadLines(fullFilename).First().Replace("\"", "");
...与...相同
FileStream fs = new FileStream(@fullFilename, FileMode.Open, FileAccess.Read, FileShare.Read);
我的问题是,如何在不以任何方式锁定它的情况下重复读取可能被另一个应用程序写入的文件的第一行和最后一行。我无法控制写入文件的应用程序。它是一个可以随时附加的数据日志。我以这种方式收听的原因是该日志可以连续几天附加。我想在我自己的 c# 程序中查看此日志中的最新数据,而无需等待日志写入完成。
我的代码调用阅读/听力函数...
//Start Listening to the "data log"
private void btnDeconstructCSVFile_Click(object sender, EventArgs e)
{
MySandbox.CopyCSVDataFromLogFile copyCSVDataFromLogFile = new MySandbox.CopyCSVDataFromLogFile();
copyCSVDataFromLogFile.checkForLogData();
}
我的听力课。现在它只是将数据添加到 2 个泛型列表中......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MySandbox.Classes;
using System.IO;
namespace MySandbox
{
public class CopyCSVDataFromLogFile
{
static private List<LogRowData> listMSDataRows = new List<LogRowData>();
static String fullFilename = string.Empty;
static LogRowData previousLineLogRowList = new LogRowData();
static LogRowData logRowList = new LogRowData();
static LogRowData logHeaderRowList = new LogRowData();
static Boolean checking = false;
public void checkForLogData()
{
//Initialise
string[] logHeaderArray = new string[] { };
string[] badDataRowsArray = new string[] { };
//Get the latest full filename (file with new data)
//Assumption: only 1 file is written to at a time in this directory.
String directory = "C:\\TestDir\\";
string pattern = "*.csv";
var dirInfo = new DirectoryInfo(directory);
var file = (from f in dirInfo.GetFiles(pattern) orderby f.LastWriteTime descending select f).First();
fullFilename = directory + file.ToString(); //This is the full filepath and name of the latest file in the directory!
if (logHeaderArray.Length == 0)
{
//Populate the Header Row
logHeaderRowList = getRow(fullFilename, true);
}
LogRowData tempLogRowList = new LogRowData();
if (!checking)
{
//Read the latest data in an asynchronous loop
callDataProcess();
}
}
private async void callDataProcess()
{
checking = true; //Begin checking
await checkForNewDataAndSaveIfFound();
}
private static Task checkForNewDataAndSaveIfFound()
{
return Task.Run(() => //Call the async "Task"
{
while (checking) //Loop (asynchronously)
{
LogRowData tempLogRowList = new LogRowData();
if (logHeaderRowList.ValueList.Count == 0)
{
//Populate the Header row
logHeaderRowList = getRow(fullFilename, true);
}
else
{
//Populate Data row
tempLogRowList = getRow(fullFilename, false);
if ((!Enumerable.SequenceEqual(tempLogRowList.ValueList, previousLineLogRowList.ValueList)) &&
(!Enumerable.SequenceEqual(tempLogRowList.ValueList, logHeaderRowList.ValueList)))
{
logRowList = getRow(fullFilename, false);
listMSDataRows.Add(logRowList);
previousLineLogRowList = logRowList;
}
}
//System.Threading.Thread.Sleep(10); //Wait for next row.
}
});
}
private static LogRowData getRow(string fullFilename, bool isHeader)
{
string line;
string[] logDataArray = new string[] { };
LogRowData logRowListResult = new LogRowData();
try
{
if (isHeader)
{
//Asign first (header) row data.
//Works but seems to block writting to the file!!!!!!!!!!!!!!!!!!!!!!!!!!!
line = File.ReadLines(fullFilename).First().Replace("\"", "");
}
else
{
//Assign data as last row (default behaviour).
line = File.ReadLines(fullFilename).Last().Replace("\"", "");
}
logDataArray = line.Split(',');
//Copy Array to Generics List and remove last value if it's empty.
for (int i = 0; i < logDataArray.Length; i++)
{
if (i < logDataArray.Length)
{
if (i < logDataArray.Length - 1)
{
//Value is not at the end, from observation, these always have a value (even if it's zero) and so we'll store the value.
logRowListResult.ValueList.Add(logDataArray[i]);
}
else
{
//This is the last value
if (logDataArray[i].Replace("\"", "").Trim().Length > 0)
{
//In this case, the last value is not empty, store it as normal.
logRowListResult.ValueList.Add(logDataArray[i]);
}
else { /*The last value is empty, e.g. "123,456,"; the final comma denotes another field but this field is empty so we will ignore it now. */ }
}
}
}
}
catch (Exception ex)
{
if (ex.Message == "Sequence contains no elements")
{ /*Empty file, no problem. The code will safely loop and then will pick up the header when it appears.*/ }
else
{
//TODO: catch this error properly
Int32 problemID = 10; //Unknown ERROR.
}
}
return logRowListResult;
}
}
}
【问题讨论】:
-
关于如何在多个进程中使用正确的共享模式打开文件的文章也很少...
-
musefan:解决方案是读取整个文件。我有一个文件将被附加几天甚至几周。我不想等待 2 周然后再阅读文件。我只想在 2 周的过程中阅读最后一行。在我的过程中,我永远不会阅读整个文件,因为它可能太大而无法阅读。
-
阿列克谢:哪个?如果他们只能阅读最后一行,这可能是我的解决方案。