FileSystemWatcher
을 사용하는 프로그램을 작성하고 OnCreated 또는 OnChanged 이벤트를 받으면 작성된/변경된 파일을 지정된 디렉터리에 복사합니다. 처음에는 OnChanged/OnCreated 이벤트를 두 번 보낼 수있는 문제 (500MB 파일을 처리해야 할 경우에는 허용되지 않음)와 관련하여 문제가 있었지만이 문제를 해결할 수있는 방법을 만들었고 실제로 차단 된 것은 다음과 같습니다. IOException
: 프로세스가 다른 프로세스에서 사용 중이므로 'C : \ Where are Photos \ bookmarks (11) .html'파일에 액세스 할 수 없습니다.C# 읽을 파일을 열 수 없습니다.
따라서 프로그램이 모든 파일을 복사하지 못하게해야합니다. 제가 언급했듯이, 사용자가이 프로그램을 사용하면 모니터링 된 디렉토리를 지정합니다. 사용자가 해당 디렉토리에서 파일을 복사/생성/변경하면 프로그램은 OnCreated/OnChanged 이벤트를 가져와 그 파일을 몇 개의 다른 디렉토리에 복사해야합니다. 위의 오류는 모든 경우에 발생합니다. 모니터링되는 폴더에서 다른 파일을 덮어 쓸 필요가있는 파일을 거의 복사하지 않거나 여러 파일을 대량으로 복사하거나 모니터링되는 디렉터리에서 파일 하나를 복사 할 때도 있습니다. 전체 프로그램이 상당히 크기 때문에 가장 중요한 부분을 보내고 있습니다. OnCreated :
private void OnCreated(object source, FileSystemEventArgs e) {
AddLogEntry(e.FullPath, "created", "");
// Update last access data if it's file so the same file doesn't
// get processed twice because of sending another event.
if (fileType(e.FullPath) == 2) {
lastPath = e.FullPath;
lastTime = DateTime.Now;
}
// serves no purpose now, it will be remove soon
string fileName = GetFileName(e.FullPath);
// copies file from source to few other directories
Copy(e.FullPath, fileName);
Console.WriteLine("OnCreated: " + e.FullPath);
}
는 onChanged :
private void OnChanged(object source, FileSystemEventArgs e) {
// is it directory
if (fileType(e.FullPath) == 1)
return; // don't mind directory changes itself
// Only if enough time has passed or if it's some other file
// because two events can be generated
int timeDiff = ((TimeSpan)(DateTime.Now - lastTime)).Seconds;
if ((timeDiff < minSecsDiff) && (e.FullPath.Equals(lastPath))) {
Console.WriteLine("-- skipped -- {0}, timediff: {1}", e.FullPath, timeDiff);
return;
}
// Update last access data for above to work
lastPath = e.FullPath;
lastTime = DateTime.Now;
// Only if size is changed, the rest will handle other handlers
if (e.ChangeType == WatcherChangeTypes.Changed) {
AddLogEntry(e.FullPath, "changed", "");
string fileName = GetFileName(e.FullPath);
Copy(e.FullPath, fileName);
Console.WriteLine("OnChanged: " + e.FullPath);
}
}
의 fileType :
private int fileType(string path) {
if (Directory.Exists(path))
return 1; // directory
else if (File.Exists(path))
return 2; // file
else
return 0;
}
복사 : 내 프로그램에서 모든 곳에서 확인하고
private void Copy(string srcPath, string fileName) {
foreach (string dstDirectoy in paths) {
string eventType = "copied";
string error = "noerror";
string path = "";
string dirPortion = "";
// in case directory needs to be made
if (srcPath.Length > fsw.Path.Length) {
path = srcPath.Substring(fsw.Path.Length,
srcPath.Length - fsw.Path.Length);
int pos = path.LastIndexOf('\\');
if (pos != -1)
dirPortion = path.Substring(0, pos);
}
if (fileType(srcPath) == 1) {
try {
Directory.CreateDirectory(dstDirectoy + path);
//Directory.CreateDirectory(dstDirectoy + fileName);
eventType = "created";
} catch (IOException e) {
eventType = "error";
error = e.Message;
}
} else {
try {
if (!overwriteFile && File.Exists(dstDirectoy + path))
continue;
// create new dir anyway even if it exists just to be sure
Directory.CreateDirectory(dstDirectoy + dirPortion);
// copy file from where event occured to all specified directories
using (FileStream fsin = new FileStream(srcPath, FileMode.Open, FileAccess.Read, FileShare.Read)) {
using (FileStream fsout = new FileStream(dstDirectoy + path, FileMode.Create, FileAccess.Write)) {
byte[] buffer = new byte[32768];
int bytesRead = -1;
while ((bytesRead = fsin.Read(buffer, 0, buffer.Length)) > 0)
fsout.Write(buffer, 0, bytesRead);
}
}
} catch (Exception e) {
if ((e is IOException) && (overwriteFile == false)) {
eventType = "skipped";
} else {
eventType = "error";
error = e.Message;
// attempt to find and kill the process locking the file.
// failed, miserably
System.Diagnostics.Process tool = new System.Diagnostics.Process();
tool.StartInfo.FileName = "handle.exe";
tool.StartInfo.Arguments = "\"" + srcPath + "\"";
tool.StartInfo.UseShellExecute = false;
tool.StartInfo.RedirectStandardOutput = true;
tool.Start();
tool.WaitForExit();
string outputTool = tool.StandardOutput.ReadToEnd();
string matchPattern = @"(?<=\s+pid:\s+)\b(\d+)\b(?=\s+)";
foreach (Match match in Regex.Matches(outputTool, matchPattern)) {
System.Diagnostics.Process.GetProcessById(int.Parse(match.Value)).Kill();
}
Console.WriteLine("ERROR: {0}: [ {1} ]", e.Message, srcPath);
}
}
}
AddLogEntry(dstDirectoy + path, eventType, error);
}
}
나는 일부 파일 I을 사용할 때마다 using
블록에서 사용하십시오. 로그에 이벤트를 쓰는 것조차 (내가 게시 한 코드가 너무 많으므로 생략했습니다) 파일을 잠그지 마십시오. 모든 작업이 using
문 블록을 사용하고 있으므로 안됩니다.
사용자가 Windows 나 다른 프로그램을 통해 내 프로그램 "복사"프로세스가 아니라면 파일을 잠그는 단서가 없습니다.
바로 지금 나는 두 가지 가능한 "솔루션"을 가지고 있습니다 (해킹 및 바람직하지 않은 솔루션이므로 깨끗한 솔루션이라고 할 수는 없습니다).
의 fileType :
private int fileType(string path) {
FileStream fs = null;
int ret = 0;
bool run = true;
if (Directory.Exists(path))
ret = 1;
else {
while (run) {
try {
fs = new FileStream(path, FileMode.Open);
ret = 2;
run = false;
} catch (IOException) {
} finally {
if (fs != null) {
fs.Close();
fs.Dispose();
}
}
}
}
return ret;
}
아마 때문에 문제 (? 다른 어떤 파일을 잠글 수) 내가 "차단-까지-바로 열기"동작을 시뮬레이션하기 위해,이로 변경 시도
fileType
방법입니다
이것은 (테스트) 말할 수있는만큼 효과가 있지만, 다른 결함은 말할 것도없고 해킹입니다.
내가 시도해 볼 수있는 다른 "솔루션"은 메서드의 끝에 어딘가에 GC.Collect()
을 사용하고 있습니다. 어쩌면 이전의 것보다 더 나쁜 "해결책"일 수도 있습니다.
누군가가 파일을 잠그고 그 파일을 열지 못하게하고 어떻게 해결할 수 있습니까? 나는 무엇을보고 싶니?
미리 감사드립니다.
빠른 응답을 위해 고맙지 만 쓰기 권한이 필요하지 않으므로 _read_ 권한이 필요합니다. 그래서 나는 그것을 읽고 다른 목적지로 복사 할 수 있습니다. – Maks
@Maks : 파일을 쓸 수 있으면 읽을 수도 있습니다. 예를 들어 글을 쓸 수 없으면 폴더가 보호되어 있기 때문에 파일을 읽기 전용으로 열려고 시도 할 수도 있습니다. –
내가 의미하는 바는 쓰기 권한 (쓰기 권한보다 가능성이 높음)이 쓰기 권한 (Windows 이벤트 (이벤트가 발생했을 때 완료되지 않았기 때문에)보다 Windows 프로세스 인 경우)입니다. – Maks