2011-12-25 22 views
8

Có cách nào để xác định xem tệp mở đã được sửa đổi trong POSIX hay không? Cụ thể hơn, làm cách nào tôi có thể triển khai is_modified() bên dưới?Xác định xem tệp mở đã được sửa đổi trong C

FILE *f = fopen("myfile", "r+"); 

// do various things with f 

if (is_modified(f)) 
    foo(f); 

Để cung cấp một số ngữ cảnh, tôi viết mô-đun trong C cho mọi tệp cần lưu trữ giá trị băm trong bảng. Giao diện cung cấp các trình bao bọc cho fopen()fclose() và việc băm có thể được thực hiện khi tệp được đóng. Tôi tìm thấy một số phương pháp để làm điều này, nhưng không phải là như hiệu quả, sạch sẽ hoặc không có lỗi bằng chứng là tôi rất thích:

  • Tính các hash của mỗi tập tin mở ra cho văn bản.
  • fflush(f) và kiểm tra xem dấu thời gian đã thay đổi chưa.
  • Cung cấp hàm bao quanh fwrite(), fprintf() vv

Bất kỳ lời đề nghị?

+1

Nếu bạn là một trong những điều đó mở tập tin, tại sao không đơn giản theo dõi xem bạn có viết hay không? –

+0

Để trừu tượng hóa. Điều này được cho là một mô-đun cho ra các trình xử lý tệp trong đó khách hàng có thể hoạt động theo bất kỳ cách nào họ muốn. Tôi không muốn sửa đổi các phần lớn của mã khác hoạt động trên các tệp mở bằng các hàm thư viện chuẩn. – nccc

+0

Nếu bạn muốn tránh các quá trình khác đồng thời sửa đổi tệp của mình, hãy xem [khóa tệp] (http://en.wikipedia.org/wiki/File_locking). – jweyrich

Trả lời

6

http://rosettacode.org/wiki/File_modification_time#POSIX_utime.28.29

Bạn có thể kiểm tra các thay đổi mới nhất chống lại sự biến đổi cuối cùng với stat function().

+1

Đó là một giải pháp rất đơn giản, nhưng nó dễ bị các điều kiện chủng tộc. Sau khi bạn nhận được thời gian sửa đổi, và trước khi bạn so sánh nó và thực hiện bất kỳ hành động nào, tệp có thể đã bị thay đổi bởi một tiến trình/luồng khác. 1 tuy nhiên. – jweyrich

+0

Tôi hoàn toàn đồng ý. Tôi đoán giấc ngủ() có thể được thực hiện để chờ đợi thời gian tối thiểu. Theo tôi, đây là một giải pháp tối ưu cho một vấn đề được kiến ​​trúc như trên. – nmjohn

+2

Tôi khuyên bạn nên sử dụng 'fstat()' thay cho 'stat()' vì bạn đã có sẵn bộ mô tả tệp. –

3

Vì bạn đang tháo các tay cầm có nắp cho fopen()fclose(), bạn có thể ghi lại kết quả của fstat() khi bạn mở tệp và lại khi bạn sắp đóng tệp và so sánh hai tệp. Nếu bất cứ điều gì đã thay đổi, sau đó bạn đã có một sự thay đổi tích cực và bạn cần phải tính toán lại băm. Nếu không có gì thay đổi, bạn có thể tin tưởng rằng bạn có cùng một tệp như trước. Nếu bạn cần loại bỏ sự không chắc chắn đó, thì bạn sẽ cần phải tính toán lại băm dù sao, biết rằng tệp có thể bị thay đổi bởi một luồng khác hoặc một tiến trình khác trong khi bạn đang tính toán băm.

Lưu ý rằng POSIX hiện đại (POSIX 2008) cung cấp struct stat với các thành viên thời gian:

  • struct timespec st_atim - cuối truy cập dữ liệu timestamp.
  • struct timespec st_mtim - Dấu thời gian sửa đổi dữ liệu cuối cùng.
  • struct timespec st_ctim - Dấu thời gian thay đổi trạng thái tệp cuối cùng.

Chúng cung cấp độ phân giải nano giây trên thời gian sửa đổi. Có thể vì các lý do tương thích ngược, có các macro như:

#define st_atime st_atim.tv_sec 
#define st_mtime st_mtim.tv_sec 
#define st_ctime st_ctim.tv_sec 

mặc dù AFAICS, tiêu chuẩn POSIX không bắt buộc điều này. Tuy nhiên, các tên st_Xtime đã được sử dụng từ đầu (Unix) - Phiên bản 7 Unix từ năm 1978, và có lẽ trước đây - vì vậy các hệ thống sẽ muốn giữ mã cũ hơn và các macro chẳng hạn như vì thế.

+0

Thật không may, 'st_mtime' và các thành viên khác không được cập nhật trong khi tệp đang mở. Vì vậy, giải pháp này tóm tắt thành một cái gì đó như 'fclose(); stat(); 'quá. – nccc

+0

Các cập nhật được lên lịch (miễn là các thay đổi, nếu có, là 'fflush()' d) ... và nếu bạn thực sự lo lắng, bạn có thể áp dụng một trong các tùy chọn O_xSYNC cho bộ mô tả tệp. Chương trình này (với các tiêu đề thích hợp) trình diễn; thử nghiệm MacOS X 10.7.2, nhưng chúng là kết quả mong đợi trên bất kỳ máy POSIX nào: 'int main (void) {struct stat s1, s2; char name [] = "zzz"; FILE * fp; if ((fp = fopen (tên, "w +"))! = 0) {fstat (fileno (fp), &s1); ngủ (5); putc ('x', fp); fflush (fp); fstat (fileno (fp), &s2); printf ("t1% ld; t2% ld \ n", (dài) s1.st_mtime, (dài) s2.st_mtime); fclose (fp); unlink (name);} return (0);} ' –

+0

Vâng,' fflush() 'sẽ cập nhật các dấu thời gian, có lẽ vì chúng tham chiếu đến inode.Tôi đoán đây là một cái có thể đi, hạt nhân chắc chắn biết liệu tệp có bị bẩn hay không dường như không bằng cách nào đó – nccc

3

bạn cũng có thể sử dụng hệ thống thông báo kqueue để nhận thông báo khi có ai đó thay đổi các tập tin, và sau đó làm mất hiệu lực/reload mục băm của bạn

man 2 kqueue

http://blog.julipedia.org/2004/10/example-of-kqueue.html

+0

Điều đó thật thú vị, nhưng: a) có nghĩa là _every_ write sẽ tạo ra một sự kiện; b) từ các khối 'kevent()', tôi cần ít nhất hai luồng. Chính xác? – nccc

+0

a) yep, nhưng bạn luôn có thể khấu hao nó với các sự kiện xếp hàng trong một khoảng thời gian cụ thể và sau đó gửi chúng đến chủ đề khác trong bulks b) yep, bạn sẽ cần chuỗi thứ hai để chờ sự kiện – jackdoe

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