2015-03-17 9 views
9

API java.nio.file.Files là một cải tiến thực sự tốt đẹp so với lớp học cũ java.io.File, nhưng một chi tiết đánh tôi là lẻ; ngoại trừ delete() không có phương pháp nào tài liệu mà họ có thể ném NoSuchFileException và thậm chí delete() cho biết đây là tùy chọn.Tôi có thể tin tưởng các phương thức trong Tệp sẽ ném NoSuchFileException khi được mong đợi không?

Tôi muốn có thể phân biệt giữa các lỗi do thiếu tệp và các sự cố IO khác, nhưng có vẻ như điều này không được đảm bảo là có thể.

Cách thay thế gọi Files.exists() và các khoản tương tự trước đó sẽ có nguy cơ xảy ra tình trạng chủng tộc nếu tệp được tạo ở giữa hai thao tác.

Tôi có thể mong đợi các phương thức trong Files sẽ tăng NoSuchFileException khi thích hợp không? Nếu vậy, tài liệu này ở đâu? Nếu không, làm thế nào tôi có thể xác định một cách an toàn sự thất bại là do một tập tin bị thiếu?


Ví dụ: Trên Windows 7 với Java 7.0.02 phương pháp Files.readAllLines() không nâng cao một NoSuchFileException, mặc dù nó không phải tài liệu một cách rõ ràng để làm như vậy:

Files.readAllLines(Paths.get("foo"), StandardCharsets.UTF_8) 
java.nio.file.NoSuchFileException: foo 
    at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:79) 
    at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97) 
    at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102) 
    at sun.nio.fs.WindowsFileSystemProvider.newByteChannel(WindowsFileSystemProvider.java:229) 
    at java.nio.file.Files.newByteChannel(Files.java:315) 
    at java.nio.file.Files.newByteChannel(Files.java:361) 
    at java.nio.file.spi.FileSystemProvider.newInputStream(FileSystemProvider.java:380) 
    at java.nio.file.Files.newInputStream(Files.java:106) 
    at java.nio.file.Files.newBufferedReader(Files.java:2660) 
    at java.nio.file.Files.readAllLines(Files.java:2993) 

Trả lời

0

Lớp Tệp cung cấp hai phương pháp xóa.

Phương thức xóa xóa (Đường dẫn) xóa tệp hoặc ném ngoại lệ nếu thao tác xóa không thành công. Ví dụ, nếu tập tin không tồn tại một NoSuchFileException được ném. Bạn có thể bắt ngoại trừ để xác định tại sao delete thất bại như sau:

try { 
    Files.delete(path); 
} catch (NoSuchFileException x) { 
    System.err.format("%s: no such" + " file or directory%n", path); 
} catch (DirectoryNotEmptyException x) { 
    System.err.format("%s not empty%n", path); 
} catch (IOException x) { 
    // File permission problems are caught here. 
    System.err.println(x); 
} 

Các deleteIfExists (Path) phương pháp cũng xóa các tập tin, nhưng nếu tập tin không tồn tại, không có ngoại lệ được ném. Thất bại âm thầm là hữu ích khi bạn có nhiều chủ đề xóa các tập tin và bạn không muốn ném một ngoại lệ chỉ vì một chủ đề đã làm như vậy đầu tiên.

Lưu ý: Các NoSuchFileExceptionDirectoryNotEmptyException những ngoại lệ mới được giới thiệu trong Java 7.

+0

Tôi hỏi về phần còn lại của API, không chỉ các phương thức 'delete()'/'deleteIfExists()'. Phần còn lại của API (ví dụ: 'readAllLines()') không ghi lại rằng nó làm tăng 'NoSuchFileException', mặc dù nó có vẻ như vậy (ít nhất là trên Windows). Ngay cả 'delete()' chỉ ra đây là một ngoại lệ tùy chọn, cho thấy người gọi không thể dựa vào hành vi này. – dimo414

1

Nói chung: không có, bạn có thể không phương pháp tin cậy trong java.nio.file.Files để ném một NoSuchFileException khi mong đợi, nhưng bạn có thể xác minh .

Như bạn có thể thấy từ stacktrace, Files sử dụng FileSystemProvider để thực hiện các thao tác tệp. Việc triển khai FileSystemProvider bị hạn chế (như WindowsFileSystemProvider) và lần lượt sử dụng rất nhiều mã gốc (C). Ví dụ: tôi đã truy tìm số NoSuchFileException tới số WindowsException dựa trên hệ điều hành để báo cáo số ERROR_FILE_NOT_FOUND hoặc ERROR_PATH_NOT_FOUND. Một ví dụ khác là newInputStream tuyến đường đi từ ChannelInputStream đến WindowsChannelFactory đến WindowsNativeDispatcher.c mà cuối cùng gọi hàm Windows gốc CreateFileW.
Với số lượng mã liên quan chỉ dành cho Windows, tôi không thấy làm thế nào điều này có thể được tin cậy để làm việc tương tự cho ví dụ Linux sử dụng mã herehere.

Theo kinh nghiệm của tôi, Linux (Posix) hành vi hệ thống tập tin là khá phù hợp, nhưng Windows (NT) hành vi hệ thống tập tin không phải là: Tôi sẽ không giả định Windows 7 để hành xử chính xác giống như Windows 8.

Cuối cùng, một nhận xét về điều kiện chủng tộc: không có hệ thống tệp nào mà tôi biết chắc chắn rằng các tệp được liệt kê trong thư mục thực sự tồn tại (một số tệp có thể đã bị xóa, đặc biệt khi sử dụng nhiều chuỗi hoạt động trên các tệp trong cùng một thư mục). Sử dụng các phương pháp như Files.exists() trước đó là, theo kinh nghiệm của tôi, một ý tưởng tồi trừ khi bạn sắp phân bổ nhiều tài nguyên (ví dụ: tạo kết nối để tải lên tệp). Khi giao dịch với các tệp, tốt hơn là giả sử mọi thứ đều theo thứ tự và bắt ngoại lệ và sau đó cố gắng xác định những gì là sai. Ví dụ. khi đọc một tệp, mở tệp mà không kiểm tra xem tệp có tồn tại hay không và nếu bạn gặp lỗi, hãy kiểm tra xem tệp có tồn tại để bắt đầu không. Điều này có thể tiết kiệm rất nhiều hoạt động I/O mà lần lượt sẽ giúp hiệu suất.

+0

"tốt hơn là giả sử mọi thứ theo thứ tự và bắt ngoại lệ và sau đó cố gắng xác định những gì là sai." chắc chắn tôi đồng ý, và cuối cùng nó sẽ là tốt đẹp nếu API 'Files' trả về một cách rõ ràng các ngoại lệ khác nhau cho các trường hợp lỗi khác nhau. – dimo414

+0

@ dimo414 Điều đó sẽ tốt đẹp nhưng với những điều kỳ quặc [như thế này] (http://stackoverflow.com/q/12139482/3080094) (nơi bạn có thể xóa một tập tin nếu bạn loại bỏ thuộc tính chỉ đọc đầu tiên) Tôi không chắc chắn nó có thể được thực hiện nhất quán trên các nền tảng. – vanOekel

+0

Đồng ý, có trường hợp cạnh, nhưng nó quá xấu các trường hợp bình thường không được ghi chép rõ ràng hơn. Có vẻ như điều tốt nhất cần làm là bắt 'IOException' và sau đó kiểm tra' Files.exists() ', và không bận tâm tìm kiếm' NoSuchFileException' mặc dù đôi khi nó có thể bị ném. – dimo414

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