我的一個windows服務要用於和其他軟件通信,采用的方法是比較簡單的文件通信方式,就是大家都訪問一個文件夾,對方將要處理的文件放到該文件夾裡,然後我來監控這個文件夾,發現有我要的文件我就取走處理。
通過萬能的baidu和Google,我找到了FileSystemWatcher這麼一個類可以來處理文件監視,用法也很簡單,主要代碼如下:
//Create a new FileSystemWatcher and set its properties.
watcher = new FileSystemWatcher(); watcher.Path = pathName; /* Watch for changes in LastAccess and LastWrite times, and the renaming of files or directories. */ watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName; // Only watch text files. watcher.Filter = "*.txt"; // Add event handlers. watcher.Created += new FileSystemEventHandler(OnChanged); watcher.Error += new ErrorEventHandler(OnError); // Begin watching. watcher.EnableRaisingEvents = true;
只要給這個類的對象設置好監視的路徑,監視文件有什麼屬性改變,還有監視文件的類型,最後添加事件觸發的處理事件就可以了,當然記得一定要激活該對象(就是watcher.EnableRaisingEvents = true;這句話)。這個類用於監視本地文件夾的時候,工作的很好,但是我的程序需求是還要能監視網絡文件夾,也就是網絡上有個共享文件夾,當我用這個類來監視網絡文件夾的時候就出現了一些不能解決的問題,
主要的問題就是當我網絡出現一些問題,比如我拔掉網線,然後再過一會(大概過個幾分鐘吧,太短是不會出問題)插回去,就發現我的watcher失效了,按照MSDN上面的說法是,可以通過添加ErrorEventhandler來捕獲watcher出現的異常事件,在Google上面也搜到有些人的帖子說確實可以捕獲到錯誤,然後再錯誤處理裡面來重新創建watcher,但是很遺憾的是我的拔網線測試始終通不過,但是很有意思的是通過禁用本機的網卡,可以捕獲到異常,但是禁用監視文件夾所在機器的網卡還是捕獲不到異常,所以我得出的結論是---建議在使用本地文件夾監視的時候可以采用FileSystemWatcher,網絡文件夾監視最好不要使用。
既然FileSystemWatcher不能很好的監控網絡文件夾,那麼應該如何監控網絡的文件夾呢,因為當前的服務程序裡面有用到定時器,就很自然的想到用定時掃描文件來監視文件夾,雖然方法看上去很笨,但是效果卻很不錯,以下是代碼:
public class FolderWatchHelper
{
public string m_pathName { set; get; }
public string m_fileTypeFilter { set; get; }
public string m_logName { set; get; }
public string m_logPassword { set; get; }
public List<string> m_fileList { set; get; }
private System.Timers.Timer m_timer;
public FolderWatchHelper(float interval)
{
m_fileList = new List<string>();
m_timer = new System.Timers.Timer();
m_timer.Interval = interval;
m_timer.Elapsed += new System.Timers.ElapsedEventHandler(WatchFolder);//到達時間的時候執行事件;
m_timer.AutoReset = true;//設置是執行一次(false)還是一直執行(true);
m_timer.Enabled = false;//是否執行System.Timers.Timer.Elapsed事件;
}
public bool IsRun()
{
return m_timer.Enabled;
}
public bool Run()
{
bool ret = true;
if (m_timer == null)
{
ret = false;
}
else if (m_timer.Enabled == false)
{
m_timer.Enabled = true;//是否執行System.Timers.Timer.Elapsed事件;
}
return ret;
}
public bool Stop()
{
bool ret = true;
if (m_timer != null && m_timer.Enabled == true)
{
m_timer.Enabled = false;
}
return ret;
}
public void WatchFolder(object source, System.Timers.ElapsedEventArgs e)
{
m_timer.Enabled = false;
bool ret = true;
if (m_pathName != "")
{
if (!Directory.Exists(m_pathName))
{
if (m_logName != "" || m_logPassword != "")
{
ConnAuthorize conn = new ConnAuthorize(m_logName, m_logPassword, m_pathName);
ret = conn.RemoteConnect(true);
}
}
if (Directory.Exists(m_pathName))
{
lock (m_fileList)
{
DirectoryInfo folder = new DirectoryInfo(m_pathName);
foreach (FileInfo file in folder.GetFiles(m_fileTypeFilter))
{
string fileName = file.FullName;
if (!m_fileList.Contains(fileName))
{
m_fileList.Add(file.FullName);
}
}
}
}
else
{
LogHelper.WriteLogFile("the watchfolder is not exist.");
}
}
m_timer.Enabled = true;
}
}
最主要的就是定時處理函數了public void WatchFolder(object source, System.Timers.ElapsedEventArgs e),這裡面就是去讀取路徑下過濾類型的文件夾,然後放入鏈表,之所以有用戶民和密碼,那是因為有些遠程共享文件即使設置everyone共享但是第一次訪問還是要用用戶名和密碼來創立連接,該功能代碼也貼出來吧:
class ConnAuthorize
{
private string userName;
private string userPwd;
private string shareResDictionary;
// constructor
public ConnAuthorize(string myUserName, string myUserPwd, string myShareResDictionary)
{
this.userName = myUserName;
this.userPwd = myUserPwd;
this.shareResDictionary = myShareResDictionary;
}
[StructLayout(LayoutKind.Sequential)]
public struct NETRESOURCEA
{
public int dwScope;
public int dwType;
public int dwDisplayType;
public int dwUsage;
[MarshalAs(UnmanagedType.LPStr)]
public string lpLocalName;
[MarshalAs(UnmanagedType.LPStr)]
public string lpRemoteName;
[MarshalAs(UnmanagedType.LPStr)]
public string lpComment;
[MarshalAs(UnmanagedType.LPStr)]
public string lpProvider;
public override String ToString()
{
String str = "LocalName: " + lpLocalName + " RemoteName: " + lpRemoteName + " Comment: " + lpComment + " lpProvider: " + lpProvider;
return (str);
}
}
[DllImport("mpr.dll")]
public static extern int WNetAddConnection2([MarshalAs(UnmanagedType.LPArray)] NETRESOURCEA[] lpNetResource, [MarshalAs(UnmanagedType.LPStr)] string lpPassword, [MarshalAs(UnmanagedType.LPStr)] string UserName, int dwFlags);
[DllImport("mpr.dll")]
public static extern int WNetCancelConnection2(string lpName, int dwFlags, bool fForce);
[DllImport("mpr.dll")]
public static extern int WNetOpenEnum(int dwScope, int dwType, int dwUsage, [MarshalAs(UnmanagedType.LPArray)] NETRESOURCEA[] lpNetResource, ref IntPtr lphEnum);
public bool RemoteConnect(bool bConnected)
{
int res;
try
{
NETRESOURCEA[] n = new NETRESOURCEA[1];
n[0] = new NETRESOURCEA();
n[0].dwType = 1;
int dwFlags = 1; // CONNECT_INTERACTIVE;
n[0].lpLocalName = @"";
n[0].lpRemoteName = shareResDictionary;
n[0].lpProvider = null;
if (bConnected)
{
res = WNetAddConnection2(n, userPwd, userName, dwFlags);
}
else
{
res = WNetCancelConnection2(shareResDictionary, 1, true);
}
}
catch (Exception e)
{
res = 1;
LogHelper.WriteLogFile("SQLiteBackUpService ConnAuthorize:RemoteConnect exception,e info:" + e.ToString());
}
if (res == 1219)
{
res = 0;
}
return (res == 0) ? true : false;
}
}
通過定時器監視共享文件可以很好的監視本地和網絡文件夾,即使斷網只要網絡恢復程序任然能夠正常監視。
白的跟紙什麼標准orz
魔都的淡定路過