java文件上传下载文件名包含中文或特殊字符

IE浏览器文件上传获取文件名包含盘符信息

问题描述

在IE浏览器中上传文件,通过MultipartFile的getOriginalFilename实际上与Chrome浏览器的返回结果不同
在Chrome浏览器下,此方法是直接返回“XXX.jpg”结果的。
而在IE浏览器环境下,此方法是返回带盘符信息的“C:/XXX.jpg”

测试代码:

@PostMapping("/upload")
@ApiOperation(value="文件上传", notes="文件上传",produces = "application/json")
public Response<String> updateFile(@NotNull(message = "参数不能为空") @RequestParam(value = "file",required = false) MultipartFile file,
									@NotNull(message = "类型不能为空") @RequestParam(value = "type",required = false)  Integer type) {
	String fileName = file.getOriginalFilename();
	
	return ResponseFactory.success(fileName);
}

以上方法获取文件名,会因为浏览器的不同而返回不同的结果,chrome浏览器直接返回文件名称,IE浏览器返回文件包含盘符在内的全路径。

解决方法

方式一

如果您的应用程序在 Linux 上运行并且您从 Windows 上传文件,那么可能包含“\”这种分隔符,此处将所有的“\”转换成“/”,我们只用关心一种分隔符即可

//获取文件名称(可能包含路径)
String fileName = file.getOriginalFilename();
//获取最后"/"的索引
int startIndex = fileName.replaceAll("\\\\", "/").lastIndexOf("/");
//截取文件名,根据业务,文件后缀也可去掉,此处去除后缀
fileName = fileName.substring(startIndex + 1).substring(0,fileName.indexOf("."));

方式二

使用 apache 公共 IO。它处理 Unix 或 Windows 格式的文件。

org.apache.commons.io.FilenameUtils.getName(multipartFile.getOriginalFilename());

方式三

在获取文件名后,判断是否在IE环境下运行的此方法,并做相应的字符串截取的处理,即可返回正确的结果。

// 获取文件名
String fileName = file.getOriginalFilename();
//判断是否为IE浏览器的文件名,IE浏览器下文件名会带有盘符信息
// Check for Unix-style path
int unixSep = fileName.lastIndexOf('/');
// Check for Windows-style path
int winSep = fileName.lastIndexOf('\\');
// Cut off at latest possible point
int pos = (winSep > unixSep ? winSep : unixSep);
if (pos != -1)  {
    // Any sort of path separator found...
    fileName = fileName.substring(pos + 1);
}

java文件下载文件名包含中文或特殊字符时乱码

解决方法如下,将中文与特殊字符进行编码,URLEncoder.encode() 方法会把空格转换成 + 号,但这样浏览器会认为文件名中就是含有一个 + 号。所以需要再用 replace(“+”, “%20”) 把 + 号转换成 %20

    @GetMapping("/download")
	@ApiOperation(value="文件下载", notes="文件下载",produces = "application/json")
	public void download(@NotNull(message = "参数不能为空") String fileName,
						 @NotNull(message = "参数不能为空") Integer type,
						 HttpServletRequest request, HttpServletResponse response)
			throws IOException {
		log.info("start download  filename:"+fileName);

		//校验并获取文件
		File file = fileService.getFileByNameAndType(fileName, type);
		String fileName = java.net.URLEncoder.encode(filename,"UTF-8").replace("+", "%20");
		try(FileInputStream fis = new FileInputStream(file)) {
			response.setContentType("multipart/form-data");
			response.addHeader("Content-Disposition", "attachment;fileName=" + fileName);
			ServletOutputStream os = response.getOutputStream();
			FileCopyUtils.copy(fis, os);
		}catch (Exception e) {
			log.error("download fail filename:"+fileName,e);
		}
		log.info("download done filename:"+fileName);
	}

在IE, Chorme, FireFox浏览器中测试对aa中国-【】+?。1 .txt文件进行下载,输入http://localhost:9090/file/download?fileName=aa中国-【】+?。1 .txt进行下载后,不同浏览器有不同的问题。如ie直接报400,因为请求参数中包含特殊字符导致路径找不到;firefox文件名中的+也被转义成空格了。

后来通过将请求参数进行编码后再次发送,IE, Chorme, FireFox浏览器都成功下载了文件,至此文件下载乱码问题全部解决了。

http://localhost:9090/file/download?fileName=aa%E4%B8%AD%E5%9B%BD-%E3%80%90%E3%80%91%2B%EF%BC%9F%E3%80%821+.txt

含有特殊字符导致操作系统无法创建文件

不同的操作系统中,创建文件或文件夹的命名是有限制的,包含了特殊字符不能创建文件或文件夹,这也是可能导致下载失败的一种情况。

以下整理不同操作系统文件或文件夹命名的规则与限制

Window系统

windows中,文件名(包括扩展名)可高达 255 个字符。文件名可以包含除 ? / \ < > * | :
之外的大多数字符;保留文件名的大小写;文件名不区分大小写(由 POSIX 应用程序使用时除外)。
windows系统下文件名长度为:255个英文字符(DOS下8.3格式),包括文件名和扩展名在内,
或者是255/2=127个中文字符+1个英文字符。

具体如下:

  • 允许文件或者文件夹名称不得超过255个字符。
  • 文件名除了开头之外任何地方都可以使用空格。
  • 文件名中不能有下列符号:“?”、“、”、“/”、“╲”、“*”、“<”、“>”、“|”。
  • Windows文件名不区分大小写,但在显示时可以保留大小写格式。
  • 文件名中可以包含多个间隔符,如“文件.image.jpg”。

Mac系统:

文件名中不能含有 ” : “字符。另外,文件名不能以 ‘.’ 字符开头,大小写敏感。

Linux系统:

允许使用除了 ‘/’ 以外 所有的特殊字符,但是不建议用户这么做。最好文件名中不要包含 : ? @ # $&()|; ‘’“”<>等字符,另外 空格符,制表符和退格符也不建议使用。

避免使用 + - 和. 作为文件名的第一个字符(Linux下以.开头的文件是隐藏文件) 。 大小写敏感。

解决方法如下,可以将所有系统不可使用的特殊字符删除掉:

   /**
     * window操作系统文件名不能含有 ? “ ”/ \ < > * | :
     * mac操作系统文件名不能以.开头
     * linux和Mac基本一直,
     * 
     * @param fileName
     * @return
     */
    public String checkFileName(String fileName) {
        Pattern pattern = Pattern.compile("[\\s\\\\/:\\*\\?\\\"<>\\|.]");
        Matcher matcher = pattern.matcher(fileName);
        fileName = matcher.replaceAll(""); // 将匹配到的非法字符以空替换
        return fileName;
    }
  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值