Có những khác biệt tinh tế như cách fileName
bạn vượt qua được diễn giải. Về cơ bản, bạn có 2 phương pháp khác nhau: ClassLoader.getResourceAsStream()
và Class.getResourceAsStream()
. Hai phương pháp này sẽ định vị tài nguyên khác nhau.
Trong Class.getResourceAsStream(path)
, đường dẫn được hiểu là một đường dẫn cục bộ đến gói của lớp mà bạn đang gọi nó từ đó. Ví dụ như gọi, String.getResourceAsStream("myfile.txt")
sẽ tìm tệp trong đường dẫn lớp của bạn tại vị trí sau : "java/lang/myfile.txt"
. Nếu đường dẫn của bạn bắt đầu bằng a /
, thì nó sẽ được coi là một đường dẫn tuyệt đối và sẽ bắt đầu tìm kiếm từ gốc của đường dẫn lớp. Vì vậy, việc gọi String.getResourceAsStream("/myfile.txt")
sẽ xem xét vị trí sau trong đường dẫn lớp của bạn ./myfile.txt
.
ClassLoader.getResourceAsStream(path)
sẽ coi tất cả các đường dẫn là đường dẫn tuyệt đối. Vì vậy, gọi String.getClassLoader().getResourceAsStream("myfile.txt")
và String.getClassLoader().getResourceAsStream("/myfile.txt")
cả hai sẽ tìm kiếm một tệp trong đường dẫn lớp của bạn tại vị trí sau : ./myfile.txt
.
Mỗi lần tôi đề cập đến một vị trí trong bài đăng này, nó có thể là một vị trí trong chính hệ thống tệp của bạn hoặc bên trong tệp jar tương ứng, tùy thuộc vào Class và / hoặc ClassLoader mà bạn đang tải tài nguyên từ đó.
Trong trường hợp của bạn, bạn đang tải lớp từ Máy chủ ứng dụng, vì vậy bạn nên sử dụng Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName)
thay vì this.getClass().getClassLoader().getResourceAsStream(fileName)
. this.getClass().getResourceAsStream()
cũng sẽ làm việc
Đọc bài viết này để biết thêm thông tin chi tiết về vấn đề cụ thể đó.
Cảnh báo cho người dùng Tomcat 7 trở xuống
Một trong những câu trả lời cho câu hỏi này nói rằng lời giải thích của tôi dường như không đúng với Tomcat 7. Tôi đã cố gắng nhìn xung quanh để xem tại sao lại như vậy.
Vì vậy, tôi đã xem mã nguồn của Tomcat WebAppClassLoader
cho một số phiên bản của Tomcat. Việc triển khai findResource(String name)
(chịu trách nhiệm hoàn toàn trong việc tạo URL cho tài nguyên được yêu cầu) gần như giống hệt nhau trong Tomcat 6 và Tomcat 7, nhưng khác với Tomcat 8.
Trong phiên bản 6 và 7, việc triển khai không cố gắng bình thường hóa tên tài nguyên. Điều này có nghĩa là trong các phiên bản này, classLoader.getResourceAsStream("/resource.txt")
có thể không tạo ra kết quả giống như classLoader.getResourceAsStream("resource.txt")
sự kiện mặc dù vậy (vì đó là những gì Javadoc chỉ định). [mã nguồn]
Trong phiên bản 8, tên tài nguyên được chuẩn hóa để đảm bảo rằng phiên bản tuyệt đối của tên tài nguyên là tên được sử dụng. Do đó, trong Tomcat 8, hai cuộc gọi được mô tả ở trên phải luôn trả về cùng một kết quả. [mã nguồn]
Do đó, bạn phải hết sức cẩn thận khi sử dụng ClassLoader.getResourceAsStream()
hoặc Class.getResourceAsStream()
trên các phiên bản Tomcat sớm hơn 8. Và bạn cũng phải ghi nhớ rằng class.getResourceAsStream("/resource.txt")
thực sự gọi classLoader.getResourceAsStream("resource.txt")
(hàng đầu /
bị tước).
getClass().getResourceAsStream("/myfile.txt")
cư xử khác vớigetClassLoader().getResourceAsStream("/myfile.txt")
.