2014-10-15 2 views
3

2 개의 프로그램 : C# GUI 응용 프로그램과 동일한 텍스트 파일에 액세스하는 C# Windows 서비스.이 프로세스는 스트림 작성기를 사용하는 다른 프로세스에서 사용 중이기 때문에 파일에 액세스 할 수 없습니다.

2014/09/08 21:15:56 mscorlib 
The process cannot access the file 'C:\09082014.log' because it is being used by another process. 
    at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) 
    at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy) 
    at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options) 
    at System.IO.StreamWriter.CreateFile(String path, Boolean append) 
    at System.IO.StreamWriter..ctor(String path, Boolean append, Encoding encoding, Int32 bufferSize) 
    at System.IO.StreamWriter..ctor(String path, Boolean append) 
    at DataloggerUI.DataHelper.WriteDataLog(String msg, Int64& downTimeSince) 
    at DataloggerUI.Form1.ReceiveData(IAsyncResult asyncResult) 

----는 C# 윈도우 서비스 부분 ----------

다음과 같다 : 작업이 동시에 발생하는 경우

a) the C# GUI application will write/append to the text file 
b) the windows service will copy the file to a network location every 20 mins. 

, 나는 오류 메시지가 아래와 같이 있어요

if (File.Exists(destination + @"\" + fi.Name)) 
      { 
       FileInfo fi_dest = new FileInfo(destination + @"\" + fi.Name); 
       if (fi.LastWriteTime > fi_dest.LastWriteTime) 
       { 
        File.Copy(fi.FullName, destination + @"\" + fi.Name, true); 
        WriteLog("Send " + fi.FullName + " to server"); 
       } 
      } 
      else 
      { 
       File.Copy(fi.FullName, destination + @"\" + fi.Name, true); 
       WriteLog("Send " + fi.FullName + " to server"); 
      } 
} 

-------는 C# 윈도우 GUI 응용 프로그램 코드처럼 아래 -------

string logfile = DataHelper.GetAppConfigString("MPRS_LogDir") + @"\" + DateTime.Now.ToString("MMddyyyy") + ".log"; 
    using (StreamWriter sw = new StreamWriter(logfile, true)) 
    { 
     sw.WriteLine(tick + " " + "KYEC" + Environment.MachineName + " " + msg); 
     sw.Close(); 
    } 

GUI 응용 프로그램에서 오류 메시지가 표시됩니다. 코드에 오류가 있습니까?

은 ------------ 피터의 조언에 따라, 다음에 수정 된 코드 --------------

try 
    { 
     using (StreamWriter sw = new StreamWriter(logfile, true)) 
     { 
      sw.WriteLine(tick + " " + "KYEC" + Environment.MachineName + " " + msg); 
     } 
    } 
    catch (IOException ex) 
    { 
     WriteErrorLog("IOException " + ex.Message); 
     System.Threading.Thread.Sleep(2000); //2 secs     
     using (StreamWriter sw = new StreamWriter(logfile, true)) 
     { 
      sw.WriteLine(tick + " " + "KYEC" + Environment.MachineName + " " + msg); 
     } 
    } 
+0

windows-service는 파일 복사 시작시기를 어떻게 결정합니까? 절차를 설명하거나 더 많은 코드를 보여주십시오. –

+0

오류는 파일이 사용 중임을 나타냅니다. 그 것이었다? 아마 GUI가 다른 것을 추가하고 싶을 때 복사되고있을 것입니다. – luk32

+0

안녕하세요 luk32 예, Windows 서비스가 어딘가에 복사하려고 시도하는 동안 GUI가 파일에 추가 할 때 오류가 발생했습니다. 어떻게 든이 예외를 피할 수 있습니까? 파일을 추가하기 전에 사용 중인지 여부를 감지하는 것과 같습니까? 또한 C# 'using'문에 의해 예외가 이미 처리됩니까? – sqr

답변

3

Peter Duniho's answer하고 자신의 편집을 바탕으로이 올바른 접근해야한다 :

// try to write maximum of 3 times 
var maxRetry = 3; 
for (int retry = 0; retry < maxRetry; retry++) 
{ 
    try 
    { 
     using (StreamWriter sw = new StreamWriter(logfile, true)) 
     { 
      sw.WriteLine("{0} KYEC{1} {2}", tick, Environment.MachineName, msg); 

      break; // you were successfull so leave the retry loop 
     } 
    } 
    catch (IOException) 
    { 
     if(retry < maxRetry - 1) 
     { 
      System.Threading.Thread.Sleep(2000); // Wait some time before retry (2 secs) 
     } 
     else 
     { 
      // handle unsuccessfull write attempts or just ignore. 
     } 
    } 
} 

이 당신이 쓰기 시도를 재 시도 할 기간을 지정할 수있는 기회를 제공합니다.

+0

감사합니다. 당신은 나에게 올바른 코드뿐만 아니라 우아하고 견고한 코드를 보여주었습니다. – sqr

1

당신은 적어도이 몇 가지 옵션이 있습니다. 가장 단순한 개념은 파일 입출력을 try/catch에 랩핑하고 IOException이 발생하면 (IOException이 발생하는 경우에만) 작업을 잠시 지연 (예 : Thread.Sleep(), 타이머 설정) 한 다음 다시 시도하십시오 .

다른 접근 방법은 명명 된 뮤텍스를 사용하여 서비스와 GUI 프로세스가 액세스를 조정할 수있게하는 것입니다. 각각은 각각의 연산을 시도하기 전에 뮤텍스를 획득합니다. 다른 파일이 현재 파일에 액세스 중이면 뮤텍스를 얻으려고하면 다른 프로세스가 완료 될 때까지 프로세스가 대기하게됩니다.

재시도 코드는 때때로 혼란과 자세한 얻을 수 있습니다 내가 뮤텍스의 접근 방식은 올바른 (당신이 문제에 간 한 번에 얻을 실제로 읽기 쉽고 간단 IMHO, 재시도 접근 방식은 이해하기 쉽게 생각하면서 이렇게 명명 된 뮤텍스 및 hellip을 만드는 방법을 배우고 어렵지 않으며 MSDN에 예제가 있습니다.

+0

안녕 피터, 고마워. 아래 코드를 try/catch 블록으로 변환 하시겠습니까? (StreamWriter sw = 새 StreamWriter (로그 파일, true)) { sw.WriteLine (tick + ""+ "KYEC"+ Environment.MachineName + ""+ msg); sw.Close(); } – sqr

+0

http://tackoverflow.com/questions/4590490/try-catch-using-right-syntax @Peter Duniho : 지금 바로 위의 링크를 읽었습니다. 나는 항상 'using'키워드가 try/catch와 동등하다고 믿고 있었다. 나는 그것이 틀렸다고 생각한다. using 문은 streamwriter 생성자를 호출하여 발생하는 예외를 catch하지 않습니다. 그래서 내가 다음으로 변경해야합니다 이 시도 {사용 을 (var에 인 myObject = 새로운 MyClass에()) { // 뭔가 여기 ... } } 캐치 (예외 예) { // 예외 처리 } – sqr

+0

전체 코드 블록을 try/catch로 래핑한다는 의미입니다. 어쨌든 일반적으로 모든 I/O 코드에 대한 좋은 아이디어입니다. I/O는 거의 항상 예외를 throw 할 가능성이 있으므로 .NET에 그대로두기보다는 프로그램이 원하는 경우 수행 할 작업을 생각할 시간이 필요합니다. 위에서 언급 한 토론과 관련하여이 예제에서는 "new StreamWriter ..."표현식이 예외를 throw 할 수 있기 때문에 전체 "사용 중"블록이 try/catch 블록에 완전히 포함되기를 원합니다.). –

5

공유 읽기 쓰기 모드에서 FileStream을 사용하여 파일을 동시에 쓰고 복사 할 수 있습니다. 다른 프로세스 에러에 의해 사용되는없이 작업을 달성 할 수있는이 방법

//To write file use 
    using (FileStream fs = new FileStream(fileToReadPath, FileMode.Append, FileAccess.Write, FileShare.ReadWrite)) 
    { 
     using (StreamWriter StreamWriter = new StreamWriter(fs)) 
     { 
      StreamWriter.WriteLine(tick + " " + "KYEC" + Environment.MachineName + " " + msg); 
      StreamWriter.Close(); 
     } 
    } 

//To copy file use 
    using (FileStream inStream = new FileStream(fileToReadPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 
    { 
     using (FileStream outStream = File.Create(fileToWritePath)) 
     { 
      while (inStream.Position < inStream.Length) 
      { 
       outStream.WriteByte((byte)inStream.ReadByte()); 
      } 
     } 
    } 

:

은 아래 코드를 사용해보십시오.

+0

나에게 조금 설명해 주시겠습니까? 감사. – sqr

+0

다른 프로세스가 동시에 읽기/쓰기를 할 수 없도록 파일을 잠근 동안 복사 중입니다. 그래서 내가 가진 예제는 여러 프로세스가 동시에 파일을 읽고 쓸 수있는 ReadWrite FileShare를 사용합니다. 따라서 File.Copy를 사용하여 파일을 복사하는 대신이 기술을 사용하여 파일 내용을 복사 할 수 있습니다. 설명을 주신 덕분에 – prem

+0

! 질문이 하나 더 있습니다.이 문제를 해결하려면 두 응용 프로그램 모두에서 FIleShare를 구현해야합니까? – sqr