2010-02-15 30 views
19

Tôi có một quá trình sẽ được gọi khá thường xuyên từ cron để đọc một tệp có các lệnh liên quan đến di chuyển nhất định trong đó. Quá trình của tôi cần phải đọc và ghi vào tệp dữ liệu này - và giữ nó khóa để ngăn các quá trình khác chạm vào nó trong thời gian này. Một quá trình hoàn toàn riêng biệt có thể được thực hiện bởi một người dùng để (tiềm năng) ghi/nối thêm vào cùng một tệp dữ liệu này. Tôi muốn hai quy trình này hoạt động tốt và chỉ truy cập từng tệp một.Java FileLock để Đọc và Viết

FileLock nio dường như là những gì tôi cần (viết các tập tin kiểu semaphore của riêng tôi), nhưng tôi gặp sự cố khi khóa nó để đọc. Tôi có thể khóa và viết tốt, nhưng khi cố gắng tạo khóa khi đọc tôi nhận được một NonWritableChannelException. Thậm chí có thể khóa tệp để đọc không? Có vẻ như một RandomAccessFile là gần gũi hơn với những gì tôi cần, nhưng tôi không thấy làm thế nào để thực hiện điều đó.

Đây là mã thất bại:

FileInputStream fin = new FileInputStream(f); 
FileLock fl = fin.getChannel().tryLock(); 
if(fl != null) 
{ 
    System.out.println("Locked File"); 
    BufferedReader in = new BufferedReader(new InputStreamReader(fin)); 
    System.out.println(in.readLine()); 
      ... 

Trường hợp ngoại lệ được ném trên dòng FileLock.

java.nio.channels.NonWritableChannelException 
at sun.nio.ch.FileChannelImpl.tryLock(Unknown Source) 
at java.nio.channels.FileChannel.tryLock(Unknown Source) 
at Mover.run(Mover.java:74) 
at java.lang.Thread.run(Unknown Source) 

Nhìn vào JavaDocs, nó nói

ngoại lệ không được kiểm soát ném khi một nỗ lực được thực hiện để viết thư cho một kênh mà không được ban đầu được mở ra cho văn bản.

Nhưng tôi không nhất thiết phải viết thư cho nó. Khi tôi cố gắng tạo ra một FileOutpuStream, vv cho mục đích viết nó là hạnh phúc cho đến khi tôi cố gắng để mở một FileInputStream trên cùng một tập tin.

+0

Bạn đã thử sử dụng ba cuộc gọi phương thức tham số, khóa FileLock (vị trí dài, kích thước dài, boolean được chia sẻ)? Tôi chưa bao giờ sử dụng FileLock trước đây nên tôi sẽ không đăng câu trả lời nhưng tôi nghĩ rằng việc sử dụng phương thức đó có thể hữu ích vì có vẻ như bạn cần khóa chung và không phải khóa độc quyền vì bạn muốn ghi vào tệp trong khi có một khóa trên đó. – ChadNC

+0

Tôi nghĩ rằng ý định đó là để khóa chỉ một phần của một tập tin, tuy nhiên tôi muốn khóa toàn bộ tập tin để ngăn chặn và có thể tham nhũng. – bobtheowl2

Trả lời

16

(a) Bạn có biết rằng việc khóa tệp sẽ không giữ cho các quy trình khác không chạm vào nó trừ khi chúng cũng sử dụng khóa không?
(b) Bạn phải khóa qua kênh có thể ghi. Lấy khóa qua chế độ RandomAccessFile trong chế độ "rw" và sau đó mở FileInputStream. Đảm bảo đóng cả hai!

+1

a) có, tôi sẽ viết cả hai quy trình và lập kế hoạch thực hiện các quy trình khóa tương tự trong cả hai b) Tôi không nhận ra rằng bạn có thể nhận khóa trên RandomAccessFile trực tiếp. Để sử dụng File [Input | Output] Stream, tôi cần thực hiện một FileInputStream mới (raf.getFD()). Tuy nhiên, bằng cách sử dụng luồng đầu vào của đối tượng RandomAccessFile trực tiếp, tôi vẫn có thể đọc từ tệp. Cảm ơn – bobtheowl2

+0

Eh? (a) bạn không thể lấy khóa trực tiếp từ RandomAccessFile, trước tiên bạn phải lấy FileChannel của nó; (b) RandomAccessFile không có luồng đầu vào, nhưng nó thực hiện DataInput để bạn có thể đọc trực tiếp từ nó. – EJP

10

Sẽ tốt hơn nếu bạn tạo khóa bằng cách sử dụng tryLock(0L, Long.MAX_VALUE, true).

Điều này tạo ra một khóa chung, đó là điều phải làm để đọc.

tryLock() là viết tắt của tryLock(0L, Long.MAX_VALUE, false), tức là yêu cầu khóa ghi độc quyền.

+0

Phản hồi tuyệt vời. Chương trình này đã được phát hành, nhưng điều này chắc chắn có thể được cập nhật trong giai đoạn tiếp theo.Chúng tôi đang nhìn thấy rất nhiều sử dụng của nó bây giờ mà ổ khóa độc quyền đang trở nên cồng kềnh trong các kịch bản nhất định. Tôi chắc chắn sẽ ghi nhớ điều này cho bản cập nhật tiếp theo. – bobtheowl2

+0

Tại sao bạn nói rằng khóa chia sẻ là điều đúng để làm để đọc, chắc chắn điều đó phụ thuộc vào trường hợp sử dụng của bạn? Nếu tôi muốn đảm bảo rằng chỉ 1 trong số các quy trình đọc một tệp (ví dụ: các tác nhân giám sát thư mục tải lên để xử lý các tệp mới) thì tôi không nghĩ rằng khóa chia sẻ là những gì tôi cần. – codebox

+1

Tôi đã viết nó như vậy vì đọc không phải là loại trừ lẫn nhau. Nó thực sự là có thể cho một số chủ đề để đọc từ một tập tin mà không can thiệp trong khi viết luôn luôn là độc quyền. Hãy nhớ rằng đây là một câu trả lời cho câu hỏi ban đầu và không có nghĩa là một sự thật tuyệt đối cho mọi tình huống. Tuy nhiên, đó là sự thật trong 99% các trường hợp sử dụng. – Huxi

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