如何读取文本文件而不锁定它?

我有一个窗口服务写它的日志在一个文本文件在一个简单的格式。

现在,我将创建一个小应用程序来读取服务的日志,并将现有日志和添加的日志显示为实时视图。

问题是服务锁定文本文件以添加新行,同时查看器应用程序锁定文件以进行读取。

服务编号:

void WriteInLog(string logFilePath, data)
{
File.AppendAllText(logFilePath,
string.Format("{0} : {1}\r\n", DateTime.Now, data));
}

查看器代码:

int index = 0;
private void Form1_Load(object sender, EventArgs e)
{
try
{
using (StreamReader sr = new StreamReader(logFilePath))
{
while (sr.Peek() >= 0)  // reading the old data
{
AddLineToGrid(sr.ReadLine());
index++;
}
sr.Close();
}


timer1.Start();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}




private void timer1_Tick(object sender, EventArgs e)
{
using (StreamReader sr = new StreamReader(logFilePath))
{
// skipping the old data, it has read in the Form1_Load event handler
for (int i = 0; i < index ; i++)
sr.ReadLine();


while (sr.Peek() >= 0) // reading the live data if exists
{
string str = sr.ReadLine();
if (str != null)
{
AddLineToGrid(str);
index++;
}
}
sr.Close();
}
}

我的代码在读写方面有什么问题吗?

如何解决这个问题?

95880 次浏览

Have you tried copying the file, then reading it?

Just update the copy whenever big changes are made.

The problem is when you are writing to the log you are exclusively locking the file down so your StreamReader won't be allowed to open it at all.

You need to try open the file in readonly mode.

using (FileStream fs = new FileStream("myLogFile.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using (StreamReader sr = new StreamReader(fs))
{
while (!fs.EndOfStream)
{
string line = fs.ReadLine();
// Your code here
}
}
}

Explicit set up the sharing mode while reading the text file.

using (FileStream fs = new FileStream(logFilePath,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite))
{
using (StreamReader sr = new StreamReader(fs))
{
while (sr.Peek() >= 0) // reading the old data
{
AddLineToGrid(sr.ReadLine());
index++;
}
}
}

You need to make sure that both the service and the reader open the log file non-exclusively. Try this:

For the service - the writer in your example - use a FileStream instance created as follows:

var outStream = new FileStream(logfileName, FileMode.Open,
FileAccess.Write, FileShare.ReadWrite);

For the reader use the same but change the file access:

var inStream = new FileStream(logfileName, FileMode.Open,
FileAccess.Read, FileShare.ReadWrite);

Also, since FileStream implements IDisposable make sure that in both cases you consider using a using statement, for example for the writer:

using(var outStream = ...)
{
// using outStream here
...
}

Good luck!

new StreamReader(File.Open(logFilePath,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite))

-> this doesn't lock the file.

I remember doing the same thing a couple of years ago. After some google queries i found this:

    FileStream fs = new FileStream(@”c:\test.txt”,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite);

i.e. use the FileShare.ReadWrite attribute on FileStream().

(found on Balaji Ramesh's blog)

This method will help you to fastest read a text file and without locking it.

private string ReadFileAndFetchStringInSingleLine(string file)
{
StringBuilder sb;
try
{
sb = new StringBuilder();
using (FileStream fs = File.Open(file, FileMode.Open))
{
using (BufferedStream bs = new BufferedStream(fs))
{
using (StreamReader sr = new StreamReader(bs))
{
string str;
while ((str = sr.ReadLine()) != null)
{
sb.Append(str);
}
}
}
}
return sb.ToString();
}
catch (Exception ex)
{
return "";
}
}

Hope this method will help you.