狠狠色丁香婷婷综合尤物/久久精品综合一区二区三区/中国有色金属学报/国产日韩欧美在线观看 - 国产一区二区三区四区五区tv

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

c#/c++ 通過系統(tǒng)api-FileSystemWatcher監(jiān)視文件或目錄變化的問題

admin
2023年12月26日 21:59 本文熱度 743

分享個比較經(jīng)典的案例,在很多場景下,我們都要去監(jiān)視某個文件夾下的文件變化,在創(chuàng)建、修改或刪除的時候觸發(fā)一些行為。眾所周知,c#有個實現(xiàn)類叫FileSystemWatcher,可以用來監(jiān)視目錄包括子目錄下文件的變化,這樣就不需要不斷的循環(huán)去遞歸掃目錄,節(jié)省很大的資源開銷,而且響應速度也更快。從本質上來說,無論在win還是linux上,都是通過封裝系統(tǒng)api進行實現(xiàn)的,所以這個坑,其實是并非是.net封裝的問題,而是一個無法繞過的問題。

先來看一個示例demo

1.  using System;

2.  using System.IO;

3.   

4.  class Program

5.  {

6.      static void Main()

7.      {

8.          // 要監(jiān)視的目錄路徑

9.          string pathToWatch = @"C:\Path\To\Your\Directory";

10.

11.        // 創(chuàng)建一個新的 FileSystemWatcher 實例

12.        using (FileSystemWatcher watcher = new FileSystemWatcher())

13.        {

14.            // 設置要監(jiān)視的目錄

15.            watcher.Path = pathToWatch;

16.

17.            // 設置要監(jiān)視的文件和目錄的更改類型

18.            watcher.NotifyFilter = NotifyFilters.LastWrite

19.                                 | NotifyFilters.FileName

20.                                 | NotifyFilters.DirectoryName;

21.            //包含子目錄監(jiān)視

22.            watcher.IncludeSubdirectories = true;

23.            // 啟用事件引發(fā)

24.            watcher.EnableRaisingEvents = true;

25.

26.            // 添加事件處理程序

27.            watcher.Created += OnCreated;

28.            watcher.Deleted += OnDeleted;

29.            watcher.Changed += OnChanged;

30.            watcher.Renamed += OnRenamed;

31.

32.            // 監(jiān)視狀態(tài)

33.            Console.WriteLine($"正在監(jiān)視目錄:{pathToWatch}");

34.            Console.WriteLine("按任意鍵退出.");

35.            Console.ReadKey();

36.        }

37.    }

38.

39.    // 文件或目錄創(chuàng)建事件處理程序

40.    private static void OnCreated(object sender, FileSystemEventArgs e)

41.    {

42.        Console.WriteLine($"新文件或目錄已創(chuàng)建: {e.Name} - 類型: {e.ChangeType}");

43.    }

44.

45.    // 文件或目錄刪除事件處理程序

46.    private static void OnDeleted(object sender, FileSystemEventArgs e)

47.    {

48.        Console.WriteLine($"文件或目錄已刪除: {e.Name} - 類型: {e.ChangeType}");

49.    }

50.

51.    // 文件或目錄更改事件處理程序

52.    private static void OnChanged(object sender, FileSystemEventArgs e)

53.    {

54.        Console.WriteLine($"文件或目錄已更改: {e.Name} - 類型: {e.ChangeType}");

55.    }

56.

57.    // 文件或目錄重命名事件處理程序

58.    private static void OnRenamed(object sender, RenamedEventArgs e)

59.    {

60.        Console.WriteLine($"文件或目錄已重命名: {e.OldName} -> {e.Name} - 類型: {e.ChangeType}");

61.    }

62.}

這段示例看起來沒有任何問題,但實際使用的時候會發(fā)現(xiàn),有些連續(xù)創(chuàng)建的文件,根本掃不到。

測試環(huán)境.net6 linux,比如監(jiān)視AAA文件夾,然后用程序創(chuàng)建AAA\BBB和AAA\BBB\123.txt,會發(fā)現(xiàn)能監(jiān)聽到BBB的創(chuàng)建,但卻沒有AAA\BBB\123.txt的通知。

再來看下windows c++上的demo

1.  #include <windows.h>

2.  #include <stdlib.h>

3.  #include <stdio.h>

4.  #include <tchar.h>

5.   

6.  void RefreshDirectory(LPTSTR);

7.  void RefreshTree(LPTSTR);

8.  void WatchDirectory(LPTSTR);

9.   

10.void _tmain(int argc, TCHAR *argv[])

11.{

12.    if(argc != 2)

13.    {

14.        _tprintf(TEXT("Usage: %s <dir>\n"), argv[0]);

15.        return;

16.    }

17.

18.    WatchDirectory(argv[1]);

19.}

20.

21.void WatchDirectory(LPTSTR lpDir)

