Java 用于 Web - Multipart/form-data 文件编码错误
Java for Web - Multipart/form-data file with wrong encoding
我正在使用 Java 和 Tomcat 开发 Web 应用程序 8. 此应用程序有一个页面,用于上传文件,其内容将显示在不同的页面中。简单明了。
但是,这些文件可能包含不太常见的字符作为其文本的一部分。例如,现在,我正在处理一个包含越南文本的文件。
该文件以 UTF-8 编码,可以在任何文本编辑器中打开。但是,尽管进行了很多搜索并尝试了许多不同的方法,但我找不到任何方法来上传它并使内容保持正确的编码。
我上传文件的页面包含以下形式:
<form method="POST" action="upload" enctype="multipart/form-data" accept-charset="UTF-8" >
File: <input type="file" name="file" id="file" multiple/><br/>
Param1: <input type="text" name="param1"/> <br/>
Param2: <input type="text" name="param2"/> <br/>
<input type="submit" value="Upload" name="upload" id="upload" />
</form>
还包含:
<%@page contentType="text/html" pageEncoding="UTF-8"%>
...
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
我的 servlet 如下所示:
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
response.setContentType("text/html;charset=UTF-8");
request.setCharacterEncoding("UTF-8");
String param1 = request.getParameter("param1");
String param2 = request.getParameter("param2");
Collection<Part> parts = request.getParts();
Iterator<Part> iterator = parts.iterator();
while (iterator.hasNext()) {
Part filePart = iterator.next();
InputStream filecontent = null;
filecontent = filePart.getInputStream();
String content = convertStreamToString(filecontent, "UTF-8");
//Save the content and the parameters in the database
if (filecontent != null) {
filecontent.close();
}
}
} catch (ParseException ex) {
}
}
static String convertStreamToString(java.io.InputStream is, String encoding) {
java.util.Scanner s = new java.util.Scanner(is, encoding).useDelimiter("\A");
return s.hasNext() ? s.next() : "";
}
尽管我付出了所有努力,但我始终无法获得保留了正确字符的 "content" 字符串。我要么得到类似 "K?n" 或 "Kạn" 的东西(这似乎是它的 ISO-8859-1 解释),但正确的应该是 "Kạn".
为了增加问题,如果我在其他表单参数(param1 或 param2)中写入越南字符,这也需要是可能的,我只能在设置表单的 accept-charset 和servlet 扫描器编码为 ISO-8859-1,我绝对不明白。在那种情况下,如果我打印接收到的参数,我会得到类似 "K & # 7 8 4 1 ; n"(没有空格)的东西,其中包含正确字符的表示。因此,只要表单本身使用该字符集,似乎就可以使用 ISO-8859-1 从表单中读取越南字符。但是,它永远不会处理上传文件的内容。我什至尝试在 ISO-8859-1 中对文件进行编码,以对所有内容使用字符集,但它根本不起作用。
我相信这种情况并不少见,所以我想请以前可能遇到过这种情况的人提供一些帮助。我可能遗漏了一些东西,因此我们将不胜感激。
提前谢谢你。
编辑 1: 虽然这个问题还没有收到回复,但我会继续发布我的发现,以防有人感兴趣或关注它。
在尝试了许多不同的事情之后,我似乎已经缩小了问题的原因。我创建了一个 class ,它从磁盘中的特定文件夹读取文件并打印其内容。代码如下:
public static void openFile() {
System.out.println(String.format("file.encoding: %s", System.getProperty("file.encoding")));
System.out.println(String.format("defaultCharset: %s", Charset.defaultCharset().name()));
File file = new File(myFilePath);
byte[] buffer = new byte[(int) file.length()];
BufferedInputStream f = null;
String content = null;
try {
f = new BufferedInputStream(new FileInputStream(file));
} catch (FileNotFoundException ex) {
}
try {
f.read(buffer);
content = new String(buffer, "UTF-8");
System.out.println("UTF-8 File: " + content);
f.close();
} catch (IOException ex) {
}
}
然后我给这个 class 添加了一个 main 函数,让它可以执行。当我 运行 它独立时,我得到以下输出:
file.encoding: UTF-8
defaultCharset: UTF-8
UTF-8 File: {"...Kạn..."}
但是,如果 运行 项目作为一个 webapp,正如它应该的那样,并从那个 class 调用相同的函数,我得到:
file.encoding: Cp1252
defaultCharset: windows-1252
UTF-8 File: {"...K?n..."}
当然,这清楚地表明webapp读取文件使用的默认编码不是UTF-8。因此,我对该主题进行了一些研究,并找到了为 Tomcat 创建 setenv.bat 并让它执行的 class 合理答案:
set "JAVA_OPTS=%JAVA_OPTS% -Dfile.encoding=UTF-8"
结果还是不对:
file.encoding: UTF-8
defaultCharset: UTF-8
UTF-8 File {"...Kạn..."}
我现在可以看到默认编码变成了UTF-8。然而,从文件中读取的内容仍然是错误的。如果我在 Microsoft Word 中打开文件,但选择使用 ISO-Latin-1 而不是 UTF-8 来读取它,上面显示的内容是相同的。出于某种奇怪的原因,读取文件仍在某处使用 ISO-Latin-1,尽管一切都指出使用 UTF-8。
同样,如果有人对此有任何建议或指导,我们将不胜感激。
我似乎无法结束这个问题,所以让我贡献我找到的答案。
问题是调查此类问题非常棘手,因为代码中有很多点可能会更改编码(页面,表单编码,请求编码,文件读取,文件写入,控制台输出、数据库写入、数据库读取...)。
就我而言,在完成我在问题中发布的所有内容之后,我浪费了很多时间来尝试解决不再存在的问题,只是因为 IDE 中的控制台输出(NetBeans,对于那个项目)没有使用所需的字符编码。所以我在某个点上做的每件事都是正确的,但是当我试图打印任何东西时,我都会出错。在我开始将日志写入文件而不是控制台,从而控制写入编码后,我开始清楚地了解这个问题。
在我的问题中(编辑之前)已经描述了所有内容之后,我的解决方案中缺少的是配置数据库连接的编码。令我惊讶的是,即使我的数据库和所有表都使用 UTF-8,应用程序和 MySQL 之间的通信仍然是 ISO-Latin。最后缺少的是将 "useUnicode=true&characterEncoding=utf-8" 添加到连接中,就像这样:
con = DriverManager.getConnection("jdbc:mysql:///dbname?useUnicode=true&characterEncoding=utf-8", "user", "pass");
感谢这个回答,还有很多其他的:
我正在使用 Java 和 Tomcat 开发 Web 应用程序 8. 此应用程序有一个页面,用于上传文件,其内容将显示在不同的页面中。简单明了。
但是,这些文件可能包含不太常见的字符作为其文本的一部分。例如,现在,我正在处理一个包含越南文本的文件。
该文件以 UTF-8 编码,可以在任何文本编辑器中打开。但是,尽管进行了很多搜索并尝试了许多不同的方法,但我找不到任何方法来上传它并使内容保持正确的编码。
我上传文件的页面包含以下形式:
<form method="POST" action="upload" enctype="multipart/form-data" accept-charset="UTF-8" >
File: <input type="file" name="file" id="file" multiple/><br/>
Param1: <input type="text" name="param1"/> <br/>
Param2: <input type="text" name="param2"/> <br/>
<input type="submit" value="Upload" name="upload" id="upload" />
</form>
还包含:
<%@page contentType="text/html" pageEncoding="UTF-8"%>
...
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
我的 servlet 如下所示:
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
response.setContentType("text/html;charset=UTF-8");
request.setCharacterEncoding("UTF-8");
String param1 = request.getParameter("param1");
String param2 = request.getParameter("param2");
Collection<Part> parts = request.getParts();
Iterator<Part> iterator = parts.iterator();
while (iterator.hasNext()) {
Part filePart = iterator.next();
InputStream filecontent = null;
filecontent = filePart.getInputStream();
String content = convertStreamToString(filecontent, "UTF-8");
//Save the content and the parameters in the database
if (filecontent != null) {
filecontent.close();
}
}
} catch (ParseException ex) {
}
}
static String convertStreamToString(java.io.InputStream is, String encoding) {
java.util.Scanner s = new java.util.Scanner(is, encoding).useDelimiter("\A");
return s.hasNext() ? s.next() : "";
}
尽管我付出了所有努力,但我始终无法获得保留了正确字符的 "content" 字符串。我要么得到类似 "K?n" 或 "Kạn" 的东西(这似乎是它的 ISO-8859-1 解释),但正确的应该是 "Kạn".
为了增加问题,如果我在其他表单参数(param1 或 param2)中写入越南字符,这也需要是可能的,我只能在设置表单的 accept-charset 和servlet 扫描器编码为 ISO-8859-1,我绝对不明白。在那种情况下,如果我打印接收到的参数,我会得到类似 "K & # 7 8 4 1 ; n"(没有空格)的东西,其中包含正确字符的表示。因此,只要表单本身使用该字符集,似乎就可以使用 ISO-8859-1 从表单中读取越南字符。但是,它永远不会处理上传文件的内容。我什至尝试在 ISO-8859-1 中对文件进行编码,以对所有内容使用字符集,但它根本不起作用。
我相信这种情况并不少见,所以我想请以前可能遇到过这种情况的人提供一些帮助。我可能遗漏了一些东西,因此我们将不胜感激。
提前谢谢你。
编辑 1: 虽然这个问题还没有收到回复,但我会继续发布我的发现,以防有人感兴趣或关注它。
在尝试了许多不同的事情之后,我似乎已经缩小了问题的原因。我创建了一个 class ,它从磁盘中的特定文件夹读取文件并打印其内容。代码如下:
public static void openFile() {
System.out.println(String.format("file.encoding: %s", System.getProperty("file.encoding")));
System.out.println(String.format("defaultCharset: %s", Charset.defaultCharset().name()));
File file = new File(myFilePath);
byte[] buffer = new byte[(int) file.length()];
BufferedInputStream f = null;
String content = null;
try {
f = new BufferedInputStream(new FileInputStream(file));
} catch (FileNotFoundException ex) {
}
try {
f.read(buffer);
content = new String(buffer, "UTF-8");
System.out.println("UTF-8 File: " + content);
f.close();
} catch (IOException ex) {
}
}
然后我给这个 class 添加了一个 main 函数,让它可以执行。当我 运行 它独立时,我得到以下输出:
file.encoding: UTF-8
defaultCharset: UTF-8
UTF-8 File: {"...Kạn..."}
但是,如果 运行 项目作为一个 webapp,正如它应该的那样,并从那个 class 调用相同的函数,我得到:
file.encoding: Cp1252
defaultCharset: windows-1252
UTF-8 File: {"...K?n..."}
当然,这清楚地表明webapp读取文件使用的默认编码不是UTF-8。因此,我对该主题进行了一些研究,并找到了为 Tomcat 创建 setenv.bat 并让它执行的 class 合理答案:
set "JAVA_OPTS=%JAVA_OPTS% -Dfile.encoding=UTF-8"
结果还是不对:
file.encoding: UTF-8
defaultCharset: UTF-8
UTF-8 File {"...Kạn..."}
我现在可以看到默认编码变成了UTF-8。然而,从文件中读取的内容仍然是错误的。如果我在 Microsoft Word 中打开文件,但选择使用 ISO-Latin-1 而不是 UTF-8 来读取它,上面显示的内容是相同的。出于某种奇怪的原因,读取文件仍在某处使用 ISO-Latin-1,尽管一切都指出使用 UTF-8。
同样,如果有人对此有任何建议或指导,我们将不胜感激。
我似乎无法结束这个问题,所以让我贡献我找到的答案。
问题是调查此类问题非常棘手,因为代码中有很多点可能会更改编码(页面,表单编码,请求编码,文件读取,文件写入,控制台输出、数据库写入、数据库读取...)。
就我而言,在完成我在问题中发布的所有内容之后,我浪费了很多时间来尝试解决不再存在的问题,只是因为 IDE 中的控制台输出(NetBeans,对于那个项目)没有使用所需的字符编码。所以我在某个点上做的每件事都是正确的,但是当我试图打印任何东西时,我都会出错。在我开始将日志写入文件而不是控制台,从而控制写入编码后,我开始清楚地了解这个问题。
在我的问题中(编辑之前)已经描述了所有内容之后,我的解决方案中缺少的是配置数据库连接的编码。令我惊讶的是,即使我的数据库和所有表都使用 UTF-8,应用程序和 MySQL 之间的通信仍然是 ISO-Latin。最后缺少的是将 "useUnicode=true&characterEncoding=utf-8" 添加到连接中,就像这样:
con = DriverManager.getConnection("jdbc:mysql:///dbname?useUnicode=true&characterEncoding=utf-8", "user", "pass");
感谢这个回答,还有很多其他的: