jar资源文件处理方式

参考

主题:【解惑】深入jar包:从jar包中读取资源文件
java读取jar包中的文件

总结

读取资源文件

问题描述:资源文件在单独运行的时候没有问题。但是把代码打成一个jar包以后,即使将资源文件一并打包,这些东西也找不出来了。

public static void getResourcefile() throws IOException {
    prop= new Properties();
    FileInputStream fis = new FileInputStream("src/main/resources/sys.cfg");
    prop.load(fis);
    fis.close();
    System.out.println(prop.get("key1"));
    System.out.println(prop.get("key2"));
} 

jar包执行

java -classpath resource-1.0-SNAPSHOT.jar getResource  
java.io.FileNotFoundException: src/main/resources/sys.cfg (No such file or directory)
        at java.io.FileInputStream.open0(Native Method)
        at java.io.FileInputStream.open(FileInputStream.java:195)
        at java.io.FileInputStream.<init>(FileInputStream.java:138)
        at java.io.FileInputStream.<init>(FileInputStream.java:93)
        at getResource.getResourcefile(getResource.java:12)
        at getResource.main(getResource.java:31)

主要是因为jar包有自己读取文件的特殊方式,不能简单的使用"/Users…/src/main/resources/sys.cfg"这种形式的文件URL来定位res.txt。即使是相对路径,也无法定位到jar文件内的txt文件。

解决方式
类装载器(ClassLoader)
(1) ClassLoader 是类加载器的抽象类。它可以在运行时动态的获取加载类的运行信息。 可以这样说,当我们调用类时,JVM加载进getResource类,并记录下Resource运行时信息(包括Resource所在jar包的路径信息),而ClassLoader类中的方法可以帮助我们动态的获取这些信息。

public URL getResource(String name) 
//查找具有给定名称的资源。资源是可以通过类代码以与代码基无关的方式访问的一些数据(图像、声音、文本等)。并返回资源的URL对象。
public InputStream getResourceAsStream(String name)
//返回读取指定资源的输入流。这个方法很重要,可以直接获得jar包中文件的内容。

(2) ClassLoader是abstract的,不可能实例化对象,更加不可能通过ClassLoader调用上面两个方法。所以我们真正写代码的时候,是通过Class类中的getResource()和getResourceAsStream()方法,这两个方法会委托ClassLoader中的getResource()和getResourceAsStream()方法 。

public static void getResourcefile() throws IOException {
    prop= new Properties();
    URL fileURL = getResource.class.getClassLoader().getResource("sys.cfg");
    System.out.println(fileURL);
    FileInputStream fis = new FileInputStream(fileURL.getPath());
    prop.load(fis);
    fis.close();
    System.out.println(prop.get("key1"));
    System.out.println(prop.get("key2"));
}

jar包执行

java -classpath resource-1.0-SNAPSHOT.jar getResource
jar:file:/Users/IdeaProjects/resource/target/resource-1.0-SNAPSHOT.jar!/sys.cfg
java.io.FileNotFoundException: file:/Users/IdeaProjects/resource/target/resource-1.0-SNAPSHOT.jar!/sys.cfg (No such file or directory)
        at java.io.FileInputStream.open0(Native Method)
        at java.io.FileInputStream.open(FileInputStream.java:195)
        at java.io.FileInputStream.<init>(FileInputStream.java:138)
        at java.io.FileInputStream.<init>(FileInputStream.java:93)
        at getResource.getResourcefile(getResource.java:14)
        at getResource.main(getResource.java:33)

失败原因
"file:/Users…/resource-1.0-SNAPSHOT.jar!/sys.cfg"并不是文件资源定位符的格式 (jar中资源有其专门的URL形式: jar:<url>!/{entry} )。所以,定位不到文件资源。
但可以通过Class类的getResourceAsStream()方法来获取 ,这种方法是如何读取jar中的资源文件的,这一点对于我们来说是透明的

public static void getResourcefile() throws IOException {
    prop= new Properties();
    InputStream fis = getResource.class.getClassLoader().getResourceAsStream("sys.cfg");
    prop.load(fis);
    fis.close();
    System.out.println(prop.get("key1"));
    System.out.println(prop.get("key2"));
}

执行

java -classpath resource-1.0-SNAPSHOT.jar getResource
value1
value2

注意点

jar包里面的文件要分大小写的,但找外面的文件名可以不分
java.util.jar.JarFile
URL是不支持中文的。URI才支持

改写资源文件

初次使用jar中资源文件

不要死扣非得读写jar中的资源文件,只有当软件第一次启动程序时才读jar中的资源文件,并将其备份到用户主目录或用户当前目录中,以后读写用户目录中的资源文件即可。只有当用户目录中的资源文件不存在时(这里程序可以判断一下),才从jar中的资源文件读信息,因此jar中的资源文件只是起到原始备份作用。
当然,这样做会有一些问题
(1) 就是每次程序安装在一新机器上时,读取的资源文件信息都是jar中的原始资源信息,中途我们可能更新过
解决方法:将更新的资源文件再一次打包到jar中
(2) 由于每次对资源文件信息的更新都是对对应的内存数据的更新,只有在关闭程序时才写回到资源文件中,没有随改随写,这样就可能造成这样一种后果,如果程序不是很健壮,程序中途bug并无响应,此时只能强制关闭,务必造成更新的资源信息没有写回到资源文件中!!!
解决方案:每次对内存中资源信息的更新后马上写回到文件中

import java.io.*;
import java.util.Properties;

public class getResource {
    public static Properties prop;
    public static void getResourcefile() throws IOException {
        prop= new Properties();
        File file = new File("sys.cfg");
        InputStream fis = null;
        if(file.exists()){
            fis = new FileInputStream(file);
        }else {
            fis = getResource.class.getClassLoader().getResourceAsStream("sys.cfg");
        }
        prop.load(fis);
        fis.close();
        System.out.println(prop.get("key1"));
        System.out.println(prop.get("key2"));
    }
    public static void setResourcefile() throws IOException {
        prop.setProperty("key1", "value1_other");
        prop.setProperty("key2", "value2_other");

        FileOutputStream fos = new FileOutputStream("sys.cfg");
        prop.store(fos, "modify");
        fos.close();
        fos.flush();
    }
    public static void main(String[] args){
        try {
            getResourcefile();
            setResourcefile();
            getResourcefile();
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值