Câu hỏi Sự khác biệt giữa tài nguyên, URI, URL, đường dẫn và tệp trong Java là gì?


Tôi đang xem một đoạn mã Java ngay bây giờ, và nó lấy một đường dẫn như một String và lấy URL của nó bằng cách sử dụng URL resource = ClassLoader.getSystemClassLoader().getResource(pathAsString);, sau đó gọi String path = resource.getPath() và cuối cùng thực hiện new File(path);.

Ồ, và cũng có các cuộc gọi đến URL url = resource.toURI(); và String file = resource.getFile().

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 qua những khác biệt hoặc cung cấp một vài liên kết đến tài liệu giả không? Đặc biệt URI đến URL và Tài nguyên để tập tin? Với tôi, có vẻ như chúng cũng giống nhau, tương ứng ...

Sự khác biệt giữa getFile() và getPath() được giải thích ở đây: Sự khác nhau giữa url.getFile () và getpath () là gì? (Điều thú vị là cả hai dường như đều trở lại Strings, điều này có thể thêm rất nhiều vào trạng thái của tôi ...)

Bây giờ, nếu tôi có một trình định vị tham chiếu đến một lớp hoặc một gói trong một tệp jar, thì hai biến đó (tức là đường dẫn một chuỗi tệp) có khác nhau không?

resource.toString() sẽ cung cấp cho bạn jar:file:/C:/path/to/my.jar!/com/example/, sau khi tất cả (lưu ý dấu chấm than).

Sự khác biệt giữa URI và URL  trong Java rằng trước đây không mã hóa không gian? Cf. Các tệp, URI và URL xung đột trong Java (Câu trả lời này giải thích chung, khái niệm sự khác biệt giữa hai thuật ngữ khá tốt: URI xác định và định vị URL;)

Cuối cùng - và quan trọng nhất - tại sao tôi cần File vật; tại sao không phải là tài nguyên (URL) đủ? (Và có một đối tượng tài nguyên?)

Xin lỗi nếu câu hỏi này là một chút không tổ chức; nó chỉ phản ánh sự nhầm lẫn mà tôi có ... :)


76
2018-01-08 16:43


gốc


Chỉ cần thêm vào sự nhầm lẫn, cũng có dòng này, điều này làm tôi nghi ngờ giả thuyết rằng File thực sự đại diện cho "tệp" ... directory = new File(resource.toURI()); - Christian
Và bạn thậm chí không bắt đầu nhìn vào Path và FileSystem từ NIO :) - eckes
@ tắc Một nhức đầu tại một thời điểm, xin vui lòng. ;) - Christian
Vâng trong bối cảnh của câu hỏi của bạn File / URL + URI không liên quan. Cái tên là phương tiện để đặt tên và vận hành trên các tệp khác là một phương thức để đặt tên và đọc từ các tài nguyên (có thể là các tệp). Các phương thức getFile và getPath đối phó với các thành phần của một URL (gây nhầm lẫn) được đặt tên giống như các đối tượng tập tin. Tài nguyên của trình nạp lớp không được biểu diễn dưới dạng tệp vì chúng có thể có nguồn gốc khác nhau (hoặc được lồng trong các tệp JAR). - eckes
Trái tim của vấn đề của bạn là các từ nguồn và con đường có thể có ý nghĩa khác nhau, tùy thuộc vào ngữ cảnh. - Raedwald


Các câu trả lời:


CẬP NHẬT 2017-04-12 Kiểm tra Câu trả lời của JvR vì nó chứa lời giải thích đầy đủ và chính xác hơn!


Xin lưu ý rằng tôi không coi mình là 100% có thẩm quyền để trả lời, nhưng tuy nhiên đây là một số nhận xét:

  • File đại diện cho một tập tin hoặc thư mục có thể truy cập thông qua hệ thống tập tin
  • nguồn là một điều khoản chung cho một đối tượng dữ liệu có thể được tải bởi ứng dụng
    • thông thường tài nguyên là các tệp được phân phối với ứng dụng / thư viện và được nạp thông qua cơ chế tải lớp (khi chúng nằm trên đường dẫn lớp)
  • URL#getPath là getter trên phần đường dẫn của URL (protocol://host/path?query)
  • URL#getFile theo trả về JavaDoc path+query

