赞
踩
代码:
里面使用了classPathResource.getFile().listFiles()
获取一个目录下全部的文件,然后返回的是file数组。
文件放在了resource下的一个目录中
在本地正常使用,但是打成jar包,部署到服务器,使用java -jar
启动后,出现异常:
从异常中来看,大概是说:目标目录在一个jar包里面,我们使用的是ClassPathResource
的getFile方法获取了目录的file对象,然后通过listFiles获取目录下全部的文件。
问题就在这里:
通过转换绝对路径,然后直接读取
File类需要的路径是一个独立的文件的路径,但是我们给的是jar内的一个路径,就无法读取了。
网上也有很多这样的资料,我也没有一一尝试,或许网上的解决方案对于我来说也可行。
我说下我的解决方案,仅供参考:
因为我读取的是一个xml文件,后面需要使用SAXReader解析xml的。在xml中引入了.dtd文件。
这是解析的代码
我直接给reader.read传入一个文件对象,就行了。
但是现在使用ClassPathResource无法直接获取到file对象。
通过查看网上的资料,说使用流可以。
于是就修改成:reader.read(classPathResource.getInputSttream())
这个编译到是也没有问题,但是在运行的时候,出现了异常:
后来想了想,应该是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包,我们需要知道我们实际上操作的是压缩包,然后按照压缩包操作的流程处理即可。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。