FileSystemWatcher C# - 无法访问文件,因为它正在被另一个进程使用
FileSystemWatcher C# - cannot access file because it is being used by another process
我正在使用 FileSystemWatcher
检测目录更改,然后读取文件内容并将其插入数据库。
这是我的代码:
private FileSystemWatcher _watcher;
public MainWindow()
{
try
{
InitializeComponent();
GetFiles();
//Task.Factory.StartNew(() => GetFiles())
// .ContinueWith(task =>
// {
// }, System.Threading.CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
}
catch(Exception ex)
{
//..
}
}
public bool GetFiles()
{
_watcher = new FileSystemWatcher(Globals.iniFilesPath, "*.ini");
_watcher.Created += FileCreated;
_watcher.IncludeSubdirectories = false;
_watcher.EnableRaisingEvents = true;
return true;
}
private void FileCreated(object sender, FileSystemEventArgs e)
{
try
{
string fileName = Path.GetFileNameWithoutExtension(e.FullPath);
if (!String.IsNullOrEmpty(fileName))
{
string[] content = File.ReadAllLines(e.FullPath);
string[] newStringArray = content.Select(s => s.Substring(s.LastIndexOf('=') + 1)).ToArray();
ChargingStationFile csf = new Product
{
Quantity = Convert.ToDecimal(newStringArray[1]),
Amount = Convert.ToDecimal(newStringArray[2]),
Price = Convert.ToDecimal(newStringArray[3]),
FileName = fileName
};
ProductController.Instance.Save(csf);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
如果我 运行 使用 CTRL+F5 此代码,我收到此消息:
但是如果我使用 F5(调试模式),那么我会收到这个错误,而不是这个关于无法访问进程和项目的错误保存成功。这真的让我很困惑..
我应该处理 watcher 吗?或类似的东西?也许我在这里遗漏了什么?
这是我第一次使用 FileSystemWatcher,显然这里确实有问题..
P.S 我发现这一行导致异常:
string[] content = File.ReadAllLines(e.FullPath);
怎么会?
谢谢大家
干杯
如 this 答案中所述:
Most likely what is happening here is that the FileCreated event is
being raised and tries to process the file before is has been
completely written to disk.
因此,您需要等到文件复制完成。根据this other answer:
From the documentation for FileSystemWatcher:
The OnCreated event is raised as soon as a file is created. If a file
is being copied or transferred into a watched directory, the OnCreated
event will be raised immediately, followed by one or more OnChanged
events.
因此,针对您的情况的解决方法是创建一个字符串列表,其中包含无法在 Created 方法处理程序中读取的文件路径,并在 FileSystemWatcher 的 Changed 事件中重新处理这些路径(阅读代码中的注释):
public partial class MainWindow : Window {
private FileSystemWatcher _watcher;
public MainWindow() {
try {
InitializeComponent();
GetFiles();
} catch (Exception ex) {
MessageBox.Show($"Exception: {ex.Message}");
}
}
private bool GetFiles() {
_watcher = new FileSystemWatcher(@"C:\TestFolder", "*.ini");
_watcher.Created += FileCreated;
_watcher.Changed += FileChanged; // add this.
_watcher.IncludeSubdirectories = false;
_watcher.EnableRaisingEvents = true;
return true;
}
// this field is new, and contains the paths of the files that could not be read in the Created method handler.
private readonly IList<string> _waitingForClose = new List<string>();
private void FileChanged(object sender, FileSystemEventArgs e) {
if (_waitingForClose.Contains(e.FullPath)) {
try {
string[] content = File.ReadAllLines(e.FullPath);
string[] newStringArray = content.Select(s => s.Substring(s.LastIndexOf('=') + 1)).ToArray();
MessageBox.Show($"On FileChanged: {string.Join(" --- ", newStringArray)}");
// Again, process the data from the file to saving in the database.
// removing the path, so as not to reprocess the file..
_waitingForClose.Remove(e.FullPath);
} catch (Exception ex) {
MessageBox.Show($"Exception on FileChanged: {ex.Message} - {e.FullPath}");
}
}
}
private void FileCreated(object sender, FileSystemEventArgs e) {
try {
string fileName = Path.GetFileNameWithoutExtension(e.FullPath);
if (!String.IsNullOrEmpty(fileName)) {
string[] content = File.ReadAllLines(e.FullPath);
string[] newStringArray = content.Select(s => s.Substring(s.LastIndexOf('=') + 1)).ToArray();
MessageBox.Show($"On FileCreated: {string.Join(" --- ", newStringArray)}");
// process the data from the file to saving in the database.
}
} catch (Exception ex) {
// if the method fails, add the path to the _waitingForClose variable
_waitingForClose.Add(e.FullPath);
//MessageBox.Show($"Exception on FIleCreated: {ex.Message} - {e.FullPath}");
}
}
}
File.ReadAllLines()
在另一个应用程序中打开文件写入时无法访问该文件,但您可以使用 FileStream
和 StreamReader
代替。
将 string[] content = File.ReadAllLines(e.FullPath);
替换为以下代码,无论文件是否在其他应用程序中打开,您都应该能够读取文件的内容:
List<string> content = new List<string>();
using (FileStream stream = new FileStream(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (StreamReader sr = new StreamReader(stream))
{
while (!sr.EndOfStream)
content.Add(sr.ReadLine());
}
我正在使用 FileSystemWatcher
检测目录更改,然后读取文件内容并将其插入数据库。
这是我的代码:
private FileSystemWatcher _watcher;
public MainWindow()
{
try
{
InitializeComponent();
GetFiles();
//Task.Factory.StartNew(() => GetFiles())
// .ContinueWith(task =>
// {
// }, System.Threading.CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
}
catch(Exception ex)
{
//..
}
}
public bool GetFiles()
{
_watcher = new FileSystemWatcher(Globals.iniFilesPath, "*.ini");
_watcher.Created += FileCreated;
_watcher.IncludeSubdirectories = false;
_watcher.EnableRaisingEvents = true;
return true;
}
private void FileCreated(object sender, FileSystemEventArgs e)
{
try
{
string fileName = Path.GetFileNameWithoutExtension(e.FullPath);
if (!String.IsNullOrEmpty(fileName))
{
string[] content = File.ReadAllLines(e.FullPath);
string[] newStringArray = content.Select(s => s.Substring(s.LastIndexOf('=') + 1)).ToArray();
ChargingStationFile csf = new Product
{
Quantity = Convert.ToDecimal(newStringArray[1]),
Amount = Convert.ToDecimal(newStringArray[2]),
Price = Convert.ToDecimal(newStringArray[3]),
FileName = fileName
};
ProductController.Instance.Save(csf);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
如果我 运行 使用 CTRL+F5 此代码,我收到此消息:
但是如果我使用 F5(调试模式),那么我会收到这个错误,而不是这个关于无法访问进程和项目的错误保存成功。这真的让我很困惑..
我应该处理 watcher 吗?或类似的东西?也许我在这里遗漏了什么?
这是我第一次使用 FileSystemWatcher,显然这里确实有问题..
P.S 我发现这一行导致异常:
string[] content = File.ReadAllLines(e.FullPath);
怎么会?
谢谢大家
干杯
如 this 答案中所述:
Most likely what is happening here is that the FileCreated event is being raised and tries to process the file before is has been completely written to disk.
因此,您需要等到文件复制完成。根据this other answer:
From the documentation for FileSystemWatcher:
The OnCreated event is raised as soon as a file is created. If a file is being copied or transferred into a watched directory, the OnCreated event will be raised immediately, followed by one or more OnChanged events.
因此,针对您的情况的解决方法是创建一个字符串列表,其中包含无法在 Created 方法处理程序中读取的文件路径,并在 FileSystemWatcher 的 Changed 事件中重新处理这些路径(阅读代码中的注释):
public partial class MainWindow : Window {
private FileSystemWatcher _watcher;
public MainWindow() {
try {
InitializeComponent();
GetFiles();
} catch (Exception ex) {
MessageBox.Show($"Exception: {ex.Message}");
}
}
private bool GetFiles() {
_watcher = new FileSystemWatcher(@"C:\TestFolder", "*.ini");
_watcher.Created += FileCreated;
_watcher.Changed += FileChanged; // add this.
_watcher.IncludeSubdirectories = false;
_watcher.EnableRaisingEvents = true;
return true;
}
// this field is new, and contains the paths of the files that could not be read in the Created method handler.
private readonly IList<string> _waitingForClose = new List<string>();
private void FileChanged(object sender, FileSystemEventArgs e) {
if (_waitingForClose.Contains(e.FullPath)) {
try {
string[] content = File.ReadAllLines(e.FullPath);
string[] newStringArray = content.Select(s => s.Substring(s.LastIndexOf('=') + 1)).ToArray();
MessageBox.Show($"On FileChanged: {string.Join(" --- ", newStringArray)}");
// Again, process the data from the file to saving in the database.
// removing the path, so as not to reprocess the file..
_waitingForClose.Remove(e.FullPath);
} catch (Exception ex) {
MessageBox.Show($"Exception on FileChanged: {ex.Message} - {e.FullPath}");
}
}
}
private void FileCreated(object sender, FileSystemEventArgs e) {
try {
string fileName = Path.GetFileNameWithoutExtension(e.FullPath);
if (!String.IsNullOrEmpty(fileName)) {
string[] content = File.ReadAllLines(e.FullPath);
string[] newStringArray = content.Select(s => s.Substring(s.LastIndexOf('=') + 1)).ToArray();
MessageBox.Show($"On FileCreated: {string.Join(" --- ", newStringArray)}");
// process the data from the file to saving in the database.
}
} catch (Exception ex) {
// if the method fails, add the path to the _waitingForClose variable
_waitingForClose.Add(e.FullPath);
//MessageBox.Show($"Exception on FIleCreated: {ex.Message} - {e.FullPath}");
}
}
}
File.ReadAllLines()
在另一个应用程序中打开文件写入时无法访问该文件,但您可以使用 FileStream
和 StreamReader
代替。
将 string[] content = File.ReadAllLines(e.FullPath);
替换为以下代码,无论文件是否在其他应用程序中打开,您都应该能够读取文件的内容:
List<string> content = new List<string>();
using (FileStream stream = new FileStream(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (StreamReader sr = new StreamReader(stream))
{
while (!sr.EndOfStream)
content.Add(sr.ReadLine());
}