简体   繁体   English

文件系统观察程序和大文件

[英]Filesystem watcher and large files

var fsw = new FileSystemWatcher(sPath, "*.PPF");
fsw.NotifyFilter = NotifyFilters.FileName;
fsw.IncludeSubdirectories = true;
fsw.Created += FswCreated;
fsw.EnableRaisingEvents = true;

static void FswCreated(object sender, FileSystemEventArgs e)
{
  string sFile = e.FullPath;
  string[] arrLines = File.ReadAllLines(sFile);
}

this fails with large files, because the process is not finnished with writing the file. 这对于大文件失败,因为编写文件时没有完成该过程。 The file is copied via the Network, so i dont know the size of the file. 该文件是通过网络复制的,所以我不知道文件的大小。 What kind of syncronisation is required to make this robust? 需要什么样的同步才能使其稳健?

Solution found on stackoverflow and modified it a bit. 在stackoverflow上找到解决方案并对其进行了一些修改。

static bool IsFileLocked(FileInfo file)
{
    FileStream stream = null;

    try
    {
        stream = file.Open(FileMode.Open, 
                 FileAccess.ReadWrite, FileShare.None);
    }
    catch (IOException)
    {
        //the file is unavailable because it is:
        //still being written to
        //or being processed by another thread
        //or does not exist (has already been processed)
        return true;
    }
    finally
    {
        if (stream != null)
            stream.Close();
    }

    //file is not locked
    return false;
}

static void FswCreated(object sender, FileSystemEventArgs e)
{
    string sFile = e.FullPath;

    Console.WriteLine("processing file : " + sFile);

    // Wait if file is still open
    FileInfo fileInfo = new FileInfo(sFile);
    while(IsFileLocked(fileInfo))
    {
        Thread.Sleep(500);
    }

    string[] arrLines = File.ReadAllLines(sFile);
}

Use the DelayedFileSystemWatcher.cs Class http://blogs.msdn.com/b/ahamza/archive/2006/02/06/526222.aspx 使用DelayedFileSystemWatcher.cshttp://blogs.msdn.com/b/ahamza/archive/2006/02/06/526222.aspx

and then this code. 然后这段代码。 Check the PrintFileSystemEventHandler eventhandler. 检查PrintFileSystemEventHandler事件处理程序。 It tries to read the file in file stream and if any ioerror is giventhe it assumes the file is still reading so it waits for a interval(2 seconds in this example) and then tries again. 它尝试在文件流中读取文件,如果有任何错误,则假定文件仍在读取,因此它等待一段时间(本例中为2秒),然后再次尝试。 Check the CONVERSION: label 检查CONVERSION:标签

static void Main(string[] args)
    {
        DelayedFileSystemWatcher dfw = new DelayedFileSystemWatcher(@"C:\\Test", "*.*");
        dfw.Changed += new FileSystemEventHandler(Program.FileSystemEventHandlerMethod);
        dfw.Created += new FileSystemEventHandler(Program.FileSystemEventHandlerMethod);
        dfw.Deleted += new FileSystemEventHandler(Program.FileSystemEventHandlerMethod);
        dfw.Error += new ErrorEventHandler(Program.ErrorEventHandlerMethod);
        dfw.Renamed += new RenamedEventHandler(Program.RenamedEventHandlerMethod);

        dfw.IncludeSubdirectories = true;
        dfw.ConsolidationInterval = 1000;
        dfw.EnableRaisingEvents = true;
        Console.WriteLine("Press \'q\' to quit the sample.");
        while (Console.Read() != 'q') ;
        //System.Threading.Thread.Sleep(60000);
        dfw.Dispose();
    }
    private static void FileSystemEventHandlerMethod(object sender, FileSystemEventArgs e)
    {
        PrintFileSystemEventHandler(e);
        System.Console.WriteLine();
    }

    private static void ErrorEventHandlerMethod(object sender, ErrorEventArgs e)
    {
        System.Console.WriteLine(e.GetException().Message);
        System.Console.WriteLine();
    }

    private static void RenamedEventHandlerMethod(object sender, RenamedEventArgs e)
    {
        PrintRenamedEventHandler(e);
        System.Console.WriteLine();
    }

    private static void PrintFileSystemEventHandler(FileSystemEventArgs e)
    {

    CONVERSION:
        try
        {

            if (e.ChangeType != WatcherChangeTypes.Deleted)
            {
                if (!isFolder(e.FullPath) && isFile(e.FullPath))
                {
                    FileStream fs = new FileStream(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.None);
                    fs.Close();
                }

            }
            System.Console.WriteLine(e.Name + " " + e.FullPath + " " + e.ChangeType);

        }
        catch (System.IO.IOException)
        {
            Console.WriteLine("There was an IOException error or File is still copying. Retrying in 2 seconds...");
            System.Threading.Thread.Sleep(2000);
            goto CONVERSION;
        }



        //System.Console.WriteLine(e.Name);
        //System.Console.WriteLine(e.FullPath);
        //System.Console.WriteLine(e.ChangeType);
    }

    private static bool isFolder(string strPath)
    {

        bool isFolderExist = false;
        try
        {
            isFolderExist = Directory.Exists(strPath);
        }
        catch
        {
            isFolderExist = false;
        }
        return isFolderExist;
    }

    private static bool isFile(string strPath)
    {

        bool isFileExist = false;
        try
        {
            isFileExist = File.Exists(strPath);
        }
        catch
        {
            isFileExist = false;
        }
        return isFileExist;
    }


    private static void PrintRenamedEventHandler(RenamedEventArgs e)
    {
        PrintFileSystemEventHandler(e);
        System.Console.WriteLine(e.OldName);
        System.Console.WriteLine(e.OldFullPath);
    }

I dont have the link to the project. 我没有项目的链接。 but this wil help. 但是这会有所帮助。

I support the solution accepted by Shay Erlichmen. 我支持Shay Erlichmen接受的解决方案。 But however a) You may wan't to open the File with access mode FileAccess.Read, incase its a read only file 但是,a)你可能不想打开文件访问模式FileAccess.Read,包括它的只读文件

b) Some programs whilst downloading, the file will have some funny extension and when completed, the extension will change, and although file would have completed you will have file not found exception. b)一些程序在下载时,文件将有一些有趣的扩展,完成后,扩展名将会改变,虽然文件已经完成,但你将找不到文件异常。

So handle the exceptions, and also subscribe to file.renamed event 因此处理异常,并订阅file.renamed事件

AFAIK you don't get notified once the copy is done, you can implement a retry mechanism. 完成复制后,您不会收到AFAIK通知,您可以实施重试机制。
If you get a shearing violation just trigger a timer to retry the operation in X seconds. 如果您遇到剪切违规,只需触发计时器即可在X秒内重试该操作。
The second retry should be after X*2 seconds and so on (with some limitation of course). 第二次重试应该在X * 2秒之后,依此类推(当然有一些限制)。

Simply in your fswCreated , sleep for about 1/2 seconds with Thread.Sleep(500) if thats possible. 只需在你的fswCreated ,如果可能的话,使用Thread.Sleep(500)睡眠约1/2秒。 That should give you the time the computer needs to finish writing the file. 这应该给你计算机完成文件编写所需的时间。

Of course, for slower hard drives, this may or may enough time. 当然,对于较慢的硬盘驱动器,这可能或可能有足够的时间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM