본문 바로가기
2_ 바삭바삭 프로그래밍/C# and Visual C++

[C#] 폴더에 수정사항이 발생했을때 이벤트를 발생시켜주는 컴포넌트 FileSystemWatcher

by 준환이형님_ 2012. 8. 16.

이벤트가 필요한 요즘 :|



출처 : 김수동 (sobakr) : http://www.devpia.com/Maeul/Contents/Detail.aspx?BoardID=6127&MAEULNO=769&no=26366&page=10 



특정 폴더(디렉터리)에 포함되어 있는 하위 폴더 및 파일의 생성,삭제,변경 등을 감지할 수 있도록

도와주는 닷넷 컴포넌트인 FileSystemWatcher 컴포넌트에 대해 알아 보겠습니다.

 

이 컴포넌트는 System.IO 네임스페이스에 포함되어 있으며 윈도우 파일 시스템 변경에 대한 알림을 수신하면서

설정된 디렉터리 내용이 변경되면 자동으로 이벤트를 발생 시켜 주는 역할을 합니다.

 

사용법은 아주 간단합니다.

먼저 초 간단한 예를 살펴 보겠습니다.

 

우선 도구 상자에서 FileSystemWatcher 컴포넌트를 Form 에 올리도록 합니다.

 

기본적으로 FileSystemWatcher 컴포넌트가 파일 시스템의 감시하려면

감시할 대상 디렉터리를 나타내는 Path 속성이 설정되어 있어야 하며 EnableRaisingEvents 속성이 참(true)

설정되어 있어야 합니다. EnableRaisingEvents 속성은 VS2005 부터는 기본값이 true 이므로 따로 변경할 필요가 없으며

Path 속성만 설정 해 주면 됩니다.

 

아래와 같이 Path 속성을 설정해 줍니다.

this.fileSystemWatcher1.Path = @"D:\Directory1";

 

 Path 속성 값으로는 디렉터리명이 설정되어야 합니다.

존재 하지 않는 디렉터리를 설정하거나 파일명을 지정하게 되면 예외가 발생하게 됩니다.

 


 참고모니터링 도중 대상 디렉터리 이름 변경

 Path = Directory1 으로 설정 하고 난 후 응용프로그램을 실행하여 파일 시스템 감시를 하고 있는 와중에

 Directory1 의 디렉터리 이름이 변경되면 어떻게 될까요??

 답은 아무 이상 없이 여전히 그 디렉터리를 감시한다.. 입니다.

 FileSystemWatcher 은 실행되고 난 후에는 디렉터리 이름이 아닌 디렉터리 핸들 값을 기반으로 감시하게 됩니다

 디렉터리 명이 변경되어도 핸들값은 변경되지 않기 때문에 이상이 없이 잘 동작하게 되는 것입니다.

 그러나 디렉터리 명이 변경되고 난 후에 응용프로그램을 죽였다가 다시 빌드하면 예외가 발생합니다.

 디렉터리를 찾지 못하기 때문입니다.

 

감시할 대상 디렉터리가 설정되었으므로 이제 무엇을 보고 받을 지에 대한 이벤트 연결을 하도록 합니다.

변경 상황에 대한 아래의 4개의 이벤트가 정의되어 있습니다.

 

1) Changed : 하위 디렉터리나 파일이 변결될 때 발생

2) Created   : 하위 디렉터리나 파일이 생성될 때 발생

3) Deleted   : 하위 디렉터리나 파일이 삭제될 때 발생

4) Renamed : 하위 디렉터리나 파일의 이름이 변경될 때 발생

 

다음 처럼 4개의 이벤트를 간단히 연결 하도록 합니다.

 private void fileSystemWatcher1_Changed(object sender, System.IO.FileSystemEventArgs e)
 {
      MessageBox.Show("변경");
 }

 private void fileSystemWatcher1_Created(object sender, System.IO.FileSystemEventArgs e)
 {
      MessageBox.Show("생성");
 }

 private void fileSystemWatcher1_Deleted(object sender, System.IO.FileSystemEventArgs e)
 {
      MessageBox.Show("삭제");
 }

 private void fileSystemWatcher1_Renamed(object sender, System.IO.RenamedEventArgs e)
 {
      MessageBox.Show("이름변경");
 }

 

이제 작업이 완료 되었습니다정말 초 간단하지요...

프로그램을 실행시킨 후 윈도우 탐색기를 통해 Directory1 폴더를 조작해 보세요...

상황에 맞는 메시지 창이 뜰 것입니다.

 

지금 까지 알아본 것은 FileSystemWatcher 컴포넌트의 기본적인 사용법에 대해 알아 보았습니다.

이제 조금더 자세히 알아 보도록 하겠습니다

 

 

하위 디렉터리 감시

FileSystemWatcher 에는 IncludeSubdirectories 라는 boolean 속성이 있습니다.

이 속성은 기본 값이 거짓(false) 입니다.

 Path 로 설정된 디렉터리의 하위 디렉터리의 감시를 하지 않겠다는 의미가 됩니다.

이 의미는 약간의 혼동의 소지가 있습니다.

 

다음 구조 처럼 Directory1 하위에 Directory1-1 이라는 디렉터리가 있다고 할때,

--Directory1

         --Directory1-1

 

FileSystemWatcher  Path = Directory1 으로 설정되고 IncludeSubdirectories = false 로 설정된다면

Directory1-1 디렉터리는 감시하지 않겠다는 의미가 됩니다.

 Directory1-1 하위에 또 다른 디렉터리나 파일이 생성되거나 삭제 , 이름 변경 따위를 보고 받지 않게 되는 것입니다.

 

그러나 Directory1-1 역시 Directory1에 포함된 디렉터리이므로 변경 사항은 감지 됩니다.

다시 말해, Directory1-1 디렉터리에 새로운 파일을 생성하거나,삭제하거나,이름변경하는 행위는 결국

Directory1-1 디렉터리의 변경을 의미합니다.

따라서 생성,삭제,이름변경 이벤트는 발생하지 않지만 변경(Changed) 이벤트는 여전히 발생하는 것입니다.

 

만일, IncludeSubdirectories = true 로 속성을 변경 한다면 이벤트는 중복해서 모두 발생합니다.

 Directory1-1 에 파일을 추가하면 '변경 -> 생성' 순으로 이벤트가 두 번 발생하게 됩니다.

 

간단히 정리 해 보겠습니다.

1) IncludeSubdirectories = false , Directory1-1에 파일 생성할 경우

    Directory1-1 디렉터리가 변경되었다는 이벤트 발생

2) IncludeSubdirectories = true , Directory1-1에 파일 생성할 경우

    Directory1-1 디렉터리가 변경되었다는 이벤트 발생 + Directory1-1 에 새로운 파일이 추가 되었다는 이벤트 발생

 

 

필터링

 

1. Filter 속성 (대상 파일 필터링)

기본 값 : *.*

 

FileSystemWatcher  컴포넌트의 Path 속성은 파일명이 아닌 디렉터리 명을 설정하도록 되어 있습니다.

그렇다면 특정 파일을 감시하고 싶을 경우에는 어떻게 해야 할까요?

 

이를 위해 FileSystemWatcher 는 Filter 속성을 제공합니다.

Filter 속성은 감시할 파일의 이름과 확장자를 명시적으로 지정하도록 하는데요..

기본 값은 '*.*' 입니다디렉터리의 모든 파일을 감시하겠다는 것입니다.

 

만일 우리가 Directory1 에 있는 file1.txt 만 감시하고 싶다면,

Filter = "file1.txt" 로 설정해 주시면 됩니다다음표는 msdn의 필터 문자열에 대한 설명입니다

 

 

2.NotifyFilter 속성 (변경 내용 필터링)

기본 값 : LastWrite, FileName, DirectoryName

 

앞서 설명드린 대로,FileSystemWatcher 컴포넌트는 설정한 디렉터리에 '생성,변경,삭제,이름변경에 대한

이벤트를 자동으로 발생 시켜 줍니다.

그러나 경우에 따라서는 이 조건과 더불에 특정한 상황만 모니터링 해야할 필요도 있을 수 있습니다.

 

예를 들어Directory1 디렉터리의 사이즈 변경만 모니터링 하고 싶은 경우가 그런 경우입니다.

사용자가 Directory1 에 빈 텍스트파일을 만든다면 '생성이벤트가 발생하기는 하지만 파일의 크기가 0 바이트이기

때문에 디렉터리의 사이즈가 변경된 것은 아닙니다.

 

이와같이 0바이티 크기의 파일 생성과 같은 이벤트는 알고 싶지 않고

바이트 이상의 파일이 새로 생성되거나 디렉터리 사이트가 변경될 때만 감지하고 싶다면

NotifyFilter 속성을 사용하셔야 합니다.

 

NotifyFilter = NotifyFilters.Size 로 설정하게 되면 0 바이트 파일 생성은 보고하지 않습니다.

다만 디렉터리에 사이즈를 변경할 만한 상황이 발생되면 보고할 뿐입니다.

 

이 속성은 NotifyFilters 라는 열거형(enum) 값을 나타냅니다.

NotifyFilters 열거형은 [FlagsAttribute] 특성을 가진 열거형이므로 열거형 값들을 비트로 조합할 수 있습니다.

즉 NotifyFilter = NotifyFilters.Size | NotifyFilters.DirectoryName 과 같이 두 개 이상의 값을 지정할 수 있는 것입니다.

 

다음 표는 NotifyFilters 열거형 값의 설명입니다.  

 

 

 

이벤트 정보

FileSystemWatcher  4가지 이벤트(Changed,Created,Deleted,Renamed) 는 이벤트 발생 시

