背景:
以jar包运行时,获取文件目录时,会报错;
idea运行不会报错。
代码:
- //复制文件夹到指定路径下
- String srcFilePath = Thread.currentThread().getContextClassLoader().getResource("").getPath()
- + "/templates";
- FileUtils.copyFolder(new File(srcFilePath), dir);
-
- /**
- * 文件夹的复制
- * @param srcFile 源文件夹File对象
- * @param destFile 目标文件夹File对象
- * @throws IOException IOException
- */
- public static void copyFolder(File srcFile, File destFile) throws IOException {
- //判断数据源File是否是文件
- if (srcFile.isDirectory()) {
- //在目的地下创建和数据源File名称一样的目录
- String srcFileName = srcFile.getName();
- File newFolder = new File(destFile, srcFileName);
- if (!newFolder.exists()) {
- newFolder.mkdir();
- }
- //获取数据源File下所有文件或者目录的File数组
- File[] listFiles = srcFile.listFiles();
-
- //遍历该File数组,得到每一个File对象
- for (File file : listFiles) {
- //把该File作为数据源File对象,递归调用复制文件夹的方法
- copyFolder(file, newFolder);
- }
- } else {
- //说明是文件,直接用字节流复制
- File newFile = new File(destFile, srcFile.getName());
- copyFile(srcFile, newFile);
- }
-
- }
-
- /**
- * 复制文件
- * @param srcFile 源文件
- * @param destFile 目标文件
- * @throws IOException IOException
- */
- public static void copyFile(File srcFile, File destFile) throws IOException {
- BufferedInputStream bis = null;
- BufferedOutputStream bos = null;
- try {
- if (!destFile.getParentFile().exists()) {
- destFile.getParentFile().mkdirs();
- }
-
- if (!destFile.exists()) {
- destFile.createNewFile();
- }
-
- bis = new BufferedInputStream(new FileInputStream(srcFile));
- bos = new BufferedOutputStream(new FileOutputStream(destFile));
-
- int len;
- byte[] bys = new byte[1024];
- while ((len = bis.read(bys)) != -1) {
- bos.write(bys, 0, len);
- }
- } finally {
-
- if (null != bos) {
- try {
- bos.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- if (null != bis) {
- try {
- bis.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
这行:bis = new BufferedInputStream(new FileInputStream(srcFile));
文件复制时,报错:
java.io.FileNotFoundException: file:/xxx/xxx.jar!/BOOT-INF/classes!/xxx/xxx (No such file or directory)
或
java.io.FileNotFoundException: file:\xxx\xxx.jar!\BOOT-INF\classes!\xxx\xxx (文件名、目录名或卷标语法不正确。)
问题产生原因:当我们使用文件路径访问文件时,该路径下的文件必须是可访问的,而jar文件本质是上是一个压缩文件,需要解压才能访问,所以程序会直接报错。
解决方案:
更改复制文件夹方式,不读文件路径,直接读取文件流。
以jar包运行时,不能使用resource.getFile()获取文件路径、判断是否为文件等,会报错:
java.io.FileNotFoundException: class path resource [xxx/xxx/] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:xxx.jar!/BOOT-INF/classes!/xxx/xxx这边使用resource.getDescription()进行获取文件路径,然后进行格式化处理。
FreeMarkerUtil工具类
- import org.apache.commons.lang.StringUtils;
- import org.springframework.core.io.Resource;
- import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
- import org.springframework.core.io.support.ResourcePatternResolver;
- import org.springframework.util.ClassUtils;
-
- import java.io.File;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
-
- /**
- * 复制resource文件、文件夹
- */
- public class FreeMarkerUtil {
-
- /**
- * 复制path目录下所有文件,覆盖(jar)
- *
- * @param path 文件目录 不能以/开头
- * @param newPath 新文件目录
- */
- public static void copyFolderFromJarCover(String path, String newPath) throws IOException {
- if (!new File(newPath).exists()) {
- new File(newPath).mkdir();
- }
- if (path.contains("\\")) {
- path = path.replace("\\", "/");
- }
- if (path.startsWith("/")) {
- //以/开头,去掉/
- path = path.substring(1);
- }
- if (path.endsWith("/")) {
- //以/结尾,去掉/
- path = path.substring(0, path.length() - 1);
- }
-
- ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
- //获取所有匹配的文件(包含根目录文件、子目录、子目录下的文件)
- Resource[] resources = resolver.getResources("classpath:" + path + "/**/");
- //打印有多少文件
- for (Resource resource : resources) {
- //文件名
- String filename = resource.getFilename();
-
- //以jar包运行时,不能使用resource.getFile()获取文件路径、判断是否为文件等,会报错:
- //java.io.FileNotFoundException: class path resource [xxx/xxx/] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:xxx.jar!/BOOT-INF/classes!/xxx/xxx
-
- //文件路径
- //file [/xxx/xxx]
- String description = resource.getDescription();
- description = description.replace("\\", "/");
- //保留 /xxx/xxx
- description = description.replaceAll("(.*\\[)|(]$)", "").trim();
-
- //以“文件目录”进行分割,获取文件相对路径
- String[] descriptions = description.split(path + "/");
- if (descriptions.length > 1) {
- //获取文件相对路径,/xxx/xxx
- String relativePath = descriptions[1];
-
- //新文件路径
- String newFilePath = newPath + "/" + relativePath;
- if (FreeMarkerUtil.isDirectory(filename)) {
- //文件夹
- if (!new File(newFilePath).exists()) {
- new File(newFilePath).mkdir();
- }
-
- } else {
-
- //文件
- InputStream stream = resource.getInputStream();
- write2File(stream, newFilePath);
- }
- }
- }
- }
-
- /**
- * 复制path目录下所有文件,不覆盖(jar)
- *
- * @param path 文件目录 不能以/开头
- * @param newPath 新文件目录
- */
- public static void copyFolderFromJar(String path, String newPath) throws IOException {
- if (!new File(newPath).exists()) {
- new File(newPath).mkdir();
- }
- if (path.contains("\\")) {
- path = path.replace("\\", "/");
- }
- if (path.startsWith("/")) {
- //以/开头,去掉/
- path = path.substring(1);
- }
- if (path.endsWith("/")) {
- //以/结尾,去掉/
- path = path.substring(0, path.length() - 1);
- }
-
- ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
- //获取所有匹配的文件(包含根目录文件、子目录、子目录下的文件)
- Resource[] resources = resolver.getResources("classpath:" + path + "/**/");
- //打印有多少文件
- for (Resource resource : resources) {
- //文件名
- String filename = resource.getFilename();
-
- //以jar包运行时,不能使用resource.getFile()获取文件路径、判断是否为文件等,会报错:
- //java.io.FileNotFoundException: class path resource [xxx/xxx/] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:xxx.jar!/BOOT-INF/classes!/xxx/xxx
-
- //文件路径
- //file [/xxx/xxx]
- String description = resource.getDescription();
- description = description.replace("\\", "/");
- //保留 /xxx/xxx
- description = description.replaceAll("(.*\\[)|(]$)", "").trim();
-
- //以“文件目录”进行分割,获取文件相对路径
- String[] descriptions = description.split(path + "/");
- if (descriptions.length > 1) {
- //获取文件相对路径,/xxx/xxx
- String relativePath = descriptions[1];
-
- //新文件路径
- String newFilePath = newPath + "/" + relativePath;
- if (FreeMarkerUtil.isDirectory(filename)) {
- //文件夹
- if (!new File(newFilePath).exists()) {
- new File(newFilePath).mkdir();
- }
-
- } else {
-
- //文件
- File f = new File(newFilePath);
- if (!f.exists()) {
- InputStream stream = resource.getInputStream();
- write2File(stream, newFilePath);
- }
- }
- }
- }
- }
-
- /**
- * 复制文件(jar)
- *
- * @param path 源文件路径
- * @param newPath 新文件路径
- */
- public static void copyFileFromJar(String path, String newPath) throws IOException {
- //不读文件路径,直接读取文件流
- InputStream inputStream = ClassUtils
- .getDefaultClassLoader()
- .getResourceAsStream(path);
- write2File(inputStream, newPath);
- }
-
- /**
- * 输入流写入文件
- *
- * @param is 输入流
- * @param filePath 文件保存目录路径
- * @throws IOException IOException
- */
- public static void write2File(InputStream is, String filePath) throws IOException {
- File destFile = new File(filePath);
- if (!destFile.getParentFile().exists()) {
- destFile.getParentFile().mkdirs();
- }
-
- if (!destFile.exists()) {
- destFile.createNewFile();
- }
-
- OutputStream os = new FileOutputStream(destFile);
- int len = 8192;
- byte[] buffer = new byte[len];
- while ((len = is.read(buffer, 0, len)) != -1) {
- os.write(buffer, 0, len);
- }
- os.close();
- is.close();
- }
-
- /**
- * 判断是否为目录、文件夹
- * @param filename 文件名
- * @return boolean
- */
- public static boolean isDirectory(String filename) {
- if (StringUtils.isBlank(filename)) {
- return false;
- }
-
- //有后缀,是文件
- boolean contains = filename.contains(".");
- if (contains) {
- return false;
- }
-
- //是文件夹
- return true;
- }
-
- /**
- * 判断是否为目录、文件夹
- * @param path 文件路径
- * @return boolean
- */
- public static boolean isDirectoryFromPath(String path) {
- if (StringUtils.isBlank(path)) {
- return false;
- }
-
- String newPath = path.replace("\\", "/");
- if (newPath.contains("/")) {
- newPath = newPath.substring(newPath.lastIndexOf("/"));
- }
-
- //有后缀,是文件;
- boolean contains = newPath.contains(".");
- if (contains) {
- return false;
- }
-
- //是文件夹
- return true;
- }
-
- public static void main(String[] args) throws IOException {
- //文件夹复制
- String path = "templates";
- String newPath = "D:/tmp";
- FreeMarkerUtil.copyFolderFromJarCover(path, newPath);
-
- //文件复制
- String filePath = "application.properties";
- String newFilePath = "D:/tmp/application.properties";
- FreeMarkerUtil.copyFileFromJar(filePath, newFilePath);
- }
-
- }
文件复制
同样道理,以jar包运行也会报错。
解决方案:
- //文件复制
- String filePath = "application.properties";
- String newFilePath = "D:/tmp/application.properties";
- FreeMarkerUtil.copyFileFromJar(filePath, newFilePath);
-
- /**
- * 复制文件(jar)
- *
- * @param path 源文件路径
- * @param newPath 新文件路径
- */
- public static void copyFileFromJar(String path, String newPath) throws IOException {
- //不读文件路径,直接读取文件流
- InputStream inputStream = ClassUtils
- .getDefaultClassLoader()
- .getResourceAsStream(path);
- write2File(inputStream, newPath);
- }