• 转:Java 资源加载


    处理配置文件对于Java程序员来说再常见不过了,不管是Servlet,Spring,抑或是Structs,都需要与配置文件打交道。Java将配置文件当作一种资源(resource)来处理,并且提供了两个类来读取这些资源,一个是Class类,另一个是ClassLoader类。

     

    当我们自己的程序需要处理配置文件时(比如xml文件或properties文件),通常会遇到两个问题:

      (1)我的配置文件应该放在哪里?

      (2)怎么我的配置文件找不到了?

     

    在了解了Java加载资源文件的机制后,以上这两个问题便迎刃而解了。

    对于第一个问题,答案是:请将你的资源文件放在classpath里,如果资源文件在jar中,请将该jar文件也加到classpath里面。

    对于第二个问题,就得看你是使用的是哪个类(Class还是ClassLoader)来加载资源文件了,所以接下来分别讨论一下Class类和ClassLoader类对于资源文件的加载机制。

     

    (一)用Class类加载资源文件

    通过调用Class类的getResourceAsStream方法来加载资源文件:

    public InputStream getResourceAsStream(String pathToConfigFile);

     

    该方法接收一个String类型的参数(pathToConfigFile)来表示资源文件的地址,如果加载成功,则返回该资源文件的输入流(InputStream),如果失败,则返回null。重要的是,在传入pathToConfigFile参数时,有两种方式,第一种方式为绝对定位方式,即pathToConfigFile以"/"开头,此时Java以classpath为根目录,直接加上pathToConfigFile来搜索资源文件。第二种方式为相对定位方式,即pathToConfigFile不以"/"开头,此时资源文件的全路径应该为:调用getResourceAsStream方法的类的package路径加上pathToConfigFile。(在将package转为目录时将"."变成"/") 

    举个例子,在IntelliJ Idea中创建一个java工程,目录结构如下:

    该工程里有两个resources文件夹,一个位于davenkin文件夹下,一个直接位于src文件夹下。第一个resources文件夹下有一个config.properties文件,其内容为:

    name = ConfigUnderDavenkin

    第二个resources文件夹下也有一个config.properties文件,其内容为:

    name = ConfigUnderSrc

    在davenkin包下定义ResourceLoader.java来加载资源文件:

    package davenkin;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.Properties;
    
    public class ResourceLoader
    {
        public static void main(String[] args) throws IOException
        {
            ResourceLoader resourceLoader = new ResourceLoader();
            resourceLoader.loadProperties1();
    
        }
    
        public void loadProperties1() throws IOException
        {
            InputStream input = null;
            try
            {
                input = Class.forName("davenkin.ResourceLoader").getResourceAsStream("/resources/config.properties");
    
                //also can be this way:
                //input = this.getClass().getResourceAsStream("/resources/config.properties");
            } catch (ClassNotFoundException e)
            {
                e.printStackTrace();
            }
            printProperties(input);
        }
    
        private void printProperties(InputStream input) throws IOException
        {
            Properties properties = new Properties();
            properties.load(input);
            System.out.println(properties.getProperty("name"));
        }
    }

    输出结果为第二个resources文件夹下config.properties的内容:

    ConfigUnderSrc

    原因在于(请注意ReourceLoader.java文件中的红色部分):我们给出的资源文件路径(/resources/config.properties)以"/"开头,即使用的是绝对定位方式,所以找到的是直接在classpath下的resources文件夹。如果去掉资源文件文件路径前的"/",则采用的是相对定位方式,此时应该输出davenkin/resources/config.properties文件的内容。

    (二)用ClassLoader类加载资源文件

    ClassLoader类也提供和Class类相同的加载方法:

    public InputStream getResourceAsStream(String pathToConfigFile);

    用ClassLoader加载配置文件时,pathToConfigFile均不能以"/"开头,在查找时直接在classpath下进行查找。Class类在查找资源文件时,也是代理(delegate)给ClassLoader完成查找功能的,请参考Java官方文档

    在使用Class和ClassLoader加载资源文件时,有几种区别细微的方法,修改ResourceLoader.java文件如下:

    package davenkin;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.Properties;
    
    public class ResourceLoader
    {
        public static void main(String[] args) throws IOException
        {
            ResourceLoader resourceLoader = new ResourceLoader();
            resourceLoader.loadProperties1();
            resourceLoader.loadProperties2();
            resourceLoader.loadProperties3();
            resourceLoader.loadProperties4();
            resourceLoader.loadProperties5();
            resourceLoader.loadProperties6();
        }
    
        public void loadProperties1() throws IOException
        {
            InputStream input = null;
            try
            {
                input = Class.forName("davenkin.ResourceLoader").getResourceAsStream("/resources/config.properties");
            } catch (ClassNotFoundException e)
            {
                e.printStackTrace();
            }
            printProperties(input);
        }
    
        public void loadProperties2() throws IOException
        {
            InputStream input = null;
    
            input = this.getClass().getResourceAsStream("/resources/config.properties");
            printProperties(input);
        }
    
        public void loadProperties3() throws IOException
        {
            InputStream input = this.getClass().getResourceAsStream("resources/config.properties");
            printProperties(input);
        }
    
        public void loadProperties4() throws IOException
        {
            InputStream input = this.getClass().getClassLoader().getResourceAsStream("resources/config.properties");
            printProperties(input);
        }
    
        public void loadProperties5() throws IOException
        {
            InputStream input = ClassLoader.getSystemResourceAsStream("resources/config.properties");
            printProperties(input);
        }
    
        public void loadProperties6() throws IOException
        {
            InputStream input = ClassLoader.getSystemClassLoader().getResourceAsStream("resources/config.properties");
    
            printProperties(input);
        }
    
        private void printProperties(InputStream input) throws IOException
        {
            Properties properties = new Properties();
            properties.load(input);
            System.out.println(properties.getProperty("name"));
        }
    }

    以上程序输出结果为(请仔细揣摩,稍不小心(比如多加了一个"/"或少加了一个"/"),就会报NullPointerException异常,表明你的资源文件没有找到):

    ConfigUnderSrc
    ConfigUnderSrc
    ConfigUnderDavenkin
    ConfigUnderSrc
    ConfigUnderSrc
    ConfigUnderSrc
    来自:http://www.cnblogs.com/CloudTeng/archive/2012/04/08/2438028.html

    另一篇:
    mport java.net.URL; 
     
    import org.springframework.context.ApplicationContext; 
    import org.springframework.context.support.ClassPathXmlApplicationContext; 
     
    public class TestMain { 
        public static void main(String[] args) { 
     
            // ############################################################################################################ 
            // 1:使用本类的Class类的getResource()方法 
            // 在当前包寻找资源(指定相对路径,其他均返回null。) 
            URL filePathUrl1 = TestMain.class.getResource("beans_sameLocation.xml"); 
     
            // 在根寻找资源(需要文件分隔符"/",其他均返回null。) 
            URL filePathUrl2 = TestMain.class.getResource("/beans.xml"); 
     
            // 在不同包内寻找资源(指定相对路径(需要文件分隔符"/"),其他均返回null。) 
            URL filePathUrl3 = TestMain.class.getResource("/test/spring/beanpost/file/beans_diffLocation.xml"); 
     
            // ############################################################################################################ 
            // 2:使用本类的Class类的ClassLoader类的getResource()方法 
            // 在相同包内寻找资源,总是返回null。 
            // URL filePathUrl3 = 
            // TestMain.class.getClassLoader().getResource("beans_sameLocation.xml"); 
     
            // 在根寻找资源,指定相对路径,其他均返回null。 
            URL filePathUrl4 = TestMain.class.getClassLoader().getResource("beans.xml"); 
     
            // 在不同包内寻找资源,指定相对路径,其他均返回null。 
            URL filePathUrl5 = TestMain.class.getClassLoader().getResource("test/spring/beanpost/file/beans_diffLocation.xml"); 
     
            // ############################################################################################################ 
            // 3:使用ClassLoader类的getSystemResource()方法 
            // 在指定包内寻找资源,指定相对路径,其他均返回null。 
            URL filePathUrl6 = ClassLoader.getSystemResource("test/spring/beanpost/beans_sameLocation.xml"); 
            // 同上 
            URL filePathUrl7 = ClassLoader.getSystemClassLoader().getResource("test/spring/beanpost/beans_sameLocation.xml"); 
     
            // 在根寻找,指定相对路径,其他均返回null。 
            URL filePathUrl8 = ClassLoader.getSystemResource("beans.xml"); 
            // 同上 
            URL filePathUrl9 = ClassLoader.getSystemClassLoader().getResource("beans.xml"); 
     
            // ############################################################################################################ 
            // 4:使用Thread加载资源(推荐此方法) 
            // 在指定包内寻找资源,(相对路径),其他均返回null。 
            filePathUrl6 = Thread.currentThread().getContextClassLoader().getResource("test/spring/beanpost/beans_sameLocation.xml"); 
     
            // 在根寻找,(相对路径),其他均返回null。 
            filePathUrl7 = Thread.currentThread().getContextClassLoader().getResource("beans.xml"); 
     
            // 在不同包内寻找资源,(相对路径),其他均返回null。 
            filePathUrl8 = Thread.currentThread().getContextClassLoader().getResource("test/spring/beanpost/file/beans_diffLocation.xml"); 
     
            // ############################################################################################################ 
     
            System.out.println(filePathUrl1.getFile()); 
            System.out.println(filePathUrl2.getFile()); 
            System.out.println(filePathUrl3.getFile()); 
            System.out.println(filePathUrl4.getFile()); 
            System.out.println(filePathUrl5.getFile()); 
            System.out.println(filePathUrl6.getFile()); 
            System.out.println(filePathUrl7.getFile()); 
            System.out.println(filePathUrl8.getFile()); 
            System.out.println(filePathUrl9.getFile()); 
            System.out.println("----------------------------------------------------------------------------------------"); 
            System.getProperties().list(System.out); 
            System.out.println("----------------------------------------------------------------------------------------"); 
     
            ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml"); 
            Animal animal = (Animal) ac.getBean("animal"); 
            System.out.println(animal.speak()); 
            animal.setAge(88); 
     
            Animal animal0 = (Animal) ac.getBean("animal"); 
            System.out.println(animal0.speak()); 
     
            ApplicationContext ac1 = new ClassPathXmlApplicationContext("beans.xml"); 
            Animal animal1 = (Animal) ac1.getBean("animal"); 
            System.out.println(animal1.speak()); 
        } 
    } 

    可以参考:http://www.haogongju.net/art/1680442 写的很好。

     用JAVA获取文件,听似简单,但对于很多像我这样的新人来说,还是掌握颇浅,用起来感觉颇深,大常最经常用的,就是用JAVA的File类,如要取得c:/test.txt文件,就会这样用File file = new File("c:/test.txt");这样用有什么问题,相信大家都知道,就是路径硬编码,对于JAVA精神来说,应用应该一次成型,到处可用,并且从现实应用来讲,最终生成的应用也会部署到Windows外的操作系统中,对于linux来说,在应用中用了c:/这样的字样,就是失败,所以,我们应该尽量避免使用硬编码,即直接使用绝对路径。

      在Servlet应用中,有一个getRealPath(String str)的方法,这个方法尽管也可以动态地获得文件的路径,不秘直接手写绝对路径,但这也是一个不被建议使用的方法,那么,我们有什么方法可以更好地获得文件呢?

          那就是Class.getResource()与Class.getResourceAsStream()方法,但很多人还是不太懂它的用法,因为很多人(比如不久前的我)都不知道应该传怎么样的参数给它,当然,有些人己经用得如火纯青,这些人是不需要照顾的,在此仅给不会或者还不是很熟的人解释一点点。

    比如我们有以下目录

    |--project

        |--src

            |--javaapplication

                |--Test.java

                |--file1.txt

            |--file2.txt

        |--build 

            |--javaapplication

                |--Test.class

                |--file3.txt

            |--file4.txt

    在上面的目录中,有一个src目录,这是JAVA源文件的目录,有一个build目录,这是JAVA编译后文件(.class文件等)的存放目录

    那么,我们在Test类中应该如何分别获得

    file1.txt  file2.txt  file3.txt  file4.txt这四个文件呢?

    首先讲file3.txt与file4.txt

    file3.txt:

    方法一:File file3 = new File(Test.class.getResource("file3.txt").getFile());  url.getFile Gets the file name of this URL

    方法二:File file3 = new File(Test.class.getResource("/javaapplication/file3.txt").getFile());

    方法三:File file3 = new File(Test.class.getClassLoader().getResource("javaapplication/file3.txt").getFile());

    file4.txt:

    方法一:File file4 = new File(Test.class.getResource("/file4.txt").getFile());

    方法二:File file4 = new File(Test.class.getClassLoader().getResource("file4.txt").getFile());

    很好,我们可以有多种方法选择,但是file1与file2文件呢?如何获得?

    答案是,你只能写上它们的绝对路径,不能像file3与file4一样用class.getResource()这种方法获得,它们的获取方法如下

    假如整个project目录放在c:/下,那么file1与file2的获取方法分别为

    file1.txt

    方法一:File file1 = new File("c:/project/src/javaapplication/file1.txt");

    方法二:。。。没有

    file2.txt

    方法一:File file2 = new File("c:/project/src/file2.txt");

    方法二:。。。也没有

    总结一下,就是你想获得文件,你得从最终生成的.class文件为着手点,不要以.java文件的路径为出发点,因为真正使用的就是.class,不会拿个.java文件就使用,因为java是编译型语言嘛

    至于getResouce()方法的参数,你以class为出发点,再结合相对路径的概念,就可以准确地定位资源文件了,至于它的根目录嘛,你用不同的IDE build出来是不同的位置下的,不过都是以顶层package作为根目录,比如在Web应用中,有一个WEB-INF的目录,WEB-INF目录里面除了web.xml文件外,还有一个classes目录,没错了,它就是你这个WEB应用的package的顶层目录,也是所有.class的根目录“/”,假如clasaes目录下面有一个file.txt文件,它的相对路径就是"/file.txt",如果相对路径不是以"/"开头,那么它就是相对于.class的路径。。

    还有一个getResourceAsStream()方法,参数是与getResouce()方法是一样的,它相当于你用getResource()取得File文件后,再new InputStream(file)一样的结果

    via:http://gavin-chen.iteye.com/blog/261151

    难经2:URL.getFile(),是你让老虎落入陷阱?:http://liuu.iteye.com/blog/300618

    url使用例子:

    // File Name : URLDemo.java
    
    import java.net.*;
    import java.io.*;
    
    public class URLDemo
    {
       public static void main(String [] args)
       {
          try
          {
             URL url = new URL(args[0]);
             System.out.println("URL is " + url.toString());
             System.out.println("protocol is "
                                        + url.getProtocol());
             System.out.println("authority is "
                                        + url.getAuthority());
             System.out.println("file name is " + url.getFile());
             System.out.println("host is " + url.getHost());
             System.out.println("path is " + url.getPath());
             System.out.println("port is " + url.getPort());
             System.out.println("default port is "
                                       + url.getDefaultPort());
             System.out.println("query is " + url.getQuery());
             System.out.println("ref is " + url.getRef());
          }catch(IOException e)
          {
             e.printStackTrace();
          }
       }
    }

    A sample run of the thid program would produce following result:

    $ java URLDemo http://www.amrood.com/index.htm?language=en#j2se
    URL is http://www.amrood.com/index.htm?language=en#j2se
    protocol is http
    authority is www.amrood.com
    file name is /index.htm?language=en
    host is www.amrood.com
    path is /index.htm
    port is -1
    default port is 80
    query is language=en
    ref is j2se

    注意file name 包括路径。

     

  • 相关阅读:
    ORACLE定时备份
    解压cpio.gz
    Fusioncharts的数字格式化
    linux apache+php+mysql安装及乱码解决办法
    两个Beta函数类型的积分及其一般形式
    【转载】巴塞尔问题(Basel Problem)的多种解法
    两本关于各种刁钻积分计算的书
    一个超几何函数类型的积分
    一个取整函数积分的一般形式
    Clausen Functions (and related series, functions, integrals)
  • 原文地址:https://www.cnblogs.com/youxin/p/2783677.html
Copyright © 2020-2023  润新知