추가 데이터 제공을 위해 EventArgument 를 제공합니다.

 

1. FileSystemEventArgs 매개변수

 Argument Created,Changed,Deleted 세 이벤트에 모두 사용되는 매개변수입니다.

파일 시스템의 생성,삭제,변경 이벤트 발생 시 추가 데이터를 제공하는 객체로써,

다음과 같은 추가 정보를 제공합니다.

 

a) ChangedType 속성

왜 이벤트가 발생했는지발생된 변경 유형을 알려 줍니다.

이 속성은 WatcherChangeTypes 열거형 값을 나타 냅니다.

 

b) FullPath 속성

영향 받은 파일 또는 디렉터리의 전체 경로를 나타냅니다

 

c) Name 속성

영향 받은 파일 또는 디렉터리의 이름을 나타냅니다

 

 

2. RenamedEventArgs 매개변수

FileSystemWatcher  Rename 이벤트는 다른 이벤트와는 달리 RenamedEventArgs  매개변수를 가집니다.

RenamedEventArgs 매개변수는 FileSystemEventArgs 매개변수가 제공하는 속성을 포함하여

다음과 같은 추가 정보를 제공해 줍니다.

 

a) OldFullPath : 이름이 변경되기 전 파일(디렉터리)의 경로

b) OldName     : 이름이 변경되기 전 파일(디렉터리)의 이름

 

 

고용량 시스템에서 파일 변경 시 고려사항

FileSystemWatcher 로 디렉터리를 감시할 때 중요한 주의사항이 있습니다.

이 컴포넌트는 디렉터리의 모든 변경 사항(생성,추가,삭제,정보변경 등)을 추적하고 이벤트를 발생시켜 줍니다.

그러나 대단히 많은 변경이 유발되는 시스템 환경에서는 그 변경 수 많큼 대단히 많은 이벤트가 발생될 것입니다.

MSDN 에서는 이러한 환경에 대한 주의점과 가이드라인을 제시해 줍니다.

http://msdn.microsoft.com/library/kor/default.asp?url=/library/KOR/vbcon/html/vbtbstroubleshootinguncpathnamesnotacceptedonnt4machines.asp

 

결과적으로 이벤트가 발생하는 속도가 이 컴포넌트의 이벤트 수신 속도를 초과하게 되면 내부 버퍼에 추가 발생된

이벤트 정보를 저장하게 됩니다모든 버퍼가 그렇듯이 버퍼에는 정해진 용량이 있고 그 용량을 초과하면

오버플로가 발생 할 수 있습니다.

즉 응용프로그램은 예외상황에 빠지게 될 수 있다는 것입니다.

 

MSDN 에서는 FileSystemWatcher  컴포넌트의  <?XML:NAMESPACE PREFIX = MSHelp NS = "http://msdn.microsoft.com/mshelp" /><?XML:NAMESPACE PREFIX = MSHelp />InternalBufferSize 속성을 통해 적절한 버퍼 크기를 설정하기를

권장합니다다음 문구는 msdn 발췌본 입니다.

"수신할 이벤트와 거의 비슷한 크기로 버퍼를 설정해야 합니다기본으로 버퍼 크기는 4KB로 설정되어 있습니다. 4KB 버퍼는 디렉터리에서 약 80개 파일의 변경 내용을 추적할 수 있습니다각 이벤트는 버퍼에서 16바이트를 차지하며 이벤트가 발생한 파일의 이름을 유니코드(각 문자 당 2바이트)로 저장하는 추가 바이트가 있습니다이 정보를 사용하여 버퍼 크기를 필요에 맞게 조정할 수 있습니다"

 

또한 적절한 버퍼 크기 설정과 더불어 다음 속성을 통한 적절한 필터링을 수행하기를 권장합니다.

?  NotifyFilter 속성을 사용하면 FileSystemWatcher 구성 요소로 하여금 모든 변경 내용을 찾도록 할 것인지 또는 감시하는 디렉터리 안에서 지정된 변경 내용만 찾도록 할 것인지를 지정할 수 있습니다.

?  IncludeSubdirectories 속성을 사용하면 감시하는 디렉터리의 하위 디렉터리를 포함할지 여부를 나타낼 수 있습니다이 기능을 사용하지 않는 경우에는 이 기능을 사용할 때보다 적은 이벤트를 받게 됩니다.

?  Changed 이벤트를 감시하도록 FileSystemWatcher 구성 요소를 설정한 경우 NotifyFilter 속성을 사용하여 필요한 이벤트만 지정할 수 있습니다.

?   

참고

Filter 속성을 사용하여 감시할 파일이나 하위 디렉터리를 지정할 수도 있지만이 속성은 버퍼에 변경이 추가된 후에 적용되므로 버퍼 크기가 전혀 줄어들지 않습니다. 대신 NotifyFilter 속성을 사용하면 버퍼에 기록되는 정보의 양을 제어할 수 있습니다.