文件监视器自动将您的工作文件从 VS.NET 项目文件夹移动






4.52/5 (10投票s)
2006 年 2 月 16 日
3分钟阅读

51425

1528
一篇关于将工作文件与 Visual Studio .NET 2003 解决方案分离的文章。
引言
Visual Studio .NET 2003 及其早期版本非常棒,并且正在成为 .NET 应用程序开发人员的首选。您创建一个新项目,然后开发和编译代码。但是,当您想要将您的工作文件部署到生产环境时,会很痛苦。虽然您可以创建一个部署项目来构建 MSI 安装程序,但在许多情况下,您不想构建 MSI。您只是想拥有一个干净的文件夹,其中仅包含工作文件夹/文件,并将它交给您的客户,而不是一堆与您的工作文件混在一起的垃圾文件。
当您使用 Visual Studio .NET 2003 创建一个项目时,它会自动生成几个文件
xxx.csproj
xxx.csproj.user
xxx.sln
xxx.suo
AssemblyInfo.cs
...
如果您的项目与 SourceSafe 链接,您将拥有更多垃圾文件。当您将您的应用程序交付给客户时,这些文件通常不需要包含在您的应用程序中。
假设您有一个非常大的项目,由几个项目组成;将工作文件与这些项目/解决方案分开是一件非常痛苦的事情。
本文试图演示如何解决此问题。我构建了一个文件监视器对象来监视项目根文件夹;每当创建、删除、重命名或更改文件/文件夹时,它会将此文件/文件夹移动到单独的目标(项目发布文件夹)。
在这种情况下,在您进行开发时,工作文件/文件夹将被移动到目标位置。当您的开发完成时,您已经创建了干净的工作文件夹。您只需复制整个目标文件夹并将其部署给您的客户。听起来不错吗?
背景
解决此问题的一般思路是
- 定义两个文件夹
- FROM:您开发项目的根文件夹。
- TO:您要部署应用程序的部署文件夹。
此文件夹包含两个子文件夹:Engine 和 Bin。Engine 用于内容文件和相关文件夹。Bin 用于所有 .dll 和 .pdb 文件。
- 创建一个配置文件,指示在哪里以及如何处理您的项目。配置文件采用 XML 格式,如下所示
<Watchers> <Watcher> <Source>c:\filewatcher\testfolder\from</Source> <ProjectDestination>c:\filewatcher\testfolder \to\Bin</ProjectDestination> <EngineDestination>c:\filewatcher\testfolder \to\Engine</EngineDestination> <FileExtensions>dll,pdb,ascx,xml,gif,jpeg,dis,js,xsl, xls,htc,txt,config,asp,aspx,asmx</FileExtensions> <Events>Created,Changed,Renamed,Deleted</Events> <Trace>yes</Trace> </Watcher> </Watchers>
- 构建一个文件监视器来监视 FROM 文件夹;基于配置文件,它将文件/文件夹从源文件夹移动/更改到目标文件夹。
使用代码
只有一个类来执行文件监视工作:FileWatcher
。此类中有三个重要的方法:ProcessWatcher
、ProcessTask
和 CopyDeleteFile
。我将逐一描述这些方法。
ProcessWatcher
创建监视器对象的实例。它创建了四个事件:FileChanged
、FileCreated
、FileReNamed
和 FileDeleted
。在配置文件中,您指定要跟踪哪个事件。
/// <summary>
/// Create the instance of the watcher object
/// and fire the monitoring events.
/// After this method has executed,
/// the process is ready to monitor
/// </summary>
private void ProcessWatcher()
{
sourcePath = GetWatcherInfo("Source");
pDestinationPath = GetWatcherInfo("ProjectDestination");
eDestinationPath = GetWatcherInfo("EngineDestination");
watchFileExtension = GetWatcherInfo("FileExtensions");
trace = GetWatcherInfo("Trace").ToLower();
string eventName = GetWatcherInfo("Events");
string [] arrEvents = eventName.Split(",".ToCharArray());
int i = 0;
pDest = pDestinationPath.Split(";".ToCharArray());
WatchFile = new FileSystemWatcher(sourcePath, "*");
WatchFile.IncludeSubdirectories = true;
WatchFile.NotifyFilter = NotifyFilters.Size |
NotifyFilters.LastWrite |
NotifyFilters.FileName |
NotifyFilters.DirectoryName;
for (i=0;i<arrEvents.Length;i++)
{
switch(arrEvents[i])
{
case "Changed":
WatchFile.Changed += new
FileSystemEventHandler(FileChanged);
break;
case "Created":
WatchFile.Created += new
FileSystemEventHandler(FileCreated);
break;
case "Renamed":
WatchFile.Renamed += new
RenamedEventHandler(FileReNamed);
break;
case "Deleted":
WatchFile.Deleted += new
FileSystemEventHandler(FileDeleted);
break;
}
}
WatchFile.EnableRaisingEvents = true;
}
每当监视器触发一个事件时,它就会进入此处检查要执行什么类型的进程。
/// <summary>
/// Decide what kind of process needs to perform
/// </summary>
/// <param name="e">FileSystemEventArgs event argument</param>
/// <param name="checkType">Fired event type</param>
/// <param name="fileOrFolder">Is this a file or folder?</param>
private void ProcessTask(FileSystemEventArgs e,
string checkType, string fileOrFolder)
{
string fileName = string.Empty;
fileName = GetNameOnly(e.Name);
switch(checkType)
{
case "Created":
CheckFolder(e.Name, fileName, fileOrFolder);
CopyDeleteFile(e.FullPath, e.Name, fileName,
"", fileOrFolder, false);
break
case "Changed":
CopyDeleteFile(e.FullPath, e.Name, fileName,
"", fileOrFolder, false);
break
case "Deleted":
if (fileOrFolder == "file")
{
for (int i=0;i<pDest.Length;i++)
{
File.Delete(pDest[i] + "\\" + fileName);
File.Delete(pDest[i] + "\\" + e.Name);
}
}
else
{
Directory.Delete(eDestinationPath +
"\\" + e.Name, true);
}
break
default:
break
}
if (trace == "yes")
WriteLog(e, checkType);
}
最后,执行方法 CopyDeleteFile
:如果是重命名请求,此方法首先删除目标文件夹中的映射文件,然后将重命名的文件复制到目标映射文件夹。如果文件类型是文件夹,则其行为与文件相同。
/// <summary>
/// Whenever a file/folder has been renamed, deleted, created or modified,
/// the destination will do the same process accordingly.
/// </summary>
/// <param name="source">The folder path is been monitoring</param>
/// <param name="watchedNamePath">The changed file/folder path</param>
/// <param name="fileName">Destination file path to be mapped</param>
/// <param name="oldName">Destination file/folder
/// path before the name changing.</param>
/// <param name="fileOrFolder">Indicates the
/// monitored object is a file or folder</param>
/// <param name="isRename">Is this fried for rename?</param>
private void CopyDeleteFile(string source, string watchedNamePath,
string fileName, string oldName,
string fileOrFolder, bool isRename)
{
//Copy to project directory
if(fileName.IndexOf(".dll") > 0 || fileName.IndexOf(".pdb") > 0)
{
for (int i=0;i<pDest.Length;i++)
{
File.Delete(pDest[i] + "\\" + fileName);
File.Copy(source, pDest[i] + "\\" + fileName, true);
File.SetAttributes(pDest[i] + "\\" + fileName,
FileAttributes.Normal);
}
}
else
{
//Copy to engine directory. Only copy when file changed
if (oldName == "" && fileOrFolder == "file")
{
File.Copy(source, eDestinationPath + "\\" +
watchedNamePath, true);
File.SetAttributes(eDestinationPath + "\\" +
watchedNamePath, FileAttributes.Normal);
}
else
{
if (fileOrFolder == "file")
{
File.Delete(eDestinationPath + "\\" + oldName);
if (isRename)
File.Copy(source, eDestinationPath +
"\\" + watchedNamePath, true);
}
else if (fileOrFolder == "folder" && oldName != "")
{
Directory.Move(eDestinationPath + "\\" + oldName,
eDestinationPath + "\\" + watchedNamePath);
}
}
}
}
运行演示程序
下载演示 Zip 文件并将其解压缩到您的 c: 驱动器。打开根目录 FileWatchDemo 文件夹,您应该看到以下文件和文件夹
c:\FileWatcherDemo\TestFolder
C:\FileWatcherDemo\CustomWatcher.config
C:\FileWatcherDemo\FileWatcher.exe
双击 FileWatcher.exe,并将一个 DLL 复制到 C:\FileWatcherDemo\TestFolder\From 文件夹。您应该看到此 DLL 已被添加到 C:\FileWatcherDemo\TestFolder\To\bin 文件夹中。
将一个 GIF 文件复制到 C:\FileWatcherDemo\TestFolder\From 文件夹,您应该看到此 GIF 文件已添加到 C:\FileWatcherDemo\TestFolder\To\engine 文件夹中。