Trong Java, URI chỉ là một cấu trúc dữ liệu để điều khiển chính định danh chung.

URL mặt khác thực sự là một trình định vị tài nguyên và cung cấp cho bạn các tính năng để thực sự đọc tài nguyên thông qua đăng ký URLStreamHandlerS.

URL có thể dẫn đến tài nguyên hệ thống tệp và bạn có thể tạo URL cho mọi tài nguyên hệ thống tệp bằng cách sử dụng file:// giao thức (do đó File <-> URL quan hệ).

Cũng lưu ý rằng URL#getFile không liên quan đến java.io.File.


Tại sao tôi cần đối tượng File; tại sao không phải là một tài nguyên (URL) đủ?

Đủ rồi. Chỉ khi bạn muốn chuyển tài nguyên cho một số thành phần có thể chỉ hoạt động với các tệp, bạn cần phải nhận Filetừ nó. Tuy nhiên, không phải tất cả các URL tài nguyên đều có thể được chuyển đổi thành FileS.

Và có một đối tượng tài nguyên?

Theo quan điểm của JRE, đó chỉ là một thuật ngữ. Một số khung cung cấp cho bạn lớp học như vậy (ví dụ: Tài nguyên của Spring).


37
2018-01-08 16:58



Cũng có java.nio.file.Path, về cơ bản là một thay thế (Java 7+) cho java.io.File, vì API thứ hai dường như đã được suy nghĩ rất ít trong những ngày đầu của Java. - ntoskrnl
Nói chung, bạn nên giảm thiểu việc sử dụng URL trừ khi nó là hoàn toàn cần thiết. Lý do là URL của bằng và Mã Băm các phương thức được triển khai một cách đáng ngạc nhiên: chúng đang chặn các cuộc gọi phương thức. - kibibyte
@ kibibyte: Tôi mong đợi cuộc gọi sẽ bị chặn, để có một sự thực thi không đồng bộ của hashcode và bằng bây giờ sẽ rất đáng lo ngại. Tôi nghĩ rằng những gì bạn có nghĩa là các cuộc gọi sẽ cố gắng và giải quyết các máy chủ để tìm nếu chúng tương đương và do đó có khả năng có thể thực hiện các cuộc gọi mạng chặn. - Newtopian


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 qua những khác biệt hoặc cung cấp một vài liên kết đến tài liệu giả không? Đặc biệt là URI đến URL và tài nguyên để tập tin? Với tôi, có vẻ như chúng cũng giống nhau, tương ứng ...

Thuật ngữ này gây nhầm lẫn và đôi khi bị quấy rầy, và chủ yếu được sinh ra từ sự tiến hóa của cả Java như một API và là 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à 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ũ sẽ chạy trên các cài đặt mới hơn, lý tưởng mà 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ầ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 nên cung cấp một trừu tượng có thể sử dụng của nền tảng cơ bản của nó, cho dù đó là một hệ điều hành hay một trình duyệt.

Tôi sẽ xem qua các khái niệm và cách chúng xuất hiện. Tôi sẽ trả lời các câu hỏi cụ thể khác của bạn sau đó, bởi vì tôi có thể phải đề cập đến một đ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 lỏng lẻo, Java sử dụng điều này để chỉ một "tệp" có thể không phải là một tệp nhưng không đại diện cho một phần dữ liệu được đặt tên. Nó không có một lớp trực tiếp hoặc biểu diễn giao diện trong Java, nhưng vì các thuộc tính của nó (có thể định vị, dễ đọc), 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 một trình duyệt, như một ứng dụng sandbox (applet!) Với quyền hạn / đặc quyền / an ninh 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 hệ thống tệp cục bộ) và một tài nguyên (một cái gì đó cần đọc).  Đây là lý do tại sao đọc một cái gì đó liên quan đến các ứng dụng (biểu tượng, các tập tin lớp học, và như vậy) được thực hiện thông qua ClassLoader.getResource và không phải thông qua lớp File.

