【问题标题】:Writing uploaded files with non-ASCII file names to disk from Java servlet从 Java servlet 将具有非 ASCII 文件名的上传文件写入磁盘
【发布时间】:2016-04-17 12:01:15
【问题描述】:

我有一个 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" 生成一个具有该名称的文件。

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

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

【问题讨论】:

  • 为什么要通过File?直接用Path就行了
  • 尝试调试每个版本,看看fileName在所有三种情况下是什么

标签: java servlets file-upload character-encoding


【解决方案1】:

我通过将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 解决了这个问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-03-13
    • 1970-01-01
    • 2012-08-18
    • 2012-11-01
    • 1970-01-01
    • 2015-02-20
    • 2018-10-27
    相关资源
    最近更新 更多