zoukankan      html  css  js  c++  java
  • 你知道怎么从jar包里获取一个文件的内容吗

    背景

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

    报错的代码

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

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

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

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

    原先的写法

    有两种获取资源的方法,第一种就是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包的形式运行,打包运行后就报如下的错误:
    Caused by: java.io.FileNotFoundException: File 'file:/Users/xxx/spring-boot-study/target/classes/Template.xlsx' does not exist
    

    定位到问题,如下:

    编写测试类

    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();
        }
    }
    
  • 相关阅读:
    dedecms如何调用当前栏目的子栏目及子栏目文章
    dedecms调用当前栏目的子栏目怎么操作
    dedecms如何增加自定义字段
    关于朋友圈你所不知道的内幕
    dedecms如何快速删除跳转的文章(记得清空内容回收站)
    帝国cms调用栏目自定义字段(栏目简介)如何操作
    Introduction To Monte Carlo Methods
    Solr学习笔记-在Tomcat上部署执行Solr
    POJ 2029--Get Many Persimmon Trees +DP
    SNMP协议总结
  • 原文地址:https://www.cnblogs.com/eaglelihh/p/15219826.html
Copyright © 2011-2022 走看看