22.{

23.   DWORD dwWaitStatus;

24.   HANDLE dwChangeHandles[2];

25.   TCHAR lpDrive[4];

26.   TCHAR lpFile[_MAX_FNAME];

27.   TCHAR lpExt[_MAX_EXT];

28.

29.   _tsplitpath_s(lpDir, lpDrive, 4, NULL, 0, lpFile, _MAX_FNAME, lpExt, _MAX_EXT);

30.

31.   lpDrive[2] = (TCHAR)'\\';

32.   lpDrive[3] = (TCHAR)'\0';

33.

34.// Watch the directory for file creation and deletion.

35.

36.   dwChangeHandles[0] = FindFirstChangeNotification(

37.      lpDir,                         // directory to watch

38.      FALSE,                         // do not watch subtree

39.      FILE_NOTIFY_CHANGE_FILE_NAME); // watch file name changes

40.

41.   if (dwChangeHandles[0] == INVALID_HANDLE_VALUE)

42.   {

43.     printf("\n ERROR: FindFirstChangeNotification function failed.\n");

44.     ExitProcess(GetLastError());

45.   }

46.

47.// Watch the subtree for directory creation and deletion.

48.

49.   dwChangeHandles[1] = FindFirstChangeNotification(

50.      lpDrive,                       // directory to watch

51.      TRUE,                          // watch the subtree

52.      FILE_NOTIFY_CHANGE_DIR_NAME);  // watch dir name changes

53.

54.   if (dwChangeHandles[1] == INVALID_HANDLE_VALUE)

55.   {

56.     printf("\n ERROR: FindFirstChangeNotification function failed.\n");

57.     ExitProcess(GetLastError());

58.   }

59.

60.

61.// Make a final validation check on our handles.

62.

63.   if ((dwChangeHandles[0] == NULL) || (dwChangeHandles[1] == NULL))

64.   {

65.     printf("\n ERROR: Unexpected NULL from FindFirstChangeNotification.\n");

66.     ExitProcess(GetLastError());

67.   }

68.

69.// Change notification is set. Now wait on both notification

70.// handles and refresh accordingly.

71.

72.   while (TRUE)

73.   {

74.   // Wait for notification.

75.

76.      printf("\nWaiting for notification...\n");

77.

78.      dwWaitStatus = WaitForMultipleObjects(2, dwChangeHandles,

79.         FALSE, INFINITE);

80.

81.      switch (dwWaitStatus)

82.      {

83.         case WAIT_OBJECT_0:

84.

85.         // A file was created, renamed, or deleted in the directory.

86.         // Refresh this directory and restart the notification.

87.

88.             RefreshDirectory(lpDir);

89.             if ( FindNextChangeNotification(dwChangeHandles[0]) == FALSE )

90.             {

91.               printf("\n ERROR: FindNextChangeNotification function failed.\n");

92.               ExitProcess(GetLastError());

93.             }

94.             break;

95.

96.         case WAIT_OBJECT_0 + 1:

97.

98.         // A directory was created, renamed, or deleted.

99.         // Refresh the tree and restart the notification.

100.        

101.                    RefreshTree(lpDrive);

102.                    if (FindNextChangeNotification(dwChangeHandles[1]) == FALSE )

103.                    {

104.                      printf("\n ERROR: FindNextChangeNotification function failed.\n");

105.                      ExitProcess(GetLastError());

106.                    }

107.                    break;

108.        

109.                case WAIT_TIMEOUT:

110.        

111.                // A timeout occurred, this would happen if some value other

112.                // than INFINITE is used in the Wait call and no changes occur.

113.                // In a single-threaded environment you might not want an

114.                // INFINITE wait.

115.        

116.                   printf("\nNo changes in the timeout period.\n");

117.                   break;

118.        

119.                default:

120.                   printf("\n ERROR: Unhandled dwWaitStatus.\n");

121.                   ExitProcess(GetLastError());

122.                   break;

123.             }

124.          }

125.       }

126.        

127.       void RefreshDirectory(LPTSTR lpDir)

128.       {

129.          // This is where you might place code to refresh your

130.          // directory listing, but not the subtree because it

131.          // would not be necessary.

132.        

133.          _tprintf(TEXT("Directory (%s) changed.\n"), lpDir);

134.       }

135.        

136.       void RefreshTree(LPTSTR lpDrive)

137.       {

138.          // This is where you might place code to refresh your

139.          // directory listing, including the subtree.

140.        

141.          _tprintf(TEXT("Directory tree (%s) changed.\n"), lpDrive);

142.       }

可以看到,這段代碼里面,有個問題,就是文件夾中如果文件創(chuàng)建在RefreshTree之后,F(xiàn)indNextChangeNotification之前,則會漏掉。所以在dotnet上,實際上并沒有使用這種方式,而是通過ReadDirectoryChangesW 去實現(xiàn)的,這種基于buffer的,理論不溢出,就不會出現(xiàn)丟失的情況。所以在windows下,只要buffer足夠大,fsw是不會漏掉任何一個文件的。

 那么來到linux,從源碼從可以看到是基于inotify的,讀下源碼第一句話,就真相大白了

所以在linux下,我的那種場景,剛好就觸發(fā)了這個問題,這種是基于inotify的缺陷,因為這玩意也沒buffer,我猜測與上面c++的demo出現(xiàn)的問題類似。

總結一下,使用fsw千萬需要小心,在win和linux上的表現(xiàn)是不同的,win上可以放心用,linux上可能會漏文件,需要在自己場景下特定的時間點進行檢測。不然可能會觸發(fā)意想不到的BUG。


該文章在 2023/12/26 22:12:56 編輯過
關鍵字查詢
相關文章
正在查詢...
點晴ERP是一款針對中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國內(nèi)大量中小企業(yè)的青睞。
點晴PMS碼頭管理系統(tǒng)主要針對港口碼頭集裝箱與散貨日常運作、調度、堆場、車隊、財務費用、相關報表等業(yè)務管理,結合碼頭的業(yè)務特點,圍繞調度、堆場作業(yè)而開發(fā)的。集技術的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點晴WMS倉儲管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質期管理,貨位管理,庫位管理,生產(chǎn)管理,WMS管理系統(tǒng),標簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務都免費,不限功能、不限時間、不限用戶的免費OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved