当前位置:   article > 正文

ClassPathResource 读取文件本地正常打包后异常_java -jar classpathresource

java -jar classpathresource

ClassPathResource 读取文件本地正常打包后异常

代码:

image-20200807115640657

里面使用了classPathResource.getFile().listFiles()获取一个目录下全部的文件,然后返回的是file数组

文件放在了resource下的一个目录中

image-20200807115906279

在本地正常使用,但是打成jar包,部署到服务器,使用java -jar启动后,出现异常:

image-20200807120051836

从异常中来看,大概是说:目标目录在一个jar包里面,我们使用的是ClassPathResource的getFile方法获取了目录的file对象,然后通过listFiles获取目录下全部的文件。

问题就在这里:

image-20200807120335622

通过转换绝对路径,然后直接读取

image-20200807120447052

File类需要的路径是一个独立的文件的路径,但是我们给的是jar内的一个路径,就无法读取了。

网上也有很多这样的资料,我也没有一一尝试,或许网上的解决方案对于我来说也可行。

我说下我的解决方案,仅供参考:

因为我读取的是一个xml文件,后面需要使用SAXReader解析xml的。在xml中引入了.dtd文件。

这是解析的代码

image-20200807120749108

我直接给reader.read传入一个文件对象,就行了。

但是现在使用ClassPathResource无法直接获取到file对象。

通过查看网上的资料,说使用流可以。

于是就修改成:reader.read(classPathResource.getInputSttream())

这个编译到是也没有问题,但是在运行的时候,出现了异常:

image-20200807121137010

后来想了想,应该是xml中配置的dtd是相对路径,但是解析的时候变成绝对路径的时候出错了

于是使用reader.read(classPathResource.getInputStream(), "classpath:" + dtdpath);本地又可以启动了。

同时服务器启动也正常了。

————————————————————————————2021-05-08
有些小伙伴对具体的实现有些疑问,我就把源码发下:

    private Map<String, byte[]> readCommonQueryResource() throws CommQueryResourceException {
        Map<String, byte[]> result = new HashMap<>();
        try {
            // 获取当前类的类加载器,然后通过 类加载器得到指定目录的 uri,并且得到这个uri的链接对象
            // QUERY_FILES_PATH是resource下的目录。resource目录会被打到jar包里面
            URLConnection connection = LoadXml2RedisGenQuery.class.getClassLoader().getResource(QUERY_FILES_PATH).openConnection();
            // 如果连接对象是jar类型的链接对象,表示指定目录是jar包内的目录
            if (connection instanceof JarURLConnection) {
                // 此时将链接对象转为jar类型的链接对象
                JarURLConnection jarCon = (JarURLConnection) connection;
                // 设置不使用缓存
                jarCon.setUseCaches(false);
                // 然后获取到jar文件对象
                JarFile jarFile = jarCon.getJarFile();
                // 这里不能使用stream,使用stream,会出现zipifile is closed异常。里面源码相同,应该是兼容性问题吧.
                Enumeration<JarEntry> entries = jarFile.entries();
                // 通过jarFile对象获取jar里面的文件
                while (entries.hasMoreElements()) {
                    JarEntry jarEntry = entries.nextElement();
                    String jarEntryName = jarEntry.getName();
                    // 只要指定前缀文件的字节流,或者是指定格式的文件的字节流
                    // 这里使用循环处理
                    // 举个例子:假设我们的resource目录下有一个testxml目录
                    // testxml目录下有很多xml,里面有些是test_1_x.xml
                    // 有些是test_2_x.xml
                    // 我们这里的QUERY_FILES_PATH 就是test_1,QUERY_FILE_NAME_PATTERN就是x
                    // 如果还有test_1_a_x.xml和test_1_a_y.xml
                    // 那么最终会在map中存储test_1_x.xml,test_1_a_x.xml的文件的key以及这两个文件对应的字节流
                    // 我们拿到了字节流,就可以读取具体的文件内容了
                    // 如果需要修改文件,貌似应该也可以,因为我们能拿到jarFile对象,修改jar里面的文件,都是通过jarFile操作的
                    // jarFile是一个操作jar文件的工具类
                    // jar文件实际上就是一个压缩包
                    // 你如果想操作jar包,那么对比下操作压缩包,类似的实现
                    // 需要注意的是这里得到的文件名称都是uri格式的,而且是类似于jar:xx/xxx/xx/xml格式
                    if (jarEntryName.startsWith(QUERY_FILES_PATH) && !jarEntry.isDirectory() &&
                            jarEntryName.matches(QUERY_FILES_PATH + QUERY_FILE_NAME_PATTERN)) {
                        InputStream inputStream = jarFile.getInputStream(jarEntry);
                        result.put(jarEntryName, inputStream == null ? new byte[0] : inputStream.readAllBytes());
                    }
                }
            } else {
            // 如果是其他的链接类型,那么至少不是jar包,那么就可以用读取文件的方式读取
                ClassPathResource classPathResource = new ClassPathResource(QUERY_FILES_PATH);
                // 我们通过链接得到了文件夹的字符串
                String fileNames = new String(connection.getInputStream().readAllBytes());
                if (classPathResource.exists()) {
                    for (String fileName : fileNames.split("\n")) {
                        if (fileName.matches(QUERY_FILE_NAME_PATTERN)) {
                            ClassPathResource resource = new ClassPathResource(QUERY_FILES_PATH + fileName);
                            if (resource.exists()) {
                                InputStream inputStream = resource.getInputStream();
                                result.put(fileName, inputStream == null ? new byte[0] : inputStream.readAllBytes());
                            }
                        }
                    }
                }
            }
        } catch (IOException e) {
            throw CommQueryResourceException.getException(e);
        }
        return result;
    }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63

操作jar包,我们需要知道我们实际上操作的是压缩包,然后按照压缩包操作的流程处理即可。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/煮酒与君饮/article/detail/815943
推荐阅读
相关标签
  

闽ICP备14008679号