2012-04-05 32 views
22

Giả sử bạn có một quy trình bên ngoài ghi tệp vào một số thư mục và bạn đã có một quá trình riêng định định đọc tệp từ thư mục này định kỳ. Vấn đề cần tránh là đọc một tệp mà quy trình khác hiện đang ở giữa việc ghi ra, vì vậy nó sẽ không đầy đủ. Hiện tại, quá trình đọc sử dụng kiểm tra bộ đếm thời gian của tệp tuổi tối thiểu, vì vậy, nó bỏ qua tất cả các tệp trừ khi ngày sửa đổi cuối cùng của chúng vượt quá XX giây.Cách kiểm tra xem tệp có "hoàn thành" (hoàn toàn được viết) bằng Java

Tôi tự hỏi liệu có cách nào tốt hơn để giải quyết vấn đề này không. Nếu filetype không xác định (có thể là một số định dạng khác nhau) thì có một số cách đáng tin cậy để kiểm tra tiêu đề của tập tin cho số byte cần có trong tệp không, so với số byte hiện có trong tệp để xác nhận chúng khớp?

Cảm ơn mọi suy nghĩ hoặc ý tưởng!

+1

Bạn có bất cứ quyền kiểm soát quá trình ghi tập tin vào thư mục mà bạn xem? –

+0

Ngoài việc đổi tên tệp khi đã hoàn tất, cách tiếp cận tôi thực hiện là làm cho nó ổn khi đọc tệp khi nó được ghi vào (nghĩ 'đuôi' trong Unix) –

Trả lời

9

Bạn có thể sử dụng tệp đánh dấu bên ngoài. Quá trình ghi có thể tạo tệp XYZ.lock trước khi bắt đầu tạo tệp XYZ và xóa XYZ.lock sau khi hoàn tất XYZ. Người đọc sau đó sẽ dễ dàng biết rằng nó có thể xem xét một tập tin hoàn thành chỉ khi các tập tin .lock tương ứng không có mặt.

+0

Xin chào Michal, làm thế nào chúng ta có thể kiểm tra xem "tệp đã bị khóa chưa "thông qua chương trình. –

+0

Ở đây, không có ổ khóa bổ sung nào trên tệp - thực tế là một tệp tồn tại hay không là những gì cấu thành khóa. –

+1

Điều gì xảy ra nếu bạn không có quyền kiểm soát quá trình ghi? – Matthieu

2

Ngay cả số lượng byte bằng nhau, nội dung của tệp có thể khác nhau.

Vì vậy, tôi nghĩ, bạn phải khớp với byte tệp cũ và tệp mới theo byte.

1

2 lựa chọn mà dường như để giải quyết vấn đề này:

  1. quá trình nhà văn tùy chọn- tốt nhất thông báo quá trình đọc bằng cách nào đó mà văn bản đã được hoàn thành.
  2. ghi tệp thành {id} .tmp, so với khi đổi tên thành {id} .java và quá trình đọc chỉ chạy trên các tệp * .java. đổi tên mất nhiều thời gian hơn và cơ hội quá trình 2 này làm việc cùng nhau giảm.
1

Đầu tiên, có Why doesn't OS X lock files like windows does when copying to a Samba share? nhưng đó là biến thể của những gì bạn đã làm.

Theo như đọc các tệp tùy ý và tìm kích thước, một số tệp có thông tin đó, một số thì không, nhưng ngay cả những tệp không có cách nào đại diện cho nó. Bạn sẽ cần thông tin cụ thể của từng định dạng và quản lý từng định dạng một cách độc lập.

Nếu bạn hoàn toàn phải thực hiện trên tệp "tức thì" đã xong, thì quá trình viết của bạn sẽ cần phải gửi một số loại thông báo. Nếu không, bạn đang khá nhiều khó khăn bỏ phiếu các tập tin, và đọc thư mục là khá rẻ về I/O so với đọc khối ngẫu nhiên từ các tập tin ngẫu nhiên.

8

Cách tôi đã thực hiện điều này trong quá khứ là quá trình ghi tệp ghi vào tệp "tạm thời" và sau đó di chuyển tệp đến vị trí đã đọc khi tệp đã hoàn thành.

Vì vậy, quá trình viết sẽ viết thành info.txt.tmp. Khi nó kết thúc, nó đổi tên tệp thành info.txt. Quá trình đọc sau đó chỉ cần kiểm tra sự tồn tại của info.txt - và nó biết rằng nếu nó tồn tại, nó đã được viết hoàn toàn.

Hoặc bạn có thể có quy trình viết ghi thông tin .txt vào một thư mục khác, và sau đó di chuyển nó vào thư mục đọc nếu bạn không thích sử dụng phần mở rộng tệp lạ.

2

Một giải pháp đơn giản, tôi đã sử dụng trong quá khứ cho kịch bản này với Windows là sử dụng boolean File.renameTo(File) và cố gắng để di chuyển các tập tin ban đầu vào một thư mục dàn riêng biệt:

Nếu successfalse thì potentiallyIncompleteFile vẫn đang được ghi vào.

2

Tôi không có tùy chọn sử dụng điểm đánh dấu tạm thời, vv vì các tệp đang được tải lên bởi khách hàng qua SFTP ghép nối đôi. chúng có thể có kích thước rất lớn.

Đó là khá hacky nhưng tôi so sánh kích thước tập tin trước và sau khi ngủ một vài giây.

của nó rõ ràng không phải lý tưởng để khóa thread nhưng trong trường hợp của chúng tôi nó chỉ đơn thuần là đang chạy như một quá trình hệ thống nền nên dường như làm việc tốt

private boolean isCompletelyWritten(File file) throws InterruptedException{ 
    Long fileSizeBefore = file.length(); 
    Thread.sleep(3000); 
    Long fileSizeAfter = file.length(); 

    System.out.println("comparing file size " + fileSizeBefore + " with " + fileSizeAfter); 

    if (fileSizeBefore.equals(fileSizeAfter)) { 
     return true; 
    } 
    return false; 
} 

Lưu ý: như đã đề cập bên dưới đây có thể không hoạt động trên các cửa sổ. Điều này đã được sử dụng trong một môi trường Linux.

+0

Điểm duy nhất của sự cố sẽ là sự cố mạng – Skynet

+0

Mã này sẽ thất bại vì dữ liệu meta kích thước tệp được viết là bước đầu tiên trong Windows. Vì vậy, luôn luôn file.length() là giống nhau – debugger89

0

Điều này có thể thực hiện bằng cách sử dụng phương thức File2tet.copyFile() Apache Commons IO thư viện maven. Nếu bạn cố gắng sao chép tập tin và nhận được IOException nó có nghĩa là tập tin đó không được lưu hoàn toàn.

Ví dụ:

public static void copyAndDeleteFile(File file, String destinationFile) { 

    try { 
     FileUtils.copyFile(file, new File(fileDirectory)); 
    } catch (IOException e) { 
     e.printStackTrace(); 
     copyAndDeleteFile(file, fileDirectory, delayThreadPeriod); 
    } 

Hoặc kiểm tra định kỳ với một số kích thước chậm trễ của thư mục chứa tập tin này:

FileUtils.sizeOfDirectory(folder); 
+0

Nó là thú vị như thế nào Commons IO có thể theo dõi này. Vì vậy, điều này có lẽ sẽ trả lời câu hỏi ban đầu mà không cần sao chép phức tạp trước đây. – Thomas

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