WindowsService

创建

20211214151712001

配置

  • 添加服务

    工程右键 => 添加 => 新建项

    20211214151712002

  • 修改服务入口

    20211214151712003

  • 添加安装程序

    20211214151712004

    20211214151712005

  • 配置服务参数

    20211214151712006

    20211214151712007

编写

20211214151712008

安装

安装和卸载主要使用的是.NET提供的 InstallUtil.exe 这个文件 ,文件位于C盘对应的目录下 C:\Windows\Microsoft.NET\Framework64\v4.0.30319 ,拷贝至和exe同一个目录bin下。

拷贝完成后再执行下方操作,需要管理员权限。(注意:安装后不要再用VisualStudio修改服务,若需要修改先卸载服务,否则服务卸载会提示卸载异常,未完全卸载!)

20211214151712009

1
installutil TestService.exe

启动

20211214151712010

1
net start TestService

调试

20211214151712011

20211214151712012

停止

20211214151712013

1
net stop TestService

卸载

20211214151712014

1
installutil /u TestService.exe

FileSystemWatcher 类

定义

  • 命名空间:

    System.IO

  • 程序集:

    System.IO.FileSystem.Watcher.dll

侦听文件系统更改通知,并在目录或目录中的文件发生更改时引发事件。

属性

属性名 属性说明
CanRaiseEvents 获取一个指示组件是否可以引发事件的值。(继承自 Component)
Container 获取包含 IContainerComponent。(继承自 Component)
DesignMode 获取一个值,用以指示 Component 当前是否处于设计模式。(继承自 Component)
EnableRaisingEvents 获取或设置一个值,该值指示是否启用此组件。
Events 获取附加到此 Component 的事件处理程序的列表。(继承自 Component)
Filter 获取或设置用于确定在目录中监视哪些文件的筛选器字符串。
Filters 获取用于确定在目录中监视哪些文件的所有筛选器的集合。
IncludeSubdirectories 获取或设置一个值,该值指示是否应监视指定路径中的子目录。
InternalBufferSize 获取或设置内部缓冲区的大小(以字节为单位)。
NotifyFilter 获取或设置要监视的更改的类型。
Path 获取或设置要监视的目录的路径。
Site 获取或设置 ISiteFileSystemWatcher
SynchronizingObject 获取或设置用于封送因目录更改而发出的事件处理程序调用的对象。

方法

方法名 方法说明
BeginInit() 开始初始化在窗体上使用或由另一个组件使用的 FileSystemWatcher。 初始化发生在运行时。
CreateObjRef(Type) 创建一个对象,该对象包含生成用于与远程对象进行通信的代理所需的全部相关信息。(继承自 MarshalByRefObject)
Dispose() 释放由 Component 使用的所有资源。(继承自 Component)
Dispose(Boolean) 释放由 FileSystemWatcher 占用的非托管资源,还可以另外再释放托管资源。
EndInit() 结束在窗体上使用或由另一个组件使用的 FileSystemWatcher 的初始化。 初始化发生在运行时。
Equals(Object) 确定指定对象是否等于当前对象。(继承自 Object)
GetHashCode() 作为默认哈希函数。(继承自 Object)
GetLifetimeService() 已过时。检索控制此实例的生存期策略的当前生存期服务对象。(继承自 MarshalByRefObject)
GetService(Type) 返回一个对象,该对象表示由 Component 或它的 Container 提供的服务。(继承自 Component)
GetType() 获取当前实例的 Type。(继承自 Object)
InitializeLifetimeService() 已过时。获取生存期服务对象来控制此实例的生存期策略。(继承自 MarshalByRefObject)
MemberwiseClone() 创建当前 Object 的浅表副本。(继承自 Object)
MemberwiseClone(Boolean) 创建当前 MarshalByRefObject 对象的浅表副本。(继承自 MarshalByRefObject)
OnChanged(FileSystemEventArgs) 引发 Changed 事件。
OnCreated(FileSystemEventArgs) 引发 Created 事件。
OnDeleted(FileSystemEventArgs) 引发 Deleted 事件。
OnError(ErrorEventArgs) 引发 Error 事件。
OnRenamed(RenamedEventArgs) 引发 Renamed 事件。
ToString() 返回包含 Component 的名称的 String(如果有)。 不应重写此方法。(继承自 Component)
WaitForChanged(WatcherChangeTypes) 一种同步方法,在给定要监视的更改的类型情况下,它会返回包含已发生的更改上的特定信息的结构。
WaitForChanged(WatcherChangeTypes, Int32) 一种同步方法,在给定要监视的更改的类型以及在超时前等待的时间(以毫秒表示)的情况下,它会返回包含已发生的更改上的特定信息的结构。

