2013-05-14 64 views
14

Tôi gặp sự cố chia sẻ tệp khi quá trình của tôi đang cố gắng đọc tệp nhật ký trong khi vẫn đang mở NLog. Trong chẩn đoán vấn đề, tôi thấy một điều gì đó đáng ngạc nhiên. Sau đây thất bại:Chia sẻ tệp không hoạt động như mong đợi

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)) 
{ 
} 

Thứ hai FileStream gọi constructor không thành công với:

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) 

Điều này bất chấp thực tế rằng FileStream đầu tiên chỉ ra sự sẵn sàng của mình để chia sẻ đọc. Những gì tôi thấy thậm chí đáng ngạc nhiên hơn là công trình này:

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)) 
{ 
} 

Um, vâng, yêu cầu hơn truy cập khi mở dòng thứ hai thực sự bỏ qua vấn đề này. Tôi hoàn toàn bối rối về lý do tại sao đó là trường hợp, và chỉ có thể giả định tôi hiểu nhầm điều gì đó. Tôi đã đọc qua các tài liệu API nhưng họ chỉ hỗ trợ mô hình tinh thần hiện tại của tôi về cách thức hoạt động này, trái với cách nó hoạt động.

Dưới đây là một số dấu ngoặc kép hỗ trợ từ docs:

Một sử dụng điển hình của kiểu liệt kê này là để xác định xem liệu hai quá trình đồng thời có thể đọc từ cùng một tập tin. Ví dụ: nếu tệp được mở là và Đọc được chỉ định, những người dùng khác có thể mở tệp để đọc nhưng không thể ghi.

Dưới đây là đá quý khác:

Các constructor FileStream sau mở một tập tin hiện có và tài trợ truy cập chỉ đọc cho người khác (đọc).

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

bất cứ ai có thể rụng bất kỳ ánh sáng vào hành vi này. Tôi đang thử nghiệm này trên. NET 4% Windows XP.

Trả lời

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

Thao tác này sẽ lên rất nhiều lập trình viên. Mọi người giả định rằng đã thêm chia sẻ đọc này. Nó đã không, các yêu cầu truy cập tập tin ban đầu đã được phép đọc và xác định nó một lần nữa không thay đổi bất cứ điều gì. Thay vào đó, số từ chối chia sẻ ghi. Và điều đó không thể làm việc bởi vì ai đó đã có quyền ghi. Và đang sử dụng nó, bạn không thể loại bỏ quyền đó. Vì vậy, yêu cầu truy cập tệp của bạn sẽ không thành công.

Bạn phải bao gồm FileShare.Write.

+1

Cảm ơn. Vì vậy, sự hiểu lầm này là rất phổ biến mà ngay cả các tài liệu là sai/gây hiểu nhầm? –

+0

Bạn có nghĩa là bao gồm 'FileShare.Write' trên luồng thứ hai, phải không? – rookie1024

0

tham số thứ tư bạn vượt qua

phần
Một hằng số mà xác định cách các tập tin sẽ được chia sẻ bởi các quá trình.

xác định chế độ nào người khác có thể mở tệp. Vì vậy, rõ ràng - khi bạn đang cố gắng để mở tập tin với chế độ fileshare "đọc" và đã có cùng một tập tin mở trong chế độ ghi - hoạt động không thành công.

+0

Nó không phải thứ ba, thứ tư. Và 'FileShare.Read' _Cho phép mở tệp tiếp theo để đọc._ –

+0

xin lỗi, sửa lỗi :) – elevener

+0

FileShare.Read -" Cho phép mở tệp tiếp theo để đọc "- nhưng không phải để viết. Bạn đã mở tệp để ghi những gì bị cấm với chế độ chia sẻ đó. Chức năng nên làm gì? – elevener

1

Điều gì thực sự xảy ra, là fileStream2 không thể thay đổi quyền truy cập tiếp theo vào tệp đã được mở để viết (hoặc phụ thêm) theo số fileStream1.

fileStream2 sẽ mở thành công tệp để lại FileShare.Read là "cũ" để truy cập tiếp theo chỉ khi không có quy trình nào có quyền truy cập tệp Write vào đó. Thậm chí nhiều hơn, trong ví dụ của chúng tôi, chúng tôi đang nói về cùng một quá trình. Nó sẽ không làm cho quá nhiều ý nghĩa để sửa đổi các thuộc tính của một luồng tập tin từ một luồng tập tin khác, phải không?

Có lẽ sự so sánh sau đây giải thích nó thậm chí còn tốt hơn:

// 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)) 
{ 
} 

Theo tôi, cụm từ mô tả cho FileShare.Read:

Cho phép mở tiếp theo của tập tin để đọc.

cần được đọc như

Việc truy cập tiếp theo đến tập tin bị hạn chế chỉ cho đọc, bao gồm truy cập ổ khóa đã tồn tại.

[Cập nhật]

tôi đã không phân tích cú pháp thông qua các mã, nhưng có vẻ như hai liên kết này có thể làm sáng tỏ qua các hoạt động nội bộ của các nhà xây dựng:

The internal FileStream ctor

The internal FileStream Init method

+0

Vẫn chưa nhấp, mặc dù đọc câu trả lời của bạn nhiều lần. Tôi thấy khó tin rằng tài liệu API hoàn toàn sai và hoàn toàn sai. ví dụ. "Ví dụ: nếu một tệp được mở và' Đọc' được chỉ định, những người dùng khác có thể mở tệp để đọc chứ không phải để ghi. " Đó là chính xác những gì tôi đã cố gắng làm trong ví dụ của tôi, nhưng nó không hoạt động. –

+0

@KentBoogaart: Tôi không biết liệu nó có liên quan không (tôi cũng không hiểu) nhưng cụm từ khóa có thể là "những người dùng khác". Một thử nghiệm tốt hơn về "những người dùng khác" sẽ là trong một thử nghiệm đa luồng. – Chris

+0

@Chris: kịch bản thực sự của tôi là đa luồng (cố gắng thu thập nhật ký trên chuỗi chẩn đoán nền). Ngoài ra, các tài liệu nêu rõ "bằng quy trình này hoặc một quy trình khác" khi mô tả hành vi chia sẻ. –

1

Tôi nghĩ rằng tôi đã tìm thấy câu trả lời trong tài liệu cho CreateFile.

Trong các cuộc thảo luận của tham số dwShareMode, nó nói:

FILE_SHARE_READ 0x00000001 phép hoạt động mở tiếp theo trên một tập tin hoặc điện thoại yêu cầu đọc truy cập. Nếu không, các quy trình khác không thể mở tệp hoặc thiết bị nếu chúng yêu cầu quyền truy cập đọc. Nếu cờ này không được chỉ định, nhưng tệp hoặc thiết bị đã được mở để truy cập đọc, chức năng không thành công.

FILE_SHARE_WRITE 0x00000002 Bật hoạt động mở tiếp theo trên tệp hoặc thiết bị để yêu cầu quyền ghi. Nếu không, các quy trình khác không thể mở tệp hoặc thiết bị nếu chúng yêu cầu quyền ghi. Nếu cờ này không được chỉ định, nhưng tệp hoặc thiết bị đã được mở để truy cập ghi hoặc có ánh xạ tệp có quyền ghi, chức năng không thành công.

Điều đó về cơ bản thay đổi hiểu biết của tôi về cách hoạt động của tính năng chia sẻ tệp.

Các vấn đề liên quan