• Java IO: 读取classpath资源


    classpath

    classpath是JVM用到的一个环境变量,它用来指示JVM如何搜索class。因为Java是编译型语言,源码文件是.java,而编译后的.class文件才是真正可以被JVM执行的字节码。因此,JVM需要知道,如果要加载一个abc.xyz.Hello的类,应该去哪搜索对应的Hello.class文件。所以,classpath就是一组目录的集合,它设置的搜索路径与操作系统相关。例如,在Windows系统上,用;分隔,带空格的目录用""括起来,可能长这样:

    C:workproject1in;C:shared;"D:My Documentsproject1in"
    

    在Linux系统上,用:分隔,可能长这样:

    /usr/shared:/usr/local/bin:/home/liaoxuefeng/bin
    

    现在我们假设classpath.;C:workproject1in;C:shared,当JVM在加载abc.xyz.Hello这个类时,会依次查找:

    • <当前目录>abcxyzHello.class
    • C:workproject1inabcxyzHello.class
    • C:sharedabcxyzHello.class

    注意到.代表当前目录。如果JVM在某个路径下找到了对应的class文件,就不再往后继续搜索。如果所有路径下都没有找到,就报错。

    classpath的设定方法

    classpath的设定方法有两种:

    1. 在系统环境变量中设置classpath环境变量,不推荐;

    2. 在启动JVM时设置classpath变量,推荐。

    强烈不推荐在系统环境变量中设置classpath,那样会污染整个系统环境。在启动JVM时设置classpath才是推荐的做法。实际上就是给java命令传入-classpath-cp参数:

    java -classpath .;C:workproject1in;C:shared abc.xyz.Hello
    

    或者使用-cp的简写:

    java -cp .;C:workproject1in;C:shared abc.xyz.Hello
    

    没有设置系统环境变量,也没有传入-cp参数,那么JVM默认的classpath.,即当前目录:

    java abc.xyz.Hello
    

    上述命令告诉JVM只在当前目录搜索Hello.class

    在IDE中运行Java程序,IDE自动传入的-cp参数是当前工程的bin目录和引入的jar包。通常,我们在自己编写的class中,会引用Java核心库的class,例如,StringArrayList等。这些class应该上哪去找?不需要告诉JVM如何去Java核心库查找class,JVM可以自主找到自己的核心库。 不要把任何Java核心库添加到classpath中!JVM根本不依赖classpath加载核心库!更好的做法是,不要设置classpath!默认的当前目录.对于绝大多数情况都够用了。

    从classpath读取文件

    很多Java程序启动的时候,都需要读取配置文件。例如,从一个.properties文件中读取配置:

    String conf = "C:\conf\default.properties";
    try (InputStream input = new FileInputStream(conf)) {
        // TODO:
    }
    

    这段代码要正常执行,必须在C盘创建conf目录,然后在目录里创建default.properties文件。但是,在Linux系统上,路径和Windows的又不一样。因此,从磁盘的固定目录读取配置文件,不是一个好的办法。

    有没有路径无关的读取文件的方式呢?

    从classpath读取文件就可以避免不同环境下文件路径不一致的问题:如果我们把default.properties文件放到classpath中,就不用关心它的实际存放路径。

    在classpath中的资源文件,路径总是以开头,我们先获取当前的Class对象,然后调用getResourceAsStream() 就可以直接从classpath读取任意的资源文件:

    try (InputStream input = getClass().getResourceAsStream("/default.properties")) {
        // TODO:
    }
    

    调用getResourceAsStream()需要特别注意的一点是,如果资源文件不存在,它将返回null。因此,我们需要检查返回的InputStream是否为null,如果为null,表示资源文件在classpath中没有找到:

    try (InputStream input = getClass().getResourceAsStream("/default.properties")) {
        if (input != null) {
            // TODO:
        }
    }
    

    如果我们把默认的配置放到jar包中,再从外部文件系统读取一个可选的配置文件,就可以做到既有默认的配置文件,又可以让用户自己修改配置:

    Properties props = new Properties();
    props.load(inputStreamFromClassPath("/default.properties"));
    props.load(inputStreamFromFile("./conf.properties"));
    

    这样读取配置文件,应用程序启动就更加灵活。

    小结

    把资源存储在classpath中可以避免文件路径依赖;Class对象的getResourceAsStream()可以从classpath中读取指定资源;

    根据classpath读取资源时,需要检查返回的InputStream是否为null

  • 相关阅读:
    屏蔽2003:在系统启动时至少有一个服务或驱动程序产生错误
    C#中有关string和byte[]转换的问题
    如何控制winform程序只能打开一个呢?
    ArrayList的使用方法【转载】
    ASP.NET中ajaX学习记录
    C#去除字符串空格的几种方法【转载】
    C# 中2,10,16进制及其ASCII码之间转化
    vc++下char数组赋值乱码问题
    c#关机时自动退出程序
    Android入门前言(一)之Android应用开发入门五问 (转自:http://blog.csdn.net/android_tutor/)
  • 原文地址:https://www.cnblogs.com/jianhaoscnu/p/13539941.html
Copyright © 2020-2023  润新知