java文件上传下载文件名包含中文或特殊字符
IE浏览器文件上传获取文件名包含盘符信息
问题描述
解决方法
方式一
方式二
方式三
java文件下载文件名包含中文或特殊字符时乱码
含有特殊字符导致操作系统无法创建文件
Window系统
Mac系统:
Linux系统:
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;
}