事件

事件名 事件说明
Changed 当更改指定 Path 中的文件和目录时发生。
Created 当在指定 Path 中创建文件和目录时发生。
Deleted 删除指定 Path 中的文件或目录时发生。
Disposed 在通过调用 Dispose() 方法释放组件时发生。(继承自 Component)
Error FileSystemWatcher 的实例无法继续监视更改或内部缓冲区溢出时发生。
Renamed 重命名指定 Path 中的文件或目录时发生。

示例(WindowsService+FileSystemWatcher)

TestService.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.ServiceProcess;

namespace TextWindowsService
{
partial class TestService : ServiceBase
{
FileSystemWatcher watcher = null;
static Log log = null;

public TestService()
{
InitializeComponent();
}

protected override void OnStart(string[] args)
{
// TODO: 在此处添加代码以启动服务。
Init();
}

protected override void OnStop()
{
// TODO: 在此处添加代码以执行停止服务所需的关闭操作。
log.Dispose();
}

void Init()
{
log = new Log(@"D:\FileSystemWatcher");
watcher = new FileSystemWatcher();
watcher.Path = @"D:\FileSystemWatcher";
watcher.NotifyFilter = NotifyFilters.Attributes
| NotifyFilters.CreationTime
| NotifyFilters.DirectoryName
| NotifyFilters.FileName
| NotifyFilters.LastAccess
| NotifyFilters.LastWrite
| NotifyFilters.Security
| NotifyFilters.Size;

watcher.Changed += OnChanged;
watcher.Created += OnCreated;
watcher.Deleted += OnDeleted;
watcher.Renamed += OnRenamed;
watcher.Error += OnError;

watcher.Filter = "*.txt";
watcher.IncludeSubdirectories = true;
watcher.EnableRaisingEvents = true;

log.WriteInfo("Press enter to exit.");
Console.WriteLine("Press enter to exit.");
Console.ReadLine();
}

private static void OnChanged(object sender, FileSystemEventArgs e)
{
if (e.ChangeType != WatcherChangeTypes.Changed)
{
return;
}
log.WriteInfo($"Changed: {e.FullPath}");
}

private static void OnCreated(object sender, FileSystemEventArgs e)
{
string value = $"Created: {e.FullPath}";
log.WriteInfo(value);
}

private static void OnDeleted(object sender, FileSystemEventArgs e) =>
log.WriteInfo($"Deleted: {e.FullPath}");

private static void OnRenamed(object sender, RenamedEventArgs e)
{
log.WriteInfo($"Renamed:");
log.WriteInfo($" Old: {e.OldFullPath}");
log.WriteInfo($" New: {e.FullPath}");
}

private static void OnError(object sender, ErrorEventArgs e) =>
PrintException(e.GetException());

private static void PrintException(Exception ex)
{
if (ex != null)
{
log.WriteInfo($"Message: {ex.Message}");
log.WriteInfo("Stacktrace:");
log.WriteInfo(ex.StackTrace);
Console.WriteLine();
PrintException(ex.InnerException);
}
}
}
}

Log.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
using System;
using System.IO;

namespace TextWindowsService
{
class Log
{
string LogFilePath = null;
StreamWriter sw = null;
string LogFileName = null;

/// <summary>
/// 日志工具类
/// </summary>
/// <param name="logFilePath">日志文件路径</param>
public Log(string logFilePath)
{
this.LogFilePath = logFilePath;
InitLogFile();
}

/// <summary>
/// 写一行信息
/// </summary>
/// <param name="msg">写入信息</param>
public void WriteInfo(string msg)
{
sw.WriteLine(msg);
}

/// <summary>
/// 释放资源
/// </summary>
public void Dispose()
{
sw.WriteLine($"========================= End_{DateTime.Now:yyyy-MM-dd hh:mm:ss} =========================");
sw.WriteLine("");
sw.WriteLine("");
sw.Close();
}

public void OpenLog()
{
System.Diagnostics.Process.Start("Explorer", "/start," + Path.Combine(LogFilePath, LogFileName));
}

/// <summary>
/// 日志文件初始化
/// </summary>
void InitLogFile()
{
if (!Directory.Exists(LogFilePath))
Directory.CreateDirectory(LogFilePath);
LogFileName = $"{DateTime.Now:yyyy-MM-dd}.log";
this.sw = new StreamWriter(Path.Combine(LogFilePath, LogFileName), true);
sw.WriteLine($"========================= Start_{DateTime.Now:yyyy-MM-dd hh:mm:ss} =========================");
}
}
}

20211214151712015

注意:本示例只有在关闭服务时才会调用写入流的Close()方法,只有调用Close()方法之后才能看见日志内容。