Tôi hoàn toàn bối rối ngay bây giờ - chủ yếu là vì thuật ngữ, tôi đoán vậy. Ai đó có thể vui lòng hướng dẫn tôi về những điểm khác biệt hoặc cung cấp một vài liên kết đến tài liệu Chống giả không? Đặc biệt là URI tới URL và Resource to File? Đối với tôi, có vẻ như chúng phải giống nhau ...
Thuật ngữ này gây nhầm lẫn và đôi khi gây bối rối, và hầu hết được sinh ra từ sự phát triển của cả Java như một API và một nền tảng theo thời gian. Để hiểu các thuật ngữ này có ý nghĩa như thế nào, điều quan trọng là phải nhận ra hai điều ảnh hưởng đến thiết kế của Java:
- Khả năng tương thích ngược. Các ứng dụng cũ nên chạy trên các bản cài đặt mới hơn, lý tưởng nhất là không cần sửa đổi. Điều này có nghĩa là một API cũ (với tên và thuật ngữ của nó) cần được duy trì thông qua tất cả các phiên bản mới hơn.
- Đa nền tảng. API phải cung cấp phần tóm tắt có thể sử dụng được của nền tảng cơ bản của nó, cho dù đó là hệ điều hành hay trình duyệt.
Tôi sẽ đi qua các khái niệm và cách chúng hình thành. Tôi sẽ trả lời các câu hỏi cụ thể khác của bạn sau đó, vì tôi có thể phải đề cập đến điều gì đó trong phần đầu tiên.
"Tài nguyên" là gì?
Một phần dữ liệu trừu tượng, chung chung có thể được định vị và đọc. Nói một cách dễ hiểu, Java sử dụng điều này để chỉ một "tệp" có thể không phải là tệp nhưng đại diện cho một phần dữ liệu được đặt tên. Nó không có lớp trực tiếp hoặc đại diện giao diện trong Java , nhưng do các thuộc tính của nó (có thể định vị, có thể đọc được) nên nó thường được biểu diễn bằng một URL.
Bởi vì một trong những mục tiêu thiết kế ban đầu của Java là được chạy bên trong trình duyệt, như một ứng dụng hộp cát (applet!) Với các quyền / đặc quyền / giải phóng mặt bằng bảo mật rất hạn chế, Java tạo ra sự khác biệt rõ ràng (lý thuyết) giữa một tệp (một cái gì đó trên cục bộ hệ thống tệp) và một tài nguyên (thứ mà nó cần để đọc). Đây là lý do tại sao việc đọc một cái gì đó liên quan đến ứng dụng (biểu tượng, tệp lớp, v.v.) được thực hiện thông qua ClassLoader.getResource
chứ không phải thông qua lớp tệp.
Thật không may, vì "tài nguyên" cũng là một thuật ngữ chung hữu ích bên ngoài cách giải thích này, nó cũng được sử dụng để đặt tên cho những thứ rất cụ thể (ví dụ: Nhóm ResourceBundle , UIResource , Tài nguyên ), theo nghĩa này, không phải là một tài nguyên.
Các lớp chính đại diện (một đường dẫn đến) một tài nguyên là java.nio.file.Path , java.io.File , java.net.URI và java.net.URL .
Tệp (java.io, 1.0)
Một đại diện trừu tượng của tên đường dẫn tệp và thư mục.
Lớp Tệp đại diện cho một tài nguyên có thể truy cập được thông qua hệ thống tệp gốc của nền tảng . Nó chỉ chứa tên của tệp, vì vậy nó thực sự là một đường dẫn (xem phần sau) mà nền tảng máy chủ lưu trữ diễn giải theo các cài đặt, quy tắc và cú pháp của riêng nó.
Lưu ý rằng Tệp không cần phải trỏ đến một cái gì đó cục bộ , chỉ một cái gì đó mà nền tảng máy chủ lưu trữ hiểu được trong ngữ cảnh truy cập tệp, ví dụ: đường dẫn UNC trong Windows. Nếu bạn gắn tệp ZIP làm hệ thống tệp trong hệ điều hành của mình, thì Tệp sẽ đọc tốt các mục nhập chứa nó.
URL (java.net, 1.0)
URL lớp đại diện cho Bộ định vị tài nguyên thống nhất, một con trỏ đến "tài nguyên" trên World Wide Web. Tài nguyên có thể là một cái gì đó đơn giản như một tệp hoặc một thư mục, hoặc nó có thể là một tham chiếu đến một đối tượng phức tạp hơn, chẳng hạn như truy vấn đến cơ sở dữ liệu hoặc công cụ tìm kiếm.
Song song với khái niệm tài nguyên, URL biểu thị tài nguyên đó giống như cách lớp Tệp đại diện cho tệp trong nền tảng máy chủ: như một chuỗi có cấu trúc trỏ đến một tài nguyên. URL cũng chứa một lược đồ gợi ý về cách tiếp cận tài nguyên (với "tệp:" là "yêu cầu nền tảng máy chủ lưu trữ") và do đó, cho phép trỏ vào tài nguyên thông qua HTTP, FTP, bên trong JAR, và không.
Thật không may, URL đi kèm với cú pháp và thuật ngữ riêng, bao gồm cả việc sử dụng "tệp" và "đường dẫn". Trong trường hợp URL là tệp-URL, URL.getFile sẽ trả về một chuỗi giống với chuỗi đường dẫn của tệp được tham chiếu.
Class.getResource
trả về một URL: nó linh hoạt hơn so với trả về Tệp và nó đã phục vụ nhu cầu của hệ thống như tưởng tượng vào đầu những năm 1990.
URI (java.net, 1.4)
Đại diện cho tham chiếu Mã định danh tài nguyên đồng nhất (URI).
URI là một sự trừu tượng (nhẹ) so với URL. Sự khác biệt giữa URI và URL là khái niệm và chủ yếu là học thuật, nhưng URI được định nghĩa tốt hơn theo nghĩa chính thức và bao gồm nhiều trường hợp sử dụng hơn. Vì URL và URI không giống nhau, một lớp mới đã được giới thiệu để đại diện cho chúng, với các phương thức URI.toURL và URL.toURI để di chuyển giữa cái này và cái kia.
Trong Java, sự khác biệt chính giữa URL và URI là một URL mang kỳ vọng là có thể phân giải được , ứng dụng có thể muốn một InputStream từ đó; một URI được coi giống như một thứ trừu tượng có thể trỏ đến một thứ gì đó có thể giải quyết được (và thường là vậy), nhưng ý nghĩa của nó và cách tiếp cận nó thì dễ hiểu hơn về ngữ cảnh và cách diễn giải.
Đường dẫn (java.nio.file, 1.7)
Một đối tượng có thể được sử dụng để định vị tệp trong hệ thống tệp. Nó thường đại diện cho một đường dẫn tệp phụ thuộc vào hệ thống.
API tệp mới, được biểu tượng hóa trong giao diện Đường dẫn, cho phép tính linh hoạt cao hơn nhiều so với lớp Tệp có thể cung cấp. Giao diện Đường dẫn là một phần trừu tượng của lớp Tệp và là một phần của API Tệp IO Mới . Trong đó Tệp nhất thiết phải trỏ đến một "tệp" như được hiểu bởi nền tảng máy chủ lưu trữ, Đường dẫn mang tính chung chung hơn: nó đại diện cho một tệp (tài nguyên) trong một hệ thống tệp tùy ý .
Đường dẫn làm mất đi sự phụ thuộc vào khái niệm tệp của nền tảng máy chủ. Nó có thể là một mục nhập trong tệp ZIP, một tệp có thể truy cập thông qua FTP hoặc SSH-FS, một biểu diễn đa gốc của classpath ứng dụng hoặc thực sự là bất kỳ thứ gì có thể được biểu diễn một cách có ý nghĩa thông qua giao diện FileSystem và trình điều khiển của nó, FileSystemProvider. Nó mang lại sức mạnh của việc "gắn kết" hệ thống tệp vào ngữ cảnh của một ứng dụng Java.
Nền tảng máy chủ lưu trữ được đại diện thông qua "hệ thống tệp mặc định"; khi bạn gọi File.toPath
, bạn nhận được một Đường dẫn trên hệ thống tệp mặc định.
Bây giờ, nếu tôi có một bộ định vị tham chiếu đến một lớp hoặc gói trong một tệp jar, thì hai cái đó (tức là đường dẫn một chuỗi tệp) có khác nhau không?
Không có khả năng. Nếu tệp jar nằm trên hệ thống tệp cục bộ, bạn không nên có thành phần truy vấn, vì vậy URL.getPath
và URL.getFile
sẽ trả về cùng một kết quả. Tuy nhiên, hãy chọn cái bạn cần: URL tệp thường có thể không có các thành phần truy vấn, nhưng tôi chắc chắn vẫn có thể thêm một thành phần.
Cuối cùng - và quan trọng nhất - tại sao tôi cần đối tượng Tệp; tại sao một Tài nguyên (URL) không đủ?
URL có thể không đủ vì Tệp cung cấp cho bạn quyền truy cập vào dữ liệu quản lý, chẳng hạn như quyền (có thể đọc, có thể ghi, có thể thực thi), loại tệp (tôi có phải là thư mục không?) Và khả năng tìm kiếm và thao tác với hệ thống tệp cục bộ. Nếu đây là những tính năng bạn cần, thì Tệp hoặc Đường dẫn sẽ cung cấp chúng.
Bạn không cần Tệp nếu bạn có quyền truy cập vào Đường dẫn. Tuy nhiên, một số API cũ hơn có thể yêu cầu Tệp.
(Và có đối tượng Tài nguyên không?)
Không, không có. Có rất nhiều thứ được đặt tên như vậy, nhưng chúng không phải là một nguồn lực theo nghĩa ClassLoader.getResource
.
Path
và FileSystem từ NIO :)