从Java servlet

时间:2016-04-17 12:01:16

标签: java servlets file-upload character-encoding

我有一个servlet,使用Apache Commons fileupload将上传的文件写入磁盘。这一切都很好。

它使用Tomcat在Windows和Linux服务器上运行。在Windows上,它正确处理具有非ASCII文件名的文件,并正确保存文件。

在Linux(CentOS 6)上,包含非ASCII字符时文件名未正确保存。

如果尝试过三种不同版本的文件写入。在Windows中所有工作,在Linux中都没有,但它们会产生不同的结果。

版本1:

String fileName = URLDecoder.decode(encFilename, "UTF-8");
String filePath = uploadFolder + File.separator + fileName;
File uploadedFile = new File(filePath);

item.write(uploadedFile);

版本2:

String fileName = URLDecoder.decode(encFilename, "UTF-8");
String filePath = uploadFolder + File.separator + fileName;
File uploadedFile = new File(filePath);

InputStream input = item.getInputStream();                    
try {
    Files.copy(input, uploadedFile.toPath());
} catch (Exception e) {
    log.error("Error writing file to disk: " + e.getMessage());
} finally {
    input.close();
}

上传名为Это тестовый файл.txt的文件我在Linux上获得以下结果:

版本1 :名为??? ???????? ????.txt

的文件

版本2 Error writing file to disk: Malformed input or input contains unmappable characters: /tmp/Это тестовый файл.txt

在具有Tomcat 7和Java 7的Windows计算机上,文件名正确写为Это тестовый файл.txt

第三个版本使用this post的方法,不使用FileUpload。结果与版本2生成的结果相同。

版本3:

Part filePart = request.getPart("file");
String fileName = "";
for (String cd : filePart.getHeader("content-disposition").split(";")) {
    if (cd.trim().startsWith("filename")) {
        fileName = cd.substring(cd.indexOf('=') + 1).trim().replace("\"", "");
        fileName = fileName.substring(fileName.lastIndexOf('/') + 1).substring(fileName.lastIndexOf('\\') + 1); // MSIE fix.
    }
}

String filePath = uploadFolder + File.separator + fileName;
File uploadedFile = new File(filePath);

InputStream input = filePart.getInputStream();                    
try {
    Files.copy(input, uploadedFile.toPath());
} catch (Exception e) {
    log.error("Error writing file to disk: " + e.getMessage());
} finally {
    input.close();
}

Tomcat正在使用-Dfile.encoding=UTF-8并且locale显示LANG=en_US.UTF-8

touch "Это тестовый файл.txt"生成一个具有该名称的文件。

始终正确写入文件内容。 (当然除了根本没有写文件)。

我错过了什么或做错了什么?

1 个答案:

答案 0 :(得分:0)

我通过将java.io.File的所有使用转换为java.nio.Filesjava.nio.Path来解决了这个问题。所以似乎java.io.File api是错误的。使用它,它可以在Windows和Linux上正常工作。

// The filename is passed as a URLencoded string
String fileName = URLDecoder.decode(request.getParameter("fileName"), "UTF-8");
Path filePath = Paths.get(uploadFolder, fileName);
Part filePart = request.getPart("file");

InputStream input = filePart.getInputStream();                    
try {
    Files.copy(input, filePath);
} catch (Exception e) {
    log.error("Error writing file to disk: " + e.getMessage());
} finally {
    input.close();
}

我在使用上传文件的应用的其他几个部分遇到了同样的问题,并且在所有情况下摆脱java.io.File并使用java.nio代替解决了问题。