Existem diferenças sutis no modo como o que fileName
você está passando é interpretado. Basicamente, você tem 2 métodos diferentes: ClassLoader.getResourceAsStream()
eClass.getResourceAsStream()
. Esses dois métodos localizarão o recurso de maneira diferente.
Em Class.getResourceAsStream(path)
, o caminho é interpretado como um caminho local para o pacote da classe da qual você está chamando. Por exemplo chamada, String.getResourceAsStream("myfile.txt")
irá procurar um arquivo no seu classpath, no seguinte local: "java/lang/myfile.txt"
. Se o seu caminho começar com a /
, será considerado um caminho absoluto e começará a pesquisar a partir da raiz do caminho de classe. Assim, a chamada String.getResourceAsStream("/myfile.txt")
examinará o seguinte local no caminho da sua classe ./myfile.txt
.
ClassLoader.getResourceAsStream(path)
considerará todos os caminhos como absolutos. Então, chamando String.getClassLoader().getResourceAsStream("myfile.txt")
e String.getClassLoader().getResourceAsStream("/myfile.txt")
ambos procurarão um arquivo no seu caminho de classe no seguinte local:./myfile.txt
.
Toda vez que eu menciono um local neste post, ele pode ser um local no seu próprio sistema de arquivos ou dentro do arquivo jar correspondente, dependendo da Class e / ou ClassLoader da qual você está carregando o recurso.
No seu caso, você está carregando a classe de um servidor de aplicativos, portanto, você deve usar em Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName)
vez de this.getClass().getClassLoader().getResourceAsStream(fileName)
. this.getClass().getResourceAsStream()
também irá funcionar.
Leia este artigo para obter informações mais detalhadas sobre esse problema específico.
Aviso para usuários do Tomcat 7 e abaixo
Uma das respostas a esta pergunta afirma que minha explicação parece incorreta para o Tomcat 7. Tentei procurar ao redor para ver por que esse seria o caso.
Então, eu olhei o código fonte do Tomcat WebAppClassLoader
para várias versões do Tomcat. A implementação de findResource(String name)
(que é totalmente responsável por produzir a URL para o recurso solicitado) é praticamente idêntica no Tomcat 6 e no Tomcat 7, mas é diferente no Tomcat 8.
Nas versões 6 e 7, a implementação não tenta normalizar o nome do recurso. Isso significa que nessas versões, classLoader.getResourceAsStream("/resource.txt")
pode não produzir o mesmo resultado que o classLoader.getResourceAsStream("resource.txt")
evento que deveria (desde que o Javadoc especifique). [Código fonte]
Na versão 8, porém, o nome do recurso é normalizado para garantir que a versão absoluta do nome do recurso seja a usada. Portanto, no Tomcat 8, as duas chamadas descritas acima sempre devem retornar o mesmo resultado. [Código fonte]
Como resultado, você deve ter um cuidado extra ao usar ClassLoader.getResourceAsStream()
ou Class.getResourceAsStream()
nas versões do Tomcat anteriores a 8. E você também deve ter em mente que, class.getResourceAsStream("/resource.txt")
na verdade, chama classLoader.getResourceAsStream("resource.txt")
(o líder /
é removido).
getClass().getResourceAsStream("/myfile.txt")
se comporta de maneira diferentegetClassLoader().getResourceAsStream("/myfile.txt")
.getClassLoader()
deString
, é um erro ou precisa de uma extensão?Use
MyClass.class.getClassLoader().getResourceAsStream(path)
para carregar recursos associados ao seu código. UseMyClass.class.getResourceAsStream(path)
como atalho e para recursos empacotados no pacote da sua turma.Use
Thread.currentThread().getContextClassLoader().getResourceAsStream(path)
para obter recursos que fazem parte do código do cliente, não muito restritos ao código de chamada. Você deve ter cuidado com isso, pois o carregador de classes de contexto de encadeamento pode estar apontando para qualquer coisa.fonte
Java antigo simples no antigo Java 7 simples e nenhuma outra dependência demonstra a diferença ...
Eu coloquei
file.txt
noc:\temp\
e eu coloqueic:\temp\
no classpath.Há apenas um caso em que há uma diferença entre as duas chamadas.
fonte
Todas essas respostas por aqui, bem como as respostas desta pergunta , sugerem que o carregamento de URLs absolutos, como "/foo/bar.properties", seja tratado da mesma forma por
class.getResourceAsStream(String)
eclass.getClassLoader().getResourceAsStream(String)
. Esse não é o caso, pelo menos não na minha configuração / versão do Tomcat (atualmente 7.0.40).Desculpe, não tenho absolutamente nenhuma explicação satisfatória, mas acho que o tomcat faz truques sujos e sua magia negra com os carregadores de classes e causa a diferença. Eu sempre usei
class.getResourceAsStream(String)
no passado e não tive nenhum problema.PS: Eu também postei isso aqui
fonte
ClassLoader.getResourceAsStream()
como absolutos? Isso é plausível porque, como mencionado em alguns comentários acima,Class.getResourceAsStream
na verdade chama getClassLoader (). GetResourceAsStream`, mas retira qualquer barra principal.Class.getResourceAsStream()
eClassLoader.getResourceAsStream()
em última análise, acabam chamandoClassLoader.findResource()
que é um método protegido cuja implementação padrão é vazio, mas cuja javadoc afirma explicitamente "implementações carregador de classe deve substituir esse método para especificar onde para encontrar recursos ". Suspeito que a implementação do tomcat desse método específico possa ter falhas.WebAppClassLoader.findResource(String name)
no Tomcat 7 com a do Tomcat 8 , e parece que há uma diferença fundamental. O Tomcat 8 normaliza explicitamente o nome do recurso, adicionando um líder/
se ele não contiver nenhum, o que torna todos os nomes absolutos. O Tomcat 7 não. Isso é claramente um erro no Tomcat 7Depois de tentar algumas maneiras de carregar o arquivo sem sucesso, lembrei-me de que poderia usá-lo
FileInputStream
, o que funcionava perfeitamente.Essa é outra maneira de ler um arquivo em um arquivo
InputStream
: ele lê o arquivo da pasta em execução no momento.fonte
Funciona, tente o seguinte:
fonte