你知道怎么从jar包里获取一个文件的内容吗

背景

项目里需要获取一个excle文件,然后对其里的内容进行修改,这个文件在jar包里,怎么尝试都读取不成功,但是觉得肯定可以做到,因为项目里的配置文件就可以读取到,于是开始了探索之路。

报错的代码

ExcelWriter excelWriter = EasyExcel.write("to.xlsx").withTemplate(t).build();

我想要成功调用以上的方法,需要读取一个文件的内容,然后写入到另一个文件中

withTemplate的参数可以是 String类型的文件路径, File类型InputStream类型的,具体如下:

你知道怎么从jar包里获取一个文件的内容吗

现在的问题就是如何传入一个正确的参数,使它正常工作

原先的写法

有两种获取资源的方法,第一种就是 Class.getResource(),第二种就是 ClassLoader.getResource()

于是有了如下的第一版写法:

public class Main {
    public static void main(String[] args) throws IOException {
        URL url = Main.class.getResource("/Template.xlsx");
        File file = new File(url.getFile());
        ExcelWriter excelWriter = EasyExcel.write("to.xlsx").withTemplate(file).build();
        excelWriter.finish();
    }
}

文件的位置如下:

你知道怎么从jar包里获取一个文件的内容吗
本地测试是没有问题的,但是项目需要打包,以jar包的形式运行,打包运行后就报如下的错误:
Caused by: java.io.FileNotFoundException: File 'file:/Users/xxx/spring-boot-study/target/classes/Template.xlsx' does not exist

定位到问题,如下:

你知道怎么从jar包里获取一个文件的内容吗

编写测试类

public class JarFileMain {
    public static void main(String[] args) {
        printFile(JarFileMain.class.getResource("/Template.xlsx"));
    }

    private static void printFile(URL url) {
        if (url == null) {
            System.out.println("null null");
            return;
        }
        File file1 = new File(url.getFile());
        System.out.println(file1 + " " + file1.exists());
        File file2 = new File(url.toString());
        System.out.println(file2 + " " + file2.exists());
    }
}

直接这样运行是没有问题的,输出结果如下:

/Users/xxx/spring-boot-study/target/classes/Template.xlsx true
file:/Users/xxx/spring-boot-study/target/classes/Template.xlsx false

但是打成jar包后,运行结果如下:

java -cp /Users/xxx/spring-boot-study/target/spring-boot-study-1.0-SNAPSHOT.jar  cn.eagleli.java.resource.JarFileMain
file:/Users/xxx/spring-boot-study/target/spring-boot-study-1.0-SNAPSHOT.jar!/Template.xlsx false
jar:file:/Users/xxx/spring-boot-study/target/spring-boot-study-1.0-SNAPSHOT.jar!/Template.xlsx false

可以看出没有打成包的时候,文件是存在的;但是打包后运行时,文件就不存在了。

找原因

因为项目里的 config.xml文件里有一些配置信息的,而且是可以读取成功的,所以肯定有办法读取到内容的,于是就看了这部分的代码。

核心代码如下:

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.XMLConfiguration;
import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;

public class ClassPathConfigPropertySource implements PropertySource {
    private XMLConfiguration config;

    public ClassPathConfigPropertySource() {
        try {
            config = new XMLConfiguration(ClassPathConfigPropertySource.class.getClassLoader().getResource("config.xml"));
            config.setReloadingStrategy(new FileChangedReloadingStrategy());
        } catch (ConfigurationException e) {

        }
    }

    @Override
    public void setProperty(String key, Object value) {
        if (config != null) {
            config.setProperty(key, value);
        }
    }

    @Override
    public Object getProperty(String key) {
        if (config != null) {
            return config.getProperty(key);
        }

        return null;
    }
}

可以看出,这个类的工作其实是 XMLConfiguration这个类来完成的,看看它的构造函数是如何初始化的

读取文件内容的核心代码如下:

public abstract class AbstractFileConfiguration extends BaseConfiguration implements FileConfiguration {
    public void load(URL url) throws ConfigurationException
    {
        if (sourceURL == null)
        {
            if (StringUtils.isEmpty(getBasePath()))
            {
                // ensure that we have a valid base path
                setBasePath(url.toString());
            }
            sourceURL = url;
        }

        // throw an exception if the target URL is a directory
        File file = ConfigurationUtils.fileFromURL(url);
        if (file != null && file.isDirectory())
        {
            throw new ConfigurationException("Cannot load a configuration from a directory");
        }

        InputStream in = null;

        try
        {
            in = url.openStream();
            load(in);
        }
        catch (ConfigurationException e)
        {
            throw e;
        }
        catch (Exception e)
        {
            throw new ConfigurationException("Unable to load the configuration from the URL " + url, e);
        }
        finally
        {
            // close the input stream
            try
            {
                if (in != null)
                {
                    in.close();
                }
            }
            catch (IOException e)
            {
                getLogger().warn("Could not close input stream", e);
            }
        }
    }
}

