2008-11-25 5 views
10

Tôi cần tạo một bộ xử lý tệp mới để mọi thao tác ghi vào xử lý đó được ghi vào đĩa ngay lập tức.Win32: Ghi vào tệp mà không bị giật?

Thông tin bổ sung: Tay cầm sẽ là STDOUT được thừa kế của một tiến trình con, vì vậy tôi cần bất kỳ đầu ra nào từ quy trình đó để ghi ngay vào đĩa.

Nghiên cứu các tài liệu CreateFile, cờ FILE_FLAG_WRITE_THROUGH trông giống như chính xác những gì tôi cần:

Viết hoạt động sẽ không đi qua bất kỳ bộ nhớ cache trung gian, họ sẽ đi trực tiếp vào đĩa.

Tôi đã viết một chương trình thử nghiệm rất cơ bản và, tốt, nó không hoạt động. Tôi đã sử dụng cờ trên CreateFile sau đó sử dụng WriteFile(myHandle,...) trong một vòng lặp dài, viết khoảng 100MB dữ liệu trong khoảng 15 giây. (Tôi đã thêm một số Sleep() 's).

Sau đó tôi thiết lập môi trường giám sát chuyên nghiệp bao gồm liên tục nhấn 'F5' trong trình khám phá. Kết quả: tệp ở 0kB sau đó nhảy tới 100MB về thời gian chương trình thử nghiệm kết thúc.

Điều tiếp theo tôi đã thử là xóa thủ công tệp sau mỗi lần viết, với FlushFileBuffers(myHandle). Điều này làm cho kích thước tập tin quan sát phát triển tốt đẹp và ổn định, như mong đợi.

Câu hỏi của tôi là, sau đó, không nên FILE_FLAG_WRITE_THROUGH đã thực hiện việc này mà không cần xóa tệp thủ công? Tui bỏ lỡ điều gì vậy? Trong chương trình 'thế giới thực', tôi không thể xóa tệp, vì tôi không có bất kỳ sự kiểm soát nào đối với tiến trình con đang sử dụng nó.

Ngoài ra còn có cờ FILE_FLAG_NO_BUFFERING, tôi không thể sử dụng cùng lý do - không kiểm soát quá trình đang sử dụng tay cầm, vì vậy tôi không thể căn chỉnh viết theo cách thủ công theo cờ này.

EDIT: Tôi đã tạo một dự án riêng biệt để xem cách kích thước của tệp thay đổi. Nó sử dụng lớp .NET FileSystemWatcher. Tôi cũng viết ít dữ liệu hơn - tổng cộng khoảng 100kB.

Đây là đầu ra. Kiểm tra các giây trong dấu thời gian.

Các 'được xây dựng trong không-đệm' phiên bản:

25.11.2008 7:03:22 PM: 10230 bytes added. 
25.11.2008 7:03:31 PM: 10240 bytes added. 
25.11.2008 7:03:31 PM: 10240 bytes added. 
25.11.2008 7:03:31 PM: 10240 bytes added. 
25.11.2008 7:03:31 PM: 10200 bytes added. 
25.11.2008 7:03:42 PM: 10240 bytes added. 
25.11.2008 7:03:42 PM: 10240 bytes added. 
25.11.2008 7:03:42 PM: 10240 bytes added. 
25.11.2008 7:03:42 PM: 10240 bytes added. 
25.11.2008 7:03:42 PM: 10190 bytes added. 

... và 'buộc (thủ công) tuôn ra' phiên bản (FlushFileBuffers() được gọi mỗi ~ 2,5 giây):

25.11.2008 7:06:10 PM: 10230 bytes added. 
25.11.2008 7:06:12 PM: 10230 bytes added. 
25.11.2008 7:06:15 PM: 10230 bytes added. 
25.11.2008 7:06:17 PM: 10230 bytes added. 
25.11.2008 7:06:19 PM: 10230 bytes added. 
25.11.2008 7:06:21 PM: 10230 bytes added. 
25.11.2008 7:06:23 PM: 10230 bytes added. 
25.11.2008 7:06:25 PM: 10230 bytes added. 
25.11.2008 7:06:27 PM: 10230 bytes added. 
25.11.2008 7:06:29 PM: 10230 bytes added. 
+0

tại sao bạn nghĩ bạn cần điều này? – Tim

+1

+1 cho 'trình khám phá chuyên nghiệp + F5'. Nhưng tôi phải nhắc bạn rằng khả năng hiển thị trong cùng một hệ thống op không có nghĩa là 'xả/độ bền'. Bạn phải hành động chuyên nghiệp hơn: hoặc đặt lại PC hoặc giải nén ổ cứng khỏi hệ thống. Tôi không chắc chắn rằng thiết lập lại hoặc tắt nguồn sẽ không bắt đầu xả bộ nhớ đệm trên bo mạch. Chỉ khi bạn loại bỏ ổ đĩa vật lý, hoặc sử dụng một số lưu trữ giả, bạn có thể chắc chắn rằng xả nước đã đạt đến thiết bị thực sự. – Val

+0

@RecognizeEvilasWaste hmm ... chúng ta hãy xem nếu nó wor –

Trả lời

11

Tôi đã bị cắn bởi điều này, quá, trong bối cảnh khai thác gỗ.

FILE_FLAG_WRITE_THROUGH chỉ đảm bảo rằng dữ liệu bạn đang gửi được gửi đến hệ thống tệp trước khi trả lại WriteFile; nó không đảm bảo rằng nó thực sự được gửi đến thiết bị vật lý. Vì vậy, ví dụ, nếu bạn thực hiện một ReadFile sau một WriteFile trên một tay cầm với lá cờ này, bạn được đảm bảo rằng đọc sẽ trả về các byte bạn đã viết, cho dù nó có dữ liệu từ bộ đệm hệ thống tập tin hoặc từ thiết bị cơ bản.

Nếu bạn muốn đảm bảo rằng dữ liệu đã được ghi vào thiết bị, thì bạn cần FILE_FLAG_NO_BUFFERING, với tất cả công việc phụ của người tiếp viên. Những người viết phải được liên kết, ví dụ, bởi vì bộ đệm là đi tất cả các con đường xuống trình điều khiển thiết bị trước khi trở về.

Cơ sở kiến ​​thức có terse but informative article về sự khác biệt.

Trong trường hợp của bạn, nếu quá trình cha mẹ sẽ sống lâu hơn những đứa trẻ, sau đó bạn có thể:

  1. Sử dụng CreatePipe API để tạo ra một thừa kế, ống nặc danh.
  2. Sử dụng CreateFile để tạo tệp có số FILE_FLAG_NO_BUFFERING được đặt.
  3. Cung cấp tay cầm có thể ghi của ống cho trẻ làm STDOUT của nó.
  4. Trong quy trình gốc, đọc từ tay cầm có thể đọc của đường ống vào bộ đệm phù hợp và ghi chúng vào tệp.
+0

Ý tưởng hay về cách tránh các giới hạn FILE_FLAG_NO_BUFFERING! Tôi sẽ chỉ phải xem cách hoạt động của bộ đệm với CreatePipe(). Cảm ơn! –

2

lẽ bạn có thể được thỏa mãn đủ với FlushFileBuffers:

sẽ xóa bộ đệm của một tập tin cụ thể và gây ra tất cả dữ liệu đệm để được ghi vào một tập tin.

Điển hình WriteFileWriteFileEx chức năng ghi dữ liệu vào một vùng đệm bên trong mà hệ điều hành ghi vào một đĩa hoặc thông tin liên lạc đường ống một cách thường xuyên. Chức năng FlushFileBuffers ghi tất cả thông tin đệm cho một tệp được chỉ định vào thiết bị hoặc đường ống.

Họ cảnh báo rằng gọi tuôn, để tuôn ra bộ đệm rất nhiều, không hiệu quả - và nó tốt hơn để chỉ vô hiệu hóa bộ nhớ đệm (tức là Tim answer):

Do đĩa tương tác bộ nhớ đệm trong vòng hệ thống, chức năng FlushFileBuffers có thể không hiệu quả khi được sử dụng sau mỗi lần ghi vào thiết bị ổ đĩa khi nhiều lần ghi đang được thực hiện riêng biệt. Nếu một ứng dụng đang thực hiện ghi nhiều vào đĩa và cũng cần đảm bảo dữ liệu quan trọng được ghi vào phương tiện liên tục, ứng dụng nên sử dụng I/O không bị chặn thay vì thường gọi FlushFileBuffers. Để mở tệp cho I/O không được lọc, hãy gọi hàm CreateFile với các cờ FILE_FLAG_NO_BUFFERINGFILE_FLAG_WRITE_THROUGH. Điều này ngăn cản các nội dung tập tin được lưu trữ và xóa siêu dữ liệu vào đĩa bằng mỗi lần ghi. Để biết thêm thông tin, hãy xem CreateFile.

Nếu đó không phải là tình huống hiệu suất cao và bạn sẽ không xả quá thường xuyên, thì FlushFileBuffers có thể đủ (và dễ dàng hơn).

+0

+1 để tham chiếu cờ 'FILE_FLAG_WRITE_THROUGH'. Tôi đã đề cập đến việc sử dụng FlushFileBuffers trong câu hỏi - như một giải pháp cho giải pháp thẳng tiến (không hoạt động), và đó là những gì tôi đang cố gắng tránh. –

+0

Xin lỗi, ý tôi là +1 cho tham chiếu để gắn cờ 'FILE_FLAG_NO_BUFFERING' (mặc dù điều đó đã được trả lời trước) –

2

Kích thước bạn đang xem trong Explorer có thể không hoàn toàn đồng bộ với những gì hệ thống tệp biết về tệp, vì vậy đây không phải là cách tốt nhất để đo lường.Nó chỉ xảy ra như vậy mà FlushFileBuffers sẽ làm cho hệ thống tập tin cập nhật thông tin mà Explorer đang xem; đóng nó và mở cửa lại có thể kết thúc làm điều tương tự.

Bên cạnh các vấn đề về bộ nhớ đệm trên đĩa được đề cập bởi những người khác, viết qua đang làm những gì bạn đang hy vọng nó đang làm. Nó chỉ là làm một 'dir' trong thư mục có thể không hiển thị thông tin cập nhật.

Câu trả lời cho thấy rằng việc ghi lại chỉ ghi nó "vào hệ thống tệp" không hoàn toàn đúng. Nó ghi vào bộ đệm hệ thống tập tin, nhưng nó cũng gửi dữ liệu xuống đĩa. Viết qua có thể có nghĩa là một lần đọc tiếp theo được thỏa mãn từ bộ nhớ cache, nhưng điều đó không có nghĩa là chúng ta đã bỏ qua một bước và không ghi nó vào đĩa. Đọc số article's summary rất cẩn thận. Đây là một chút khó hiểu cho mọi người.

4

Đây là một câu hỏi cũ nhưng tôi nghĩ rằng tôi có thể thêm một chút vào nó. Trên thực tế tất cả mọi người ở đây tôi tin là sai. Khi bạn ghi vào một luồng có ghi thông qua và không bị chặn, nó sẽ ghi vào đĩa nhưng nó KHÔNG cập nhật siêu dữ liệu liên kết với Hệ thống Tệp (ví dụ như trình thám hiểm nào cho bạn thấy).

Bạn có thể tìm thấy một tài liệu tham khảo tốt về loại công cụ này đây http://winntfs.com/2012/11/29/windows-write-caching-part-2-an-overview-for-application-developers/

Chúc mừng,

Greg

+1

MSDN nói rõ ràng điều ngược lại. Nó nói rằng siêu dữ liệu đang được flushed. Dù sao, điều gì đáng ngạc nhiên là những gì 'FILE_FLAG_WRITE_THROUGH' thực sự là nghĩa vụ phải được sử dụng cho. Về cơ bản nó là một cách bình thường, được đệm với chỉ một sự khác biệt, writeback của các trang bẩn bắt đầu ngay lập tức (trái ngược với "một số thời gian không xác định sau"). Đó là tốt, ngoại trừ KB nói rằng nó luôn chạy đồng bộ và khối cho đến khi viết hoàn thành đã hoàn thành. Mà làm cho toàn bộ điều vô nghĩa (unbuffered có thể chạy không đồng bộ không có vấn đề). – Damon

0

Có lẽ bạn muốn cân nhắc lập bản đồ bộ nhớ mà tập tin. Ngay sau khi bạn ghi vào vùng bộ nhớ được ánh xạ, tệp sẽ được cập nhật.

Win API File Mapping