mở tài nguyên với đường dẫn tương đối trong Java


84

Trong ứng dụng Java của mình, tôi cần lấy một số tệp và thư mục.

Đây là cấu trúc chương trình:

./main.java
./package1/guiclass.java
./package1/resources/resourcesloader.java
./package1/resources/repository/modules/   -> this is the dir I need to get
./package1/resources/repository/SSL-Key/cert.jks    -> this is the file I need to get

guiclass tải lớp resourceloader sẽ tải các tài nguyên của tôi (thư mục và tệp).

Đối với tệp, tôi đã thử

resourcesloader.class.getClass().getResource("repository/SSL-Key/cert.jks").toString()

để có được đường dẫn thực, nhưng cách này không hoạt động.

Tôi không biết sử dụng đường dẫn nào cho thư mục.


1
class.getClass () không giống như class.getClassLoader (). Cũng có một giải pháp khác, getResourceAsStream () bằng cách sử dụng một lớp trong cùng gói với tài nguyên của bạn. Để biết thêm chi tiết: tshikatshikaaa.blogspot.nl/2012/07/… .
Jérôme Verstrynge,

Câu trả lời:


48

Cung cấp đường dẫn liên quan đến trình tải lớp, không phải lớp mà bạn đang nhận trình tải. Ví dụ:

resourcesloader.class.getClassLoader().getResource("package1/resources/repository/SSL-Key/cert.jks").toString();

161

Tôi đã gặp vấn đề với việc sử dụng getClass().getResource("filename.txt")phương pháp này. Khi đọc hướng dẫn tài liệu Java, nếu tài nguyên của bạn không nằm trong cùng một gói với lớp bạn đang cố gắng truy cập tài nguyên, thì bạn phải cung cấp cho nó đường dẫn tương đối bắt đầu '/'. Chiến lược được đề xuất là đặt các tệp tài nguyên của bạn trong thư mục "tài nguyên" trong thư mục gốc. Vì vậy, ví dụ nếu bạn có cấu trúc:

src/main/com/mycompany/myapp

thì bạn có thể thêm một thư mục tài nguyên theo đề xuất của maven trong:

src/main/resources

hơn nữa bạn có thể thêm các thư mục con trong thư mục tài nguyên

src/main/resources/textfiles

và nói rằng tệp của bạn được gọi myfile.txtđể bạn có

src/main/resources/textfiles/myfile.txt

Bây giờ đây là nơi mà vấn đề đường dẫn ngu ngốc xuất hiện. Giả sử bạn có một lớp trong đó com.mycompany.myapp packagevà bạn muốn truy cập myfile.txttệp từ thư mục tài nguyên của mình. Một số người nói rằng bạn cần cung cấp:

"/main/resources/textfiles/myfile.txt" path

hoặc là

"/resources/textfiles/myfile.txt"

cả hai điều này đều sai. Sau khi tôi chạy mvn clean compile, các tệp và thư mục được sao chép trong:

myapp/target/classes 

thư mục. Nhưng thư mục tài nguyên không có ở đó, chỉ là các thư mục trong thư mục tài nguyên. Vì vậy, bạn có:

myapp/target/classes/textfiles/myfile.txt

myapp/target/classes/com/mycompany/myapp/*

vì vậy đường dẫn chính xác để cung cấp cho getClass().getResource("")phương thức là:

"/textfiles/myfile.txt"

nó đây:

getClass().getResource("/textfiles/myfile.txt")

Điều này sẽ không trả về null nữa mà sẽ trả về lớp của bạn. Tôi hi vọng nó sẽ giúp ích cho mọi người. Thật kỳ lạ đối với tôi, "resources"thư mục này cũng không được sao chép mà chỉ có các thư mục con và tệp trực tiếp trong "resources"thư mục. Nó có vẻ hợp lý với tôi rằng "resources"thư mục cũng sẽ được tìm thấy dưới"myapp/target/classes"


1
Trong của tôi target/classes, tôi chỉ có thể xem các tệp trong tài nguyên chính và không kiểm tra tài nguyên. Tại sao?
Ava

@Ava Thêm thư mục thử nghiệm làm thư mục nguồn của bạn và bạn đã sẵn sàng!
Aakash Parashar

@Ava, chắc chắn đó là câu trả lời muộn cho bạn, nhưng có thể giúp ích cho ai đó. Bạn cần thực hiện mvn clean test-compilelệnh, vì nó sẽ tiếp tục compiletrong vòng đời của Maven . Điều đó sẽ tạo ra target/test-classes.
Alexander Radchenko

34

Với hy vọng cung cấp thêm thông tin cho những người không nhận được điều này nhanh chóng như những người khác, tôi muốn cung cấp kịch bản của mình vì nó có thiết lập hơi khác. Dự án của tôi đã được thiết lập với cấu trúc thư mục sau (sử dụng Eclipse):

Dự án/
  src / // mã nguồn ứng dụng
    org /
      dự án của tôi/
        MyClass.java
  test / // bài kiểm tra đơn vị
  res / // tài nguyên
    images / // hình ảnh PNG cho các biểu tượng
      my-image.png
    xml / // Tệp XSD để xác thực tệp XML với JAXB
      my-schema.xsd
    conf / // tệp .conf mặc định cho Log4j
      log4j.conf
  thư viện lib / // được thêm vào đường dẫn xây dựng thông qua cài đặt dự án

Tôi gặp sự cố khi tải tài nguyên của mình từ thư mục res . Tôi muốn tất cả các tài nguyên của mình tách biệt với mã nguồn của tôi (chỉ đơn giản cho mục đích quản lý / tổ chức). Vì vậy, những gì tôi phải làm là thêm thư mục res vào đường dẫn xây dựng và sau đó truy cập tài nguyên thông qua:

static final ClassLoader loader = MyClass.class.getClassLoader();

// in some function
loader.getResource("images/my-image.png");
loader.getResource("xml/my-schema.xsd");
loader.getResource("conf/log4j.conf");

LƯU Ý: Dấu /được bỏ qua ở đầu chuỗi tài nguyên vì tôi đang sử dụng ClassLoader.getResource (String) thay vì Class.getResource (String) .


1
. +1 để đề xuất ClassLoader
pyb

1
Câu trả lời hay nhất về chủ đề này! Mẹo về việc không sử dụng /ở đầu đường dẫn tài nguyên là chìa khóa!
Kayhadrin

10

Khi bạn sử dụng 'getResource' trên một Lớp, một đường dẫn tương đối được giải quyết dựa trên gói mà Lớp có trong đó. Khi bạn sử dụng 'getResource' trên ClassLoader, một đường dẫn tương đối được giải quyết dựa trên thư mục gốc.

Nếu bạn sử dụng đường dẫn tuyệt đối, cả hai phương thức 'getResource' sẽ bắt đầu tại thư mục gốc.


Đừng quên những ảnh hưởng của/
Gilberto

@nbeyer Tại sao việc sử dụng getResourcevới đường dẫn tuyệt đối lại bắt đầu ở thư mục gốc? Mục đích của con đường tuyệt đối không phải là tuyệt đối sao?
atjua

10

@GianCarlo: Bạn có thể thử gọi thuộc tính Hệ thống user.dir sẽ cung cấp cho bạn quyền root của dự án java và sau đó nối đường dẫn này vào đường dẫn tương đối của bạn, ví dụ:

String root = System.getProperty("user.dir");
String filepath = "/path/to/yourfile.txt"; // in case of Windows: "\\path \\to\\yourfile.txt
String abspath = root+filepath;



// using above path read your file into byte []
File file = new File(abspath);
FileInputStream fis = new FileInputStream(file);
byte []filebytes = new byte[(int)file.length()];
fis.read(filebytes);

1
OP muốn định vị một tài nguyên trong classpath (rất có thể trong một jar được tạo trong lần xây dựng thứ). Phương pháp này không cung cấp cách để đạt được mục tiêu đó - bạn không thể trỏ a Fileđến tài nguyên bên trong tệp jar, chỉ đến một mục nhập thích hợp trong hệ thống tệp (ví dụ: chính tệp jar).
Attila

Tôi thích ý tưởng lấy "user.dir" để xem đường dẫn mong muốn. Cảm ơn
YouAreAwesome

5

Đối với những người sử dụng eclipse + maven. Giả sử bạn cố gắng truy cập tệp images/pic.jpgtrong src/main/resources. Làm theo cách này:

ClassLoader loader = MyClass.class.getClassLoader();
File file = new File(loader.getResource("images/pic.jpg").getFile());

là hoàn toàn đúng, nhưng có thể dẫn đến ngoại lệ con trỏ rỗng. Có vẻ như eclipse không nhận ra các thư mục trong cấu trúc thư mục maven là thư mục nguồn ngay lập tức. Bằng cách xóa và src/main/resourcesthư mục khỏi danh sách thư mục nguồn của dự án và đặt nó trở lại (dự án> thuộc tính> đường dẫn xây dựng java> nguồn> loại bỏ / thêm Thư mục), tôi đã có thể giải quyết vấn đề này.


2
resourcesloader.class.getClass()

Có thể được chia nhỏ thành:

Class<resourcesloader> clazz = resourceloader.class;
Class<Class> classClass = clazz.getClass();

Có nghĩa là bạn đang cố tải tài nguyên bằng lớp bootstrap.

Thay vào đó, bạn có thể muốn một cái gì đó như:

resourcesloader.class.getResource("repository/SSL-Key/cert.jks").toString()

Nếu chỉ javac cảnh báo về việc gọi các phương thức tĩnh trên các ngữ cảnh không tĩnh ...


1

Làm công việc sau đây?

resourcesloader.class.getClass().getResource("/package1/resources/repository/SSL-Key/cert.jks")

Có lý do gì khiến bạn không thể chỉ định đường dẫn đầy đủ bao gồm cả gói không?


1

Đi với hai câu trả lời như đã nói ở trên. Cái đầu tiên

resourcesloader.class.getClassLoader().getResource("package1/resources/repository/SSL-Key/cert.jks").toString();
resourcesloader.class.getResource("repository/SSL-Key/cert.jks").toString()

Nên là một và cùng một điều?


1

Để có được đường dẫn thực đến tệp, bạn có thể thử cách này:

URL fileUrl = Resourceloader.class.getResource("resources/repository/SSL-Key/cert.jks");
String pathToClass = fileUrl.getPath;    

Resourceloader là tên lớp ở đây. "resources / repository / SSL-Key / cert.jks" là đường dẫn liên quan đến tệp. Nếu bạn có guiclass của mình trong ./package1/java mà vẫn còn phần còn lại của cấu trúc thư mục, bạn sẽ lấy "../resources/repository/SSL-Key/cert.jks" làm đường dẫn tương đối vì các quy tắc xác định đường dẫn tương đối.

Bằng cách này, bạn có thể đọc tệp của mình bằng BufferedReader. KHÔNG SỬ DỤNG DÂY CHUYỀN để xác định đường dẫn đến tệp, vì nếu bạn có khoảng trắng hoặc một số ký tự từ bảng chữ cái tiếng Anh trong đường dẫn của bạn, bạn sẽ gặp sự cố và không tìm thấy tệp.

BufferedReader bufferedReader = new BufferedReader(
                        new InputStreamReader(fileUrl.openStream()));

0

Tôi đã thực hiện một sửa đổi nhỏ trên một lớp lót của @ jonathan.cone (bằng cách thêm .getFile()) để tránh ngoại lệ con trỏ rỗng và đặt đường dẫn đến thư mục dữ liệu. Đây là những gì đã làm việc cho tôi:

String realmID = new java.util.Scanner(new java.io.File(RandomDataGenerator.class.getClassLoader().getResource("data/aa-qa-id.csv").getFile().toString())).next();

0

Dùng cái này:

resourcesloader.class.getClassLoader().getResource("/path/to/file").**getPath();**
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.