可见它没有把 URL转为 File,而是直接用的 InputStream in = url.openStream();

最终代码

public class Main {
    public static void main(String[] args) throws IOException {
        URL url = Main.class.getResource("/Template.xlsx");
        //File file = new File(url.getFile());
        ExcelWriter excelWriter = EasyExcel.write("to.xlsx").withTemplate(url.openStream()).build();
        excelWriter.finish();
    }
}

Original: https://www.cnblogs.com/eaglelihh/p/15219826.html
Author: eaglelihh
Title: 你知道怎么从jar包里获取一个文件的内容吗

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/587209/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Tomcat中的观察者模式 (Lifecycle)

    几个重要的类,接口 LifeCycle : 主题接口 LifeCycleBase : 抽象的主题实现 LifeCycleListener : 观察者 具体分析 public int…

    Java 2023年6月6日
    089
  • mysql出现serverTimezone问题

    jdbc:mysql://172.16.50.141:3306/tx-manager?serverTimezone=Asia/Shanghai&characterEncod…

    Java 2023年6月16日
    073
  • java XML标记语言

    可扩展标记语言( Extensive Markup Language),标签中的元素名是可以自己随意写,可拓展是相对于html来说 标记语言:由一对尖括号括起来 用来当做配置文件 …

    Java 2023年6月6日
    084
  • JDK成长记6:你了解LinkedList的五脏六腑么?

    上一节你看过了LinkedList的add方法源码,是不是已经打开了思路呢?其实核心原理就是辅助指针+Node双向链表数据结构而已。 相信经过前面的学习,你应该热身完毕了,之后的学…

    Java 2023年6月5日
    099
  • 官方文档中文版!Spring Cloud Stream 快速入门

    本文内容翻译自官方文档,spring-cloud-stream docs,对 Spring Cloud Stream的应用入门介绍。 一、Spring Cloud Stream 简…

    Java 2023年5月30日
    0127
  • IDEA 启动报错 java.nio.charset.MalformedInputException: Input length=2

    idea 启动提示 other.xml 无法解析 …… cannot parse file other.xml: java.nio.charset.Malf…

    Java 2023年5月29日
    081
  • Swagger UI 与SpringMVC的整合

    关于 Swagger Swagger能成为最受欢迎的REST APIs文档生成工具之一,有以下几个原因: Swagger 可以生成一个具有互动性的API控制台,开发者可以用来快速学…

    Java 2023年5月30日
    096
  • SpringCloud 使用 Feign各 种报错

    由于只想在SpringBoot中使用一下Feign客户端,来访问第三方请求,但因为各种版本问题,一直报各种乱七八糟的错 pom文件 <span class="hlj…

    Java 2023年6月7日
    084
  • markdown语法

    1.标题 //&#x6807;&#x9898;&#x4E00;&#x5171;&#x516D;&#x4E2A;&#x7EA7…

    Java 2023年6月5日
    0114
  • Mybatis运行原理

    Mybatis运行原理 先是简要的文字说明,后面放上图。如有叙述错误,感谢指正哈。 一、 根据配置文件创建SQLSessionFactory 首先将配置文件转化为流,创建SqlSe…

    Java 2023年6月8日
    091
  • 随机生成数组+冒泡排序

    示例如下: public class MaoPaoPaiXu { public static int[] mp(int[] nums) { for (int i = 0; i &l…

    Java 2023年6月6日
    0124
  • Vue(十二)—组件通信

    参考文章:https://blog.csdn.net/qq_37288477/article/details/86630428 父子通信: 1.父传子props 官网demo:ht…

    Java 2023年6月13日
    085
  • 自定义线程池配置类

    1、线程池参数 /** * @author houChen * @date 2021/12/11 11:05 * @Description: 线程池参数 */ @Component…

    Java 2023年5月30日
    088
  • SpringBoot学习(十)Spring集成、会话、(监视和管理JMX)、WebSockets和web服务

    一、Spring集成 Spring Boot为使用Spring Integration提供了一些便利,包括spring-boot-starter-integration &#822…

    Java 2023年5月30日
    0116
  • Java微服务分布式架构

    摘自《Java微服务分布式架构企业实战》 1.传统单体应用架构存在的问题一个完整的单体应用程序通常主要由三部分组成:客户端用户界面、模块和数据库,如图1.1所示。传统单体应用的开发…

    Java 2023年5月29日
    092
  • 8.java NIO

    1.简介 2.NIO和BIO的比较 1.BIO以流的方式处理数据,而NIO以块的放还是处理数据,块的I/O都效率比流的I/O高很多 2.BIO是阻塞的,NIO是非阻塞的 3.BIO…

    Java 2023年6月5日
    072
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球