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

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

代码:

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

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

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

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

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

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

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

问题就在这里:

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

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

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

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

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

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

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

这是解析的代码

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

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

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

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

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

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

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

后来想了想,应该是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;
    }

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

    原文作者:a18792721831
    原文地址: https://blog.csdn.net/a18792721831/article/details/107860718
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