本次的项目环境为 Running with Spring Boot v1.5.10.RELEASE, Spring v4.3.14.RELEASE, 服务器环境为CentOS7.0.

transferTo

我们在上传文件的时候会用到transferTo 这个方法,

transferTo 是 package org.springframework.web.multipart;
帮我们已经封装好,所以我们上传文件的时候是很方便的,只需要一行代码。

Spring 大哥真的是强大。

今天我们上传的时候老是报错,错误提示

java.io.IOException: java.io.FileNotFoundException: /opt/xxxxxxx/xxx.png (Is a directory)


蹩脚的英文好好的翻译一下,xxx.png 是一个目录。

对的,看到这里大家大概就明吧了。

  String path = FILE_PATH + PATH_NAME + File.separator + dirName;
        String fileName = file.getOriginalFilename();
        ======>注意这里等下要讲的
        File targetFile = new File(path , fileName);
        if (!targetFile.exists()) {
            targetFile.mkdirs();
        }
        boolean upState = false;
        try {
            file.transferTo(targetFile);
            upState = true;
        } catch (IOException e) {
            log.error("file transferTo e", e);
            e.printStackTrace();
        }

分析下

其实这个这里上传文件只是一个方法,用到了 Spring自己封装的MultipartFile类,上传只是用到了transferTo,参数是文件的路径。

好了,来一步步调试看源码。

  • 第一步看transferTo中的源码
public void transferTo(File dest) throws IOException, IllegalStateException {
             ======>注意这里调用的是part 类中的write 方法,参数是File的路径
            this.part.write(dest.getPath());
            if (dest.isAbsolute() && !dest.exists()) {
                FileCopyUtils.copy(this.part.getInputStream(), new FileOutputStream(dest));
            }
        }
  • 第二步看 ApplicationPart 中的write方法
public void write(String fileName) throws IOException {
        File file = new File(fileName);
        if (!file.isAbsolute()) {
            file = new File(this.location, fileName);
        }

        try {
            this.fileItem.write(file);
        } catch (Exception var4) {
            throw new IOException(var4);
        }
    }

大家注意看第二步中的 if (!file.isAbsolute()),是的问题就在这里。

这时候如果!file.isAbsolute()成立,也就是我们没有使用绝对路径,那么file = new File(location,fileName);

这个时候会创建一个新的路径,看下面的代码

 public File(File parent, String child) {
        if (child == null) {
            throw new NullPointerException();
        }
        if (parent != null) {
            if (parent.path.equals("")) {
                this.path = fs.resolve(fs.getDefaultParent(),
                                       fs.normalize(child));
            } else {
                this.path = fs.resolve(parent.path,
                                       fs.normalize(child));
            }
        } else {
            this.path = fs.normalize(child);
        }
        this.prefixLength = fs.prefixLength(this.path);
    }

看到这里应该了解了/opt/xxxxxxx/xxx.png ,这个图片被当成文件夹了,在这里创建了一个文件夹,而不是图片。

解决方法

  • 代码注入,修改源码中的location
    @Bean
    MultipartConfigElement multipartConfigElement() {
        MultipartConfigFactory factory = new MultipartConfigFactory();
        factory.setLocation(你的上传路径path);
        return factory.createMultipartConfig();
    }
  • 文件上传时候创建文件
    String path = FILE_PATH + PATH_NAME + File.separator + dirName;
        String fileName = file.getOriginalFilename();
         ======> 注意要先创建图片的目录mkdirs
        File sourceFile = new File(path);
        if (!sourceFile.exists()) {
            sourceFile.mkdirs();
        }

        File targetFile = new File(path + File.separator + fileName);

        boolean upState = false;
        try {
            file.transferTo(targetFile);
            upState = true;
        } catch (IOException e) {
            log.error("file transferTo e", e);
            e.printStackTrace();
        }

结论

这里其实就是 new File(path + File.separator + fileName)的问题,因为Spring的源码中不会根据你给的路径自动创建图片的上一层路径。

写这个就是要说明,遇到问题的时候要多读源码,一步步的调试。

当你一步步接近真相的时候,你会感觉到很有成就感,就像爬过一座山头一样。

多读源码 ,不要只是拷贝,很多场景拷贝的时候细节问题不一样的。