Thật không may, bởi vì "tài nguyên" cũng là một thuật ngữ chung hữu ích ở ngoài giải thích này, nó cũng được sử dụng để đặt tên cho những điều rất cụ thể (ví dụ: lớp học Bó tài nguyên, UIResource, Nguồn) không phải, theo nghĩa này, một nguồn tài nguyên.

Các lớp chính biểu diễn (một đường dẫn đến) một tài nguyên là java.nio.file.Path, java.io.File, java.net.URIjava.net.URL.

Tập tin (java.io, 1.0)

Một đại diện trừu tượng của tên tệp và đường dẫn thư mục.

Lớp File đại diện cho một nguồn tài nguyên có thể truy cập 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 sau) mà nền tảng máy chủ thông dịch theo các thiết lập, quy tắc và cú pháp của nó.

Lưu ý rằng File không cần trỏ đến một cái gì đó địa phương, chỉ là điều mà nền tảng máy chủ hiểu được trong ngữ cảnh truy cập tệp, ví dụ: một đường dẫn UNC trong Windows. Nếu bạn gắn kết một tệp ZIP dưới dạng hệ thống tệp trong Hệ điều hành của mình, thì Tệp sẽ đọc các mục được chứa của nó tốt.

URL (java.net, 1.0)

URL lớp đại diện cho một bộ định vị tài nguyên đồng nhất, một con trỏ đến một "tài nguyên" trên World Wide Web. Một tài nguyên có thể đơ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 tới một đối tượng phức tạp hơn, chẳng hạn như truy vấn tới một cơ sở dữ liệu hoặc một công cụ tìm kiếm.

Song song với khái niệm về tài nguyên, URL đại diện cho tài nguyên đó giống như cách lớp Tệp biểu thị một tệp trong nền tảng máy chủ: dưới dạng một chuỗi có cấu trúc trỏ đến tài nguyên.  URL bổ sung chứa lược đồ gợi ý cách truy cập tài nguyên (với "tệp:" đang "hỏi nền tảng máy chủ") và vì vậy cho phép trỏ vào tài nguyên thông qua HTTP, FTP, bên trong JAR và không có gì.

Thật không may, URL đi kèm với cú pháp và thuật ngữ của riêng họ, bao gồm cả việc sử dụng "tệp" và "đường dẫn". Trong trường hợp URL là một tệp-URL, URL.getFile sẽ trả về một chuỗi giống hệt 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 việc trả về tệp và nó đã phục vụ các nhu cầu của hệ thống như được tưởng tượng vào đầu những năm 1990.

URI (java.net, 1.4)

Đại diện cho một tham chiếu nhận dạng tài nguyên đồng nhất (URI).

URI là một trừu tượng (nhẹ) trên URL.  Sự khác biệt giữa URI và URL là khái niệm và chủ yếu là học tập, nhưng URI được xác định tốt hơn theo nghĩa chính thức và bao gồm phạm vi sử dụng rộng hơn. Bởi vì URL và URI là / không giống nhau, nên một lớp mới đã được giới thiệu để biểu diễn chúng, với các phương thức URI.toURL và URL.toURI để di chuyển giữa một 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 được giải quyết, một ứng dụng nào đó có thể muốn một InputStream từ; một URI được coi là một điều trừu tượng mà có thể chỉ tới một cái gì đó có thể giải quyết được (và thường là), nhưng ý nghĩa của nó và cách tiếp cận nó thì cởi mở hơn với bối cảnh và cách giải thích.

Con đường (java.nio.file, 1.7)

Một đối tượng có thể được sử dụng để định vị một tệp trong hệ thống tệp. Nó thường sẽ đại diện cho một đường dẫn tập tin phụ thuộc 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 linh hoạt 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 trừu tượng của lớp Filevà là một phần của API tệp IO mới. Trường hợp tệp nhất thiết trỏ đến một "tệp" như được hiểu bởi nền tảng máy chủ, Đường dẫn chung chung hơn: đại diện cho một tệp (tài nguyên) trong một tùy ý hệ thống tập tin.

Đường dẫn lấy đi sự phụ thuộc vào khái niệm của một nền tảng máy chủ lưu trữ của một tập tin. Nó có thể là một mục trong một tệp ZIP, một tệp có thể truy cập thông qua FTP hoặc SSH-FS, một đại diện đa gốc của đường dẫn ứng dụng, hoặc thực sự bất cứ điều gì có thể được biểu diễn có ý nghĩa thông qua giao diện FileSystem và trình điều khiển của nó, FileSystemProvider. Nó mang sức mạnh của các hệ thống tập tin "gắn kết" vào bối cảnh của một ứng dụng Java.

Nền tảng máy chủ được thể hiện thông qua "hệ thống tệp mặc định"; khi bạn gọi File.toPath, bạn sẽ nhận được Đường dẫn trên hệ thống tệp mặc định.


Bây giờ, nếu tôi có một trình định vị tham chiếu đến một lớp hoặc một gói trong một tệp jar, thì hai biến đó (tức là đường dẫn một chuỗi tệp) có khác nhau không?

Không chắc. 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 nên trả về cùng một kết quả. Tuy nhiên, hãy chọn một tệp bạn cần: tệp-URL có thể không có các thành phần truy vấn thông thường, nhưng tôi vẫn có thể thêm một thành phần truy vấn.

Cuối cùng - và quan trọng nhất - tại sao tôi cần đối tượng File; tại sao không phải là một tài nguyên (URL) đủ?

URL có thể không đủ vì tệp cho phép bạn truy cập vào dữ liệu vệ sinh như quyền (có thể đọc, ghi, thực thi), loại tệp (tôi là thư mục?) Và khả năng tìm kiếm và thao tác 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 cho họ.

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ó một đối tượng tài nguyên?)

Không, không có. Có nhiều thứ được đặt tên như nó, nhưng chúng không phải là một nguồn lực theo nghĩa ClassLoader.getResource.


26
2017-11-21 16:56



Wow, rất kỹ lưỡng. Chỉ cần đi qua nó, nhưng đã có câu hỏi tiếp theo đầu tiên: Khi bạn nói một tệp "chỉ chứa tên của tệp", bạn không mâu thuẫn với câu lệnh ban đầu của bạn rằng "Đại diện trừu tượng về tên đường dẫn tệp và thư mục" - iemore? - Christian
@Christian Tôi có nghĩa là "chỉ có tên" như trong: không theo bất kỳ cách nào mô hình hóa nội dung của tệp; nó chỉ đơn thuần là một bao bọc mỏng xung quanh một sợi dây. Phần "đại diện trừu tượng" được trích dẫn từ tài liệu API. ;) - JvR
Câu trả lời này xứng đáng để có nhiều upvotes hơn ... sẽ cập nhật câu trả lời chấp nhận của tôi để điểm độc giả này. - Pavel Horal


Câu trả lời của Pavel Horal là tốt đẹp.

Như ông nói, từ "tập tin" có ý nghĩa hoàn toàn khác nhau (thực tế không liên quan) trong URL#getFile so với java.io.File - có thể đó là một phần của sự nhầm lẫn.

Chỉ cần thêm:

  • A nguồn trong Java là một khái niệm trừu tượng, một nguồn dữ liệu có thể đọc được. Vị trí (hoặc địa chỉ) của tài nguyên được biểu diễn trong Java bằng một URL vật.

  • A nguồn có thể tương ứng với một tệp thông thường trong hệ thống tệp cục bộ (cụ thể, khi nó URL bắt đầu với file://). Nhưng một tài nguyên là tổng quát hơn (nó cũng có thể là một số tập tin được lưu trữ trong một cái lọ, hoặc một số dữ liệu được đọc từ mạng, hoặc từ bộ nhớ, hoặc ...). Và nó còn hạn chế hơn, bởi vì File (ngoài việc là những thứ khác ngoài một tệp thông thường: một thư mục, một liên kết) cũng có thể được tạo và viết.

  • Hãy nhớ trong Java File đối tượng không thực sự đại diện cho "tệp" nhưng vị trí (tên đầy đủ, có đường dẫn) của tệp. Vì vậy, một File đối tượng cho phép bạn định vị (và mở) một tệp, dưới dạng URLcho phép bạn truy cập (và mở) một tài nguyên. (Không có Resource lớp trong Java để đại diện cho một tài nguyên, nhưng không phải là một để đại diện cho một tập tin! một lần nữa : File không phải là tệp, đó là đường dẫn của tệp).


11
2018-01-08 17:49





Khi tôi hiểu chúng, bạn có thể phân loại chúng như sau:

Dựa trên web: URI và URL.

  • URL: URL là một vị trí nhất định trên internt (chỉ là một webaddress bình thường như - stackoverflow.com)
  • URI: URL bao giờ là một URI. Nhưng URI cũng có thể chứa những thứ như "mailto:", do đó, chúng cũng là một số "script" mà tôi muốn nói.

Và địa phương: Tài nguyên, Đường dẫn và Tệp

  • Tài nguyên: Tài nguyên là các tệp bên trong bình của bạn. Chúng được sử dụng để tải các tập tin ra khỏi lọ / container.
  • Đường dẫn: Đường dẫn về cơ bản là một chuỗi. Nhưng nó đi kèm với một số chức năng tiện dụng để nối nhiều chuỗi hoặc thêm tệp vào chuỗi. Nó đảm bảo đường dẫn bạn đang xây dựng là hợp lệ.
  • Tệp: Đây là tham chiếu đến một thư mục hoặc tệp. Nó được sử dụng để sửa đổi tệp, mở tệp, v.v.

Sẽ dễ dàng hơn nếu chúng được sáp nhập vào một lớp - chúng thực sự khó hiểu: D

Tôi hy vọng cái này sẽ giúp bạn :)

(Tôi vừa xem tài liệu - xem docs.oracle.com)


3
2018-01-08 17:02





Tệp là một biểu diễn trừu tượng của một thực thể trong hệ thống tệp cục bộ.

Đường dẫn thường là một chuỗi cho biết vị trí của tệp trong hệ thống tệp. Nó thường không bao gồm tên tệp. Vì vậy, c: \ documents \ mystuff \ stuff.txt sẽ có một đường dẫn với giá trị của "C: \ documents \ mystuff" Rõ ràng định dạng của tên tập tin và đường dẫn tuyệt đối sẽ khác nhau rất nhiều từ hệ thống tập tin đến hệ thống tập tin.

URL là một susbset của URI với URL thường đại diện cho các tài nguyên có thể truy cập qua http. Tôi không nghĩ rằng có bất kỳ loại quy tắc ironclad về khi một cái gì đó phải là một URI vs một URL. URI là các chuỗi dưới dạng "protocol: // resource-identifier" chẳng hạn như bitcoin: // params, http://something.com?param=value. Các lớp như URL thường bao bọc chuỗi và cung cấp các phương thức tiện ích mà String sẽ không có lý do gì để cung cấp.

Không có những thứ như Tài nguyên, ít nhất là không theo nghĩa bạn đang nói đến. Chỉ vì một phương thức được đặt tên là getResource không có nghĩa là nó trả về một đối tượng kiểu Resource.

Cuối cùng, cách tốt nhất để tìm ra phương thức của Class là tạo ra một thể hiện của nó trong mã của bạn, gọi các phương thức và sau đó là bước qua trong chế độ gỡ lỗi hoặc gửi kết quả đến System.out.


0
2018-01-08 17:08



Định nghĩa của bạn về "đường dẫn" KHÔNG tương ứng với khái niệm "đường dẫn" trong ngữ cảnh OP - leonbloy