Tôi đang làm việc trên phần mềm máy chủ định kỳ cần lưu dữ liệu vào đĩa. Tôi cần đảm bảo rằng tệp cũ bị ghi đè và tệp không thể bị hỏng (ví dụ: chỉ ghi đè một phần) trong trường hợp các trường hợp bất ngờ.Lưu tập tin đáng tin cậy (File.Replace) trong môi trường bận rộn
tôi đã áp dụng mô hình sau:
string tempFileName = Path.GetTempFileName();
// ...write out the data to temporary file...
MoveOrReplaceFile(tempFileName, fileName);
... nơi MoveOrReplaceFile là:
public static void MoveOrReplaceFile(string source, string destination) {
if (source == null) throw new ArgumentNullException("source");
if (destination == null) throw new ArgumentNullException("destination");
if (File.Exists(destination)) {
// File.Replace does not work across volumes
if (Path.GetPathRoot(Path.GetFullPath(source)) == Path.GetPathRoot(Path.GetFullPath(destination))) {
File.Replace(source, destination, null, true);
} else {
File.Copy(source, destination, true);
}
} else {
File.Move(source, destination);
}
}
này hoạt động tốt miễn là máy chủ có quyền truy cập độc quyền cho tập tin. Tuy nhiên, File.Replace có vẻ rất nhạy cảm với việc truy cập bên ngoài vào các tệp. Bất cứ khi nào phần mềm của tôi chạy trên hệ thống có chống vi-rút hoặc hệ thống sao lưu theo thời gian thực, các lỗi File.Replace ngẫu nhiên bắt đầu xuất hiện:
System.IO.IOException: Không thể xóa tệp cần thay thế.
Dưới đây là một số nguyên nhân có thể là tôi đã loại bỏ:
- tập tin chưa được phát hành xử lý: using() đảm bảo rằng tất cả các xử lý tập tin được phát hành càng sớm càng tốt.
- Sự cố luồng: khóa() bảo vệ tất cả quyền truy cập vào từng tệp.
- Ổ đĩa khác nhau: Tệp.Replace() không thành công khi được sử dụng trên ổ đĩa. Phương pháp của tôi kiểm tra điều này và quay trở lại File.Copy().
Và đây là một số gợi ý mà tôi đã đi qua, và tại sao tôi không muốn sử dụng chúng:
- Volume Shadow Copy Service: Đây chỉ hoạt động miễn là ba vấn đề phần mềm -party (màn hình sao lưu và chống virus, vv) cũng sử dụng VSS. Sử dụng VSS yêu cầu tấn P/Invoke và có các vấn đề cụ thể cho nền tảng.
- Khóa tệp: Trong C#, việc khóa tệp yêu cầu duy trì mở tệp FileStream. Nó sẽ giữ phần mềm của bên thứ ba ra, nhưng 1) Tôi vẫn sẽ không thể thay thế tệp bằng File.Replace và 2) Như tôi đã đề cập ở trên, tôi muốn ghi vào tệp tạm thời trước để tránh tình cờ tham nhũng.
Tôi đánh giá cao bất kỳ đầu vào nào khi nhận tệp.Replace để làm việc mọi lúc hoặc, nói chung, lưu/ghi đè tệp trên đĩa một cách đáng tin cậy.
Bạn có mong đợi 'MoveOrReplaceFile' được chạy đồng thời (có nghĩa là truy cập bởi nhiều chủ đề * ứng dụng * của bạn hoặc thậm chí từ nhiều phiên bản ứng dụng của bạn)? –
Mã của riêng tôi không bao giờ gọi MoveOrReplaceFile đồng thời, nhưng có các quy trình khác ngoài tầm kiểm soát của tôi có thể tìm cách đọc tệp. Những truy cập đọc ngẫu nhiên này là nguyên nhân khiến File.Replace thất bại. – matvei