2013-05-14 4 views
14

NLog에서 내 프로세스가 로그 파일을 읽는 동안 로그 파일을 읽는 파일 공유 문제가 있습니다. 문제를 진단 할 때 놀라운 것을 발견했습니다. 다음은 실패파일 공유가 예상대로 작동하지 않습니다.

System.IO.IOException was unhandled 
    Message=The process cannot access the file 'c:\...\test.file' because it is being used by another process. 
    Source=mscorlib 
    StackTrace: 
     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, Boolean useLongPath) 
     at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share) 

이 처음 FileStream 독서를 공유하는 의지를 나타낸다는 사실에도 불구하고 :

using (var fileStream1 = new FileStream("test.file", FileMode.Append, FileAccess.Write, FileShare.Read)) 
using (var fileStream2 = new FileStream("test.file", FileMode.Open, FileAccess.Read, FileShare.Read)) 
{ 
} 

두 번째 FileStream 생성자 호출은 실패합니다.

using (var fileStream1 = new FileStream("test.file", FileMode.Append, FileAccess.Write, FileShare.Read)) 
using (var fileStream2 = new FileStream("test.file", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 
{ 
} 

음, 그래, 두 번째 스트림이 실제로 문제를 우회 열 때 액세스를 요청 : 내가 더 놀라운 발견 한 것은이 작품이었다. 나는 그것이 왜 그런지에 대해 완전히 당혹스럽고, 단지 내가 오해하고 있다고 가정 할 수 있습니다. 필자는 API 문서를 읽었지만 어떻게 작동해야하는지에 대한 현재의 정신 모델을 지원합니다.

열거의 전형적인 사용 두 프로세스가 동시에 동일한 파일로부터 판독 할 수 있는지 여부를 정의 할 수있다 :

여기에 docs 일부지지 인용된다. 예를 들어 파일이 이고 읽음이 지정된 경우 다른 사용자는 이라는 파일을 열어 볼 수는 있지만 쓰기는 할 수 없습니다.

는 여기에 또 다른 보석이다 :

다음 파일 스트림 생성자는 기존 파일과 보조금을 다른 사용자 (읽기)에 는 읽기 전용 액세스를 엽니 다.

FileStream s2 = new FileStream(name, FileMode.Open, FileAccess.Read, FileShare.Read);

사람은이 동작에 어떤 빛을 창고 수 있습니다. 나는 이것을 .NET 4 % Windows XP에서 테스트하고 있습니다.

답변

15
var fileStream2 = new FileStream(..., FileShare.Read) 

이것은 많은 프로그래머를 이동시킵니다. 모두가 읽기 공유를 추가했다고 가정합니다. 실제로 읽지 못했던 원래 파일 액세스 요청은 다시 변경되지 않으며 아무 것도 변경하지 않습니다. 대신 쓰기 공유를 거부합니다. 그리고 누군가는 이미 쓰기 권한을 가지고 있기 때문에 작동하지 않습니다. 그리고 그것을 사용하고 있습니다, 당신은 그 권리를 제거 할 수 없습니다. 따라서 파일 액세스 요청이 실패합니다.

이어야하며 FileShare.Write를 포함해야합니다.

+1

감사합니다. 따라서 오해가 너무 커서 문서가 잘못되었거나 오도 된 것일 수 있습니다. –

+0

두 번째 스트림에는'FileShare.Write'가 포함됩니다. – rookie1024

0

네 번째 매개 변수는


파일이 프로세스에 의해 공유되는 방법을 결정하는 상수를 전달합니다.

은 다른 사용자가 파일을 열 수있는 모드를 결정합니다. 그래서 분명히 - 파일 공유 모드가 "읽기"이고 파일이 이미 쓰기 모드에서 열려있는 상태에서 파일을 열려고 할 때 작업이 실패합니다.

+0

3 위가 아니며 4 위입니다. 그리고'FileShare.Read' _ 후속으로 파일 읽기를 허용합니다. _ –

+0

죄송합니다. 수정 됨 : – elevener

+0

FileShare.Read - "파일 읽기를 허용합니다."- 그러나 쓰기는 허용하지 않습니다. 해당 공유 모드로 금지 된 것을 작성하기 위해 이미 파일을 열었습니다. 함수는 무엇을해야합니까? – elevener

1

실제로는 fileStream2이 이미 쓰기 (또는 추가)를 위해 열려있는 파일에 대한 후속 액세스를 fileStream1으로 변경할 수 없습니다.

fileStream2 성공적으로 이미에 Write 파일 액세스 권한이없는 프로세스가없는 경우에만 후속 액세스에 대한 "유산"으로 FileShare.Read을 떠나는 파일을 엽니 다. 더군다나, 우리의 예에서 우리는 같은 과정을 이야기하고 있습니다. 다른 파일 스트림에서 파일 스트림의 속성을 수정하는 것은 너무 많은 의미가 있습니다. 그렇지 않습니까?

아마 다음과 같은 비교도 더 잘 설명 : 제 생각에는

// works 
using (var fileStream1 = new FileStream("test.file", FileMode.OpenOrCreate, FileAccess.Read, FileShare.ReadWrite)) 
using (var fileStream2 = new FileStream("test.file", FileMode.Append, FileAccess.Write, FileShare.Read)) 
using (var fileStream3 = new FileStream("test.file", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 
{ 
} 

// fails 
using (var fileStream1 = new FileStream("test.file", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite)) 
using (var fileStream2 = new FileStream("test.file", FileMode.Append, FileAccess.Write, FileShare.Read)) 
using (var fileStream3 = new FileStream("test.file", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 
{ 
} 

, 설명 문구를 FileShare.Read을 위해 :

읽기에 대한 파일의 이후 개방을 할 수 있습니다.

파일에 대한 후속 액세스로 읽어야은 기존의 잠금 장치의 액세스를 포함하여, 을 읽기 위해 제한됩니다.

[업데이트]

나는 코드를 구문 분석되지 않은,하지만이 두 링크가 생성자의 내부 기능을 통해 되거 수 있음을 보인다

The internal FileStream ctor

The internal FileStream Init method

+0

답을 여러 번 읽었음에도 불구하고 아직 클릭하지 않았습니다. 나는 API 문서가 너무 완전하고 완전히 틀렸다는 것을 믿기 어렵다. 예. "예를 들어, 파일이 열리고'Read'가 지정되면, 다른 사용자는 파일을 열어서 읽을 수는 있지만 쓸 수는 없습니다." 그게 내 예제에서 시도한 것이지만 작동하지 않습니다. –

+0

@KentBoogaart : 관련성이 있는지는 잘 모르겠지만 (필자도 이해가 안되지만) 핵심 구는 "다른 사용자"일 수 있습니다. "다른 사용자"에 대한 더 나은 테스트는 멀티 스레드 테스트에 있습니다. – Chris

+0

@Chris : 내 실제 시나리오는 멀티 스레드 (백그라운드 진단 스레드에서 로그를 수집하려고 시도 중)입니다. 또한 문서는 공유 동작을 설명 할 때 명시 적으로 "이 프로세스 또는 다른 프로세스별로"라고 명시합니다. –

1

CreateFile에 대한 설명서에서 대답을 찾은 것 같습니다. dwShareMode 매개 변수의 논의에서

, 그것은 말한다 :

FILE_SHARE_READ 0x00000001 는 읽기 액세스를 요청하는 파일이나 장치에서 연속되는 열기 연산을 가능하게합니다. 그렇지 않으면 다른 프로세스에서 파일이나 장치가 읽기 액세스를 요청하면 해당 프로세스를 열 수 없습니다. 이 플래그가 지정되지 않았지만 파일이나 장치가 읽기 액세스를 위해 열린 경우, 함수는 실패합니다.

FILE_SHARE_WRITE 0x00000002 파일 또는 기록 액세스를 요청하는 디바이스에 후속 개방 동작을 가능. 그렇지 않으면 다른 프로세스가 쓰기 액세스를 요청하면 파일이나 장치를 열 수 없습니다. 이 플래그를 지정하지 않았지만 파일이나 장치가 쓰기 액세스를 위해 열렸거나 쓰기 액세스 권한이있는 파일 매핑이있는 경우이 함수는 실패합니다. 근본적 방법 파일 공유 작품에 대한 이해를 변경

.

관련 문제