Tôi muốn biết cách tốt nhất để tải tài nguyên trong Java:
this.getClass().getResource() (or getResourceAsStream())
,Thread.currentThread().getContextClassLoader().getResource(name)
,System.class.getResource(name)
.
Tôi muốn biết cách tốt nhất để tải tài nguyên trong Java:
this.getClass().getResource() (or getResourceAsStream())
,Thread.currentThread().getContextClassLoader().getResource(name)
,System.class.getResource(name)
.Câu trả lời:
Tìm ra giải pháp theo những gì bạn muốn ...
Có hai thứ mà getResource
/ getResourceAsStream()
sẽ nhận được từ lớp mà nó được gọi là ...
Vì vậy, nếu bạn làm
this.getClass().getResource("foo.txt");
nó sẽ cố gắng tải foo.txt từ cùng một gói với lớp "this" và với trình tải lớp của lớp "this". Nếu bạn đặt dấu "/" ở phía trước thì bạn hoàn toàn đang tham chiếu đến tài nguyên.
this.getClass().getResource("/x/y/z/foo.txt")
sẽ tải tài nguyên từ trình tải lớp của "this" và từ gói xyz (nó sẽ cần ở cùng thư mục với các lớp trong gói đó).
Thread.currentThread().getContextClassLoader().getResource(name)
sẽ tải bằng trình tải lớp ngữ cảnh nhưng sẽ không phân giải tên theo bất kỳ gói nào (nó phải được tham chiếu tuyệt đối)
System.class.getResource(name)
Sẽ tải tài nguyên bằng trình tải lớp hệ thống (nó cũng phải được tham chiếu tuyệt đối, vì bạn sẽ không thể đưa bất cứ thứ gì vào gói java.lang (gói của Hệ thống).
Chỉ cần nhìn vào nguồn. Cũng chỉ ra rằng getResourceAsStream chỉ gọi "openStream" trên URL được trả về từ getResource và trả về điều đó.
Thread#setContextClassLoader
. Điều này hữu ích nếu bạn cần sửa đổi classpath trong khi chương trình đang thực thi.
Chà, nó một phần phụ thuộc vào những gì bạn muốn xảy ra nếu bạn thực sự đang ở trong một lớp dẫn xuất.
Ví dụ: giả sử SuperClass
là trong A.jar và SubClass
trong B.jar, và bạn đang thực thi mã trong một phương thức thể hiện được khai báo trong SuperClass
nhưng nơi this
tham chiếu đến một thể hiện của SubClass
. Nếu bạn sử dụng this.getClass().getResource()
nó sẽ trông tương đối với SubClass
, trong B.jar. Tôi nghi ngờ đó thường không phải là những gì cần thiết.
Cá nhân tôi có lẽ sẽ sử dụng Foo.class.getResourceAsStream(name)
thường xuyên nhất - nếu bạn đã biết tên của tài nguyên bạn đang theo dõi và bạn chắc chắn về vị trí liên quan của nó, thì đó là Foo
cách hiệu quả nhất IMO.
Tất nhiên cũng có lúc đó không phải là điều bạn muốn: hãy đánh giá từng trường hợp dựa trên giá trị của nó. Chỉ là "Tôi biết tài nguyên này được đóng gói với lớp này" là câu phổ biến nhất mà tôi gặp phải.
this.getClass()
. Tạo một thể hiện của lớp con và gọi phương thức ... nó sẽ in ra tên của lớp con, không phải lớp cha.
Tôi tìm kiếm ba nơi như hình dưới đây. Bình luận được chào đón.
public URL getResource(String resource){
URL url ;
//Try with the Thread Context Loader.
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if(classLoader != null){
url = classLoader.getResource(resource);
if(url != null){
return url;
}
}
//Let's now try with the classloader that loaded this class.
classLoader = Loader.class.getClassLoader();
if(classLoader != null){
url = classLoader.getResource(resource);
if(url != null){
return url;
}
}
//Last ditch attempt. Get the resource from the classpath.
return ClassLoader.getSystemResource(resource);
}
Tôi biết nó thực sự muộn cho một câu trả lời khác nhưng tôi chỉ muốn chia sẻ những gì đã giúp tôi cuối cùng. Nó cũng sẽ tải tài nguyên / tệp từ đường dẫn tuyệt đối của hệ thống tệp (không chỉ đường dẫn của classpath).
public class ResourceLoader {
public static URL getResource(String resource) {
final List<ClassLoader> classLoaders = new ArrayList<ClassLoader>();
classLoaders.add(Thread.currentThread().getContextClassLoader());
classLoaders.add(ResourceLoader.class.getClassLoader());
for (ClassLoader classLoader : classLoaders) {
final URL url = getResourceWith(classLoader, resource);
if (url != null) {
return url;
}
}
final URL systemResource = ClassLoader.getSystemResource(resource);
if (systemResource != null) {
return systemResource;
} else {
try {
return new File(resource).toURI().toURL();
} catch (MalformedURLException e) {
return null;
}
}
}
private static URL getResourceWith(ClassLoader classLoader, String resource) {
if (classLoader != null) {
return classLoader.getResource(resource);
}
return null;
}
}
Tôi đã thử rất nhiều cách và chức năng được đề xuất ở trên, nhưng chúng không hoạt động trong dự án của tôi. Dù sao thì tôi cũng đã tìm ra giải pháp và đây là:
try {
InputStream path = this.getClass().getClassLoader().getResourceAsStream("img/left-hand.png");
img = ImageIO.read(path);
} catch (IOException e) {
e.printStackTrace();
}
this.getClass().getResourceAsStream()
trong trường hợp này. Nếu bạn nhìn vào nguồn của getResourceAsStream
phương thức, bạn sẽ nhận thấy rằng nó làm điều tương tự như bạn nhưng theo cách thông minh hơn (dự phòng nếu không ClassLoader
có trên lớp). Nó cũng chỉ ra rằng bạn có thể gặp phải một tiềm năng null
trên getClassLoader
mã của mình…
this.getClass().getResourceAsStream()
không hoạt động với tôi, vì vậy tôi sử dụng nó hoạt động. Tôi nghĩ rằng có một số người có thể đối mặt với vấn đề như tôi.