2009-03-24 32 views
110

Có cách nào trong Java để xây dựng một cá thể Tệp trên tài nguyên được truy xuất từ ​​một cái bình thông qua trình nạp lớp không?Tài nguyên Java dưới dạng tệp

Ứng dụng của tôi sử dụng một số tệp từ jar (mặc định) hoặc từ thư mục hệ thống tệp được chỉ định tại thời gian chạy (đầu vào của người dùng). Tôi đang tìm kiếm một cách nhất quán của
a) tải những tập tin này như một dòng suối
b) liệt kê các file trong thư mục người dùng định nghĩa hoặc các thư mục trong jar tương ứng

Chỉnh sửa: Rõ ràng, cách tiếp cận lý tưởng sẽ tránh xa java.io.File hoàn toàn. Có cách nào để tải một thư mục từ classpath và liệt kê nội dung của nó (tập tin/thực thể chứa trong nó)?

Trả lời

53

ClassLoader.getResourceAsStreamClass.getResourceAsStream chắc chắn là cách để tải dữ liệu tài nguyên. Tuy nhiên, tôi không tin rằng có bất kỳ cách nào để "liệt kê" nội dung của một phần tử của classpath.

Trong một số trường hợp, điều này có thể đơn giản là không thể - ví dụ: ClassLoadercó thể tạo dữ liệu khi đang chạy, dựa trên tên tài nguyên được yêu cầu. Nếu bạn nhìn vào API ClassLoader (cơ bản là cơ chế classpath hoạt động như thế nào), bạn sẽ thấy không có gì để làm những gì bạn muốn.

Nếu bạn biết bạn đã thực sự có tệp jar, bạn có thể tải tệp đó bằng ZipInputStream để tìm hiểu những gì có sẵn. Nó sẽ có nghĩa là bạn sẽ có mã khác nhau cho các thư mục và các tập tin jar mặc dù.

Một cách khác, nếu tệp được tạo riêng trước, hãy bao gồm một loại tệp kê khai có chứa danh sách tài nguyên có sẵn. Nhóm trong tệp jar hoặc đưa nó vào hệ thống tệp dưới dạng tệp và tải tệp trước khi cung cấp cho người dùng lựa chọn tài nguyên.

+3

Tôi đồng ý nó gây phiền nhiễu - nhưng nó làm cho ClassLoader áp dụng rộng rãi hơn theo những cách khác. Ví dụ, thật dễ dàng để viết một "trình nạp lớp web" vì web rất tốt để tìm nạp các tệp, nhưng nó không thường là các tệp * liệt kê *. –

+0

Có vẻ như tài nguyên bạn đang cố gắng tải lớn hơn 1MiB 'InputStream' bạn nhận được từ' getResourceAsStream' dừng để truy xuất byte của tài nguyên sau kích thước đó và thay vào đó trả về 0 iff, nó nằm trong hệ thống tệp nén như một cái lọ. Bạn dường như bị buộc phải sử dụng 'getResource' và tải tệp độc lập khỏi trường hợp này trong trường hợp đó. – mgttlinger

+0

@mgttlinger: Điều đó nghe có vẻ không có ý nghĩa với tôi ... có lẽ đáng để đăng một câu hỏi mới với một repro nếu bạn có thể. –

5

Hãy thử điều này:

ClassLoader.getResourceAsStream ("some/pkg/resource.properties"); 

Hiện có nhiều phương pháp có sẵn, ví dụ xem tại đây: http://www.javaworld.com/javaworld/javaqa/2003-08/01-qa-0808-property.html

+0

Cảm ơn bạn đã trả lời. Tôi biết về getResourceAsStream, nhưng tôi không nghĩ rằng tôi có thể tải một thư mục từ classpath thông qua đó. – Mantrum

+0

Trong thư mục Java là một tập tin (UNIX gốc tôi đoán) vì vậy bạn nên ít nhất là thử. – topchef

+0

Tôi nghĩ rằng để liệt kê các tập tin trong một thư mục bạn sẽ cần phải sử dụng java.io.File. Bạn có thể tra cứu tệp bằng Trình tải lớp.findResource trả về một URL có thể được chuyển tới File. –

91

tôi đã cùng một vấn đề và đã có thể sử dụng như sau:

// Load the directory as a resource 
URL dir_url = ClassLoader.getSystemResource(dir_path); 
// Turn the resource into a File object 
File dir = new File(dir_url.toURI()); 
// List the directory 
String files = dir.list() 
+37

Cách tiếp cận này không hoạt động với JAR trong classpath, chỉ với các tệp và thư mục – yegor256

+1

Đó là những gì tôi muốn! thực sự thx – StrikeW

+1

@ yegor256 Nếu tệp của bạn nằm trong một cái lọ, bạn có thể tạo đối tượng 'FileSystem' và lấy' Đường dẫn' từ đó. Sau đó, bạn có thể đọc nó như bình thường. (xem http://stackoverflow.com/a/22605905/1876344) – mgttlinger

2
+2

Trong khi liên kết này có thể trả lời câu hỏi, [nó sẽ là thích hợp hơn] (// meta.stackoverflow.com/q/8259) để bao gồm các phần thiết yếu của câu trả lời ở đây và cung cấp liên kết để tham chiếu, vì liên kết có thể thay đổi hoặc trang được liên kết có thể bị xóa, do đó làm cho câu trả lời vô dụng. – JonasCz

48

Dưới đây là một chút mã từ một trong những ứng dụng của tôi ... Lết tôi biết nếu nó phù hợp với nhu cầu của bạn. Bạn có thể sử dụng điều này nếu bạn biết tệp bạn muốn sử dụng.

URL defaultImage = ClassA.class.getResource("/packageA/subPackage/image-name.png"); 
File imageFile = new File(defaultImage.toURI()); 

Hy vọng điều đó sẽ hữu ích.

9

Một cách đáng tin cậy để xây dựng một trường hợp tập tin trên một nguồn tài nguyên lấy ra từ một lọ là nó để sao chép các tài nguyên như một dòng suối vào một tập tin tạm thời (các tập tin tạm thời sẽ bị xóa khi JVM thoát):

public static File getResourceAsFile(String resourcePath) { 
    try { 
     InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(resourcePath); 
     if (in == null) { 
      return null; 
     } 

     File tempFile = File.createTempFile(String.valueOf(in.hashCode()), ".tmp"); 
     tempFile.deleteOnExit(); 

     try (FileOutputStream out = new FileOutputStream(tempFile)) { 
      //copy stream 
      byte[] buffer = new byte[1024]; 
      int bytesRead; 
      while ((bytesRead = in.read(buffer)) != -1) { 
       out.write(buffer, 0, bytesRead); 
      } 
     } 
     return tempFile; 
    } catch (IOException e) { 
     e.printStackTrace(); 
     return null; 
    } 
} 
Các vấn đề liên quan