C# - 不时检查文件是否存在并从中读取

时间:2012-09-25 07:30:05

标签: c# multithreading timer windows-services

我创建一个Windows服务,它会不时检查某个是否存在,如果存在,则从中读取,将数据发送到服务器并将文件移动到另一个文件夹。文件大小约为1-3 Mb。

我想我会在这里使用System.Threading.Timer来检查文件是否存在。你觉得怎么样?

另一个问题。如果正在复制文件,则我的应用程序不得从中读取。它应该等到复制完成。只有在那之后,它必须从中读取并进行其他活动。

所以问题:

1)这是使用System.Threading.Timer的正确决定吗?

2)如何检查正在复制的文件并等到文件完成?

3)我必须使用多线程吗?

5 个答案:

答案 0 :(得分:5)

  

我想我会在这里使用System.Threading.Timer来检查文件是否存在。你觉得怎么样?

我想你可以看一下FileSystemWatcher类,它会在创建文件时通知你并引发一个事件,而不是你使用一个不断轮询文件存在的Timer。

答案 1 :(得分:4)

计时器非常昂贵。您可以使用FileSystemWatcher哪个监听文件系统更改通知,并在目录或目录中的文件发生更改时引发事件。

// Create a new FileSystemWatcher and set its properties.
    FileSystemWatcher watcher = new FileSystemWatcher();
    watcher.Path = /*path*/
    /* Watch for changes in LastAccess and LastWrite times, and
       the renaming of files or directories. */
    watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
       | NotifyFilters.FileName | NotifyFilters.DirectoryName;
    // Only watch text files.
    watcher.Filter = "*.txt";

    // Add event handlers.
    watcher.Changed += new FileSystemEventHandler(OnChanged);
    watcher.Created += new FileSystemEventHandler(OnChanged);
    watcher.Deleted += new FileSystemEventHandler(OnChanged);
    watcher.Renamed += new RenamedEventHandler(OnRenamed);

    // Begin watching.
    watcher.EnableRaisingEvents = true;

然后这将是OnChanged方法:

    //This method is called when a file is created, changed, or deleted.
    private static void OnChanged(object source, FileSystemEventArgs e)
    {
        //Show that a file has been created, changed, or deleted.
        WatcherChangeTypes wct = e.ChangeType;
        Console.WriteLine("File {0} {1}", e.FullPath, wct.ToString());
    }

参考:http://devproconnections.com/net-framework/how-build-folder-watcher-service-c

答案 2 :(得分:1)

我使用的常用方法是使用FileSystemWatcher监视文件夹(如果不是.NET管理的话,还是相关的API),并尝试确保在源/目标文件夹上执行的唯一操作是移动/在同一物理驱动器上的文件夹之间重命名,并删除。如果要添加文件,请打开/写入/刷新/关闭目标文件系统驱动器上的临时文件夹,然后将其移动/重命名为正在监视的文件夹。至关重要的是,临时文件夹与目标文件夹位于同一物理驱动器上,以便可以在没有数据副本的情况下移动/重命名。

这在非托管系统上运行良好,而不是在C#上尝试过,但是没有任何理由不能正常工作。

其他涉及持续轮询和/或检查文件大小的解决方案只是不方便,不灵活,浪费,杂乱和延迟最多。

多线程 - 可能在任何远程文件系统上都是。网络文件调用往往在不可访问性等方面有很长的超时,因此在发出错误/异常之前阻止调用者看起来像是永远的。如果你想完成任何其他工作,除非你的用户可以容忍“沙漏应用程序”,窗口变得反应​​迟钝,消失回来,变灰并且操作系统提供关闭它们,否则你应该可以解决这个问题。

哦,还有一件事 - 最好在启动时进行清洗。东西在任何时候都可能出错,所以在跑步时要清理临时文件夹等中任何挥之不去的垃圾。

答案 3 :(得分:0)

我不会使用FileSystemWatcher它太脆弱了

FileSystemWatcher does not work on files created from windows service

我会将计时器设置为合理的刻度周期,你应该没问题。

一些示例代码

Timer_TicK()
{
 // remove tick event handler

 // do your processing

 // add back tick event handler
}

如果您要进行相当多的处理,这将使多个tick事件发生。在您发现由于性能问题而需要使用它之前,我不会多线程。

在C#中,如果您在文件系统复制文件时尝试读取文件,则会出现异常。您需要检查该异常或检查文件的属性(大小等)以了解它何时完成。

答案 4 :(得分:0)

完整计时器示例,我每次发生间隔时都会启动新线程(你不必,但这是一个很好的做法),这会检查文件是否存在并读取并删除它如果是:

using System;
using System.ServiceProcess;
using System.Threading;
using System.Timers;
using System.IO;

namespace MyNamespace
{
    public partial class Service1:  ServiceBase
    {
        Thread syncThread = null;
        System.Timers.Timer timer1;
        string filePath = @"C:\myfile.txt";
        int interval = 60000;  // 1 min -- adjust as necessary

        public Service1()
        {
           InitializeComponent();             
        }

        protected override void OnStart(string[] args)
        {
            timer1 = new System.Timers.Timer();
            timer1.Interval = interval;
            timer1.Enabled = true;
            timer1.Elapsed += new ElapsedEventHandler(timer1_Elapsed);
            timer1.Start();
        }
        protected override void OnStop()
        {
            syncThread.Abort();
            timer1.Stop();
        }
        protected void timer1_Elapsed(object sender, ElapsedEventArgs e)
        {
            syncThread = new Thread(new ThreadStart(doThread));
            syncThread.Start();
        }
        protected void doThread()
        {
            // whatever you put here, it will
            // run for each timer interval that elapses
            // in a separate thread, and each thread will
            // end when the processing in this function ends

            string fileContent = String.Empty;      

            if (File.Exists(filePath)
            {
                FileStream fs = new FileStream(filePath, FileMode.Open);
                StreamReader sr = new StreamReader(fs);
                fileContent = sr.ReadToEnd();
                sr.Close();
                fs.Close();
            } 

            if (fileContent != String.Empty)
            {
               // File was present... process the content...

               // Then I do this...
               File.Delete();
            }
        } 
    }
}

我没有遇到任何问题。我更喜欢在每个时间间隔内启动新线程,因此如果之前的运行尚未完成,它不会导致问题。走这条路,你有这个控制,可以决定你的间隔是什么,你的过程并不总是在进行 - 只是服务。使用FileSystemWatcher的另一条路线,它始终在观察和运行,并且您无法调整时间间隔,就像您可以使用计时器一样,以减少正在进行的事件/进程的数量,例如/如果文件已创建,则快速修改&保存。

我唯一看到的缺点就是必须自己检查文件属性,但这些都很容易检查。如果您像我一样处理后File.Delete(),则只需File.Exists(filePath)即可,以确定文件是否已重新创建。如果您必须检查是否需要修改,则只需检查DateTime lastModifed = File.GetLastWriteTime(filePath)(请参阅http://www.csharp-examples.net/file-creation-modification-time/)当前时间+您的间隔(DateTime lastRun = DateTime.Now.AddMilliseconds(interval))。如果lastRun > lastModified,您必须处理它。