文件上传transferTo一行代码的bug的更多相关文章

  1. BootStrap fileinput.js文件上传组件实例代码

    1.首先我们下载好fileinput插件引入插件 ? 1 2 3 <span style="font-size:14px;"><link type="t ...

  2. java常见3种文件上传速度对比和文件上传方法详细代码

    在java里面文件上传的方式很多,最简单的依然是FileInputStream.FileOutputStream了,在这里我列举3种常见的文件上传方法代码,并比较他们的上传速度(由于代码是在本地测试, ...

  3. JAVA中使用FTPClient实现文件上传下载实例代码

    一.上传文件 原理就不介绍了,大家直接看代码吧 ? 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 ...

  4. ASP.NET - 多文件上传,纯代码,不使用插件

    解决方案: 前段代码: <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Mu ...

  5. 95)PHP,文件上传知识和代码

    首先是知识总结: 上传: 从浏览器端传输的到服务器端. 请求时: 数据从浏览器端传输到服务器端. 可见: 上传,发生在浏览器向服务器发出请求过程中. 文件,对于浏览器来讲,就是表单中的一个特殊类型的数 ...

  6. 全网最简单的大文件上传与下载代码实现(React+Go)

    前言 前段时间我需要实现大文件上传的需求,在网上查找了很多资料,并且也发现已经有很多优秀的博客讲了大文件上传下载这个功能. 我的项目是个比较简单的项目,并没有采用特别复杂的实现方式,所以我这篇文章的目 ...

  7. HDwiki文件上传导致远程代码执行漏洞

    漏洞版本: HDwiki(2011) 漏洞描述: 互动维客开源系统(HDwiki)作为中国第一家拥有自主知识产权的中文维基(Wiki)系统,由互动在线(北京)科技有限公司于2006 年11月28日正式 ...

  8. SFTP 文件上传下载引用代码

    http://sha1064616837.iteye.com/blog/2036996 http://www.cnblogs.com/itmanxgl/p/fe5d33512609fe540eb08a ...

  9. ajaxfileupload多文件上传 - 修复只支持单个文件上传的bug

    搜索: jquery ajaxFileUpload AjaxFileUpload同时上传多个文件 原生的AjaxFileUpload插件是不支持多文件上传的,通过修改AjaxFileUpload少量代 ...

随机推荐

  1. C语言学习笔记之字符串拼接的2种方法——strcat、sprintf

    本文为原创文章,转载请标明出处 1. 使用strcat进行字符串拼接 #include <stdio.h> #include <stdlib.h> #include <s ...

  2. 三分钟学会使用Derby数据库

    Derby数据库是一个纯用Java实现的内存数据库,属于Apache的一个开源项目.由于是用Java实现的,所以可以在任何平台上运行:另外一个特点是体积小,免安装,java1.6开始集成了derby数 ...

  3. 向MyEclipse的项目中导入js文件时,出现小红叉

    这个问题困扰我很久.刚开始时,也没有解决,因此也在网上寻找解决方法,还是没能解决.最近做项目时再一次出现了这样的问题,于是决定还是再找找办法.在此,分享一下自己的解决方法,给正处于痛苦中的童鞋们带来解 ...

  4. zookeeper ACL(access control lists)权限控制

    基本作用:        针对节点可以设置 相关读写等权限,目的为了保障数据安全性        权限permissions可以制定不同的权限范围以及角色 一:ACL构成         zk的acl ...

  5. Jekyll的_config文件配置报错

    8 April 2019 by IchiehPan Jekyll 搭建博客时, 修改完_config.yml文件后就收到了github的build error邮件. 大致内容如下: did not f ...

  6. 【内推】平安产险大数据测试开发工程师,15-30k!

    平安产险技术岗内部推荐-大数据测试开发工程师等-欢迎中年人和2020应届生 上班地点:深圳福田平安金融中心 另有大量 上海 北京 成都 广州 岗位 交流qq群 828186629 微信pythonte ...

  7. 苹果iPhone9、小米7…当曝光成为一门生意就没那么好玩了

    大众最乐此不疲的,当然就是以熊熊燃烧的八卦之心,去挖掘各种或为隐私,或为未知的那些事儿.为此,狗仔队.曝光人士等就受到了追捧.当然,也有对他们的各种嘲讽--而在智能手机行业,各种曝光更是乐此不疲的上演 ...

  8. redis集群配置及python操作

    之前我们分析过喜马拉雅的爬取信息,使用分布式爬取,而且需要修改scrapy-redis的过滤算法为布隆过滤来减少redis内存占用,最后考虑这样还是不一定够,那么redis集群就是更好的一种选择方式了 ...

  9. python爬虫-scrapy日志

    1.scrapy日志介绍 Scrapy的日志系统是实现了对python内置的日志的封装 scrapy也使用python日志级别分类 logging.CRITICAL logging.ERROE log ...

  10. [ASP.NET Core 3框架揭秘] 服务承载系统[1]: 承载长时间运行的服务[上篇]

    借助.NET Core提供的承载(Hosting)系统,我们可以将任意一个或者多个长时间运行(Long-Running)的服务寄宿或者承载于托管进程中.ASP.NET Core应用仅仅是该承载系统的一 ...