我创建一个Windows服务,它会不时检查某个是否存在,如果存在,则从中读取,将数据发送到服务器并将文件移动到另一个文件夹。文件大小约为1-3 Mb。
我想我会在这里使用System.Threading.Timer
来检查文件是否存在。你觉得怎么样?
另一个问题。如果正在复制文件,则我的应用程序不得从中读取。它应该等到复制完成。只有在那之后,它必须从中读取并进行其他活动。
所以问题:
1)这是使用System.Threading.Timer
的正确决定吗?
2)如何检查正在复制的文件并等到文件完成?
3)我必须使用多线程吗?
答案 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
,您必须处理它。