java jar 以两种不同的字符编码写入
java jar writes in two different character-encoding
所以当从 Eclipse 运行 时我的代码工作正常,但是执行项目的可运行 jar 却不行。
这是我的代码:
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class cc {
public static HttpURLConnection con;
public static String url = "http://bac.onec.dz/index.php";
public static int begin;
public static int max;
public static boolean paused=false;
public static String path="result.csv";
public static void setData(int b,int m){
begin=b;max=m;
}
public static void main(String[] args) throws Exception {
int i =1;
setData(35043487,2);
while (i<=max && !paused) {
sendPost(begin++);
i++;
}
}
private static void sendPost(int mat) throws Exception {
String urlParameters ;
URL obj = new URL(url);
BufferedReader in;
StringBuffer response;
con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Host", "bac.onec.dz");
con.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0");
con.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
con.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
con.setRequestProperty("Accept-Encoding", "gzip, deflate");
con.setRequestProperty("Referer", "http://bac.onec.dz/");
con.setRequestProperty("Cookie", "bbbbbbbbbbbbbbb=ANNCLHAEAAAAAAAAJHKBHDAAAAAAAAAAEADAOFFHFHFHAAAADAAANKIFFKIFAAAA; TS1ff960=20859ee226968392c837af0430f21cf0087e23d48701410f5785a62879b49ee6533a75145e5dca68b041d236; aaaaaaaaaaaaaaa=GAABBCCHICBGBAAECAAAAAKCHHAAAAAAEACAALAAKGFHAAAADAAAAGAACKIFAAAA");
con.setDoOutput(true);
urlParameters = "matriculebac="+mat+"&dobac=%D8%A7%D8%B3%D8%AA%D8%B8%D9%87%D8%A7%D8%B1+%D8%A7%D9%84%D9%86%D8%AA%D9%8A%D8%AC%D8%A9";
DataOutputStream wr = new DataOutputStream(con.getOutputStream());
wr.writeBytes(urlParameters);
wr.flush();
wr.close();
in = new BufferedReader( new InputStreamReader(con.getInputStream()));
response = new StringBuffer();
Object[] aa = in.lines().toArray();
for (Object object : aa) response.append(object.toString()+"\n");
in.close();
Pattern pattern = Pattern.compile("alert\(.*?\);");
Matcher matcher = pattern.matcher(response.toString());
String[] person = null;
if (matcher.find())
{
String p =matcher.group(0).substring(7, matcher.group(0).length()-3);
person = p.split("\\n");
}
try {
String [] pp=
{
person[0 ],
person[1 ].split(":")[1].substring(1),
person[2 ].split(":")[1].substring(1),
person[10].split(":")[1].substring(1),
person[4 ].split(":")[1].substring(1),
person[5 ].split(":")[1].substring(1),
person[6 ].split(":")[1].substring(1),
person[7 ].split(":")[1].substring(1),
};
CvsWrite(pp);
} catch (Exception e) {
}
}
public static void CvsWrite(String[] args) throws IOException {
List<String> pers = new ArrayList<>();
for (String string : args) pers.add(string);
String clct1 = pers.stream().collect(Collectors.joining(",")) + "\r\n";
File f = new File(path);
if (!f.exists())
try {
f.createNewFile();
List<String> test = new ArrayList<>();
test.add("الملاحظة");
test.add("رقم التسجيل");
test.add("الشعبة");
test.add("المعدل");
test.add("اللقب");
test.add("الاسم");
test.add("مكان الميلاد");
test.add("تاريخ الميلاد");
String clct2 = test.stream().collect(Collectors.joining(","))+ "\r\n\r\n";
Files.write(Paths.get(path),clct2.getBytes(), StandardOpenOption.APPEND);
} catch (IOException e) {}
Files.write(Paths.get(path),clct1.getBytes(), StandardOpenOption.APPEND);
}
}
运行 来自 eclipse,输出文件完美支持 UTF-8 编码。
运行 来自导出的 jar,输出文件的一部分是 ANSI 编码。现在,如果我只写这些词,那不会有问题,但是代码用阿拉伯语写其他内容,输出就像
输出文件是用记事本++打开的
在美国标准
http://i.stack.imgur.com/6RGEj.png
在 UTF-8 中
http://i.stack.imgur.com/Li0qf.png
正如我提到的,当 运行 来自 eclipse
时没有遇到这个问题
嗯,这听起来好像您在 运行 以不同的方式获得不同的默认编码 - 这在某种程度上是可以预料的。
将文本转换为二进制时,只需指定编码即可:
byte[] bytes = col.getBytes(StandardCharsets.UTF_8);
Files.write(Paths.get(path), bytes, StandardOpenOption.Append);
(我建议使用 Files.write
并直接传入文本,但这将使用平台默认换行符,这将是一个单独的问题...)
您在创建 InputStreamReader
时遇到了同样的问题:
in = new BufferedReader( new InputStreamReader(con.getInputStream()));
这是假设数据采用平台默认编码。 永远不要假设。您应该找出数据的 actual 编码是什么,并使用它来读取。然后决定(作为一个单独的问题)你想写什么编码。
使用的是String.getBytes()
,它使用当前机器的默认操作系统编码。那不是便携式的。指定编码。
由于现有的旧内容是 ANSI,因此继续使用 ANSI。
Files.write(Paths.get(path), clct2.getBytes("Windows-1256"), StandardOpenOption.APPEND);
并使用 ANSI 读取文件:
String s = new String(bytes, "Windows-1256");
第一次和第二次写文件操作使用默认的操作系统编码,或者为两者指定相同的编码,遇到同样的问题,即编码冲突。
解决方法是:将第一次写文件的编码指定为UTF-8。
.
.
String clct2 = test.stream().collect(Collectors.joining(","))+ "\r\n\r\n";
Files.write(Paths.get(path),clct2.getBytes("UTF-8"), StandardOpenOption.APPEND);
} catch (IOException e) {}
Files.write(Paths.get(path),clct1.getBytes(), StandardOpenOption.APPEND);
.
.
This is certainly a dumb solution, since the bug is about portability and default OS encoding, but it worked :)
所以当从 Eclipse 运行 时我的代码工作正常,但是执行项目的可运行 jar 却不行。
这是我的代码:
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class cc {
public static HttpURLConnection con;
public static String url = "http://bac.onec.dz/index.php";
public static int begin;
public static int max;
public static boolean paused=false;
public static String path="result.csv";
public static void setData(int b,int m){
begin=b;max=m;
}
public static void main(String[] args) throws Exception {
int i =1;
setData(35043487,2);
while (i<=max && !paused) {
sendPost(begin++);
i++;
}
}
private static void sendPost(int mat) throws Exception {
String urlParameters ;
URL obj = new URL(url);
BufferedReader in;
StringBuffer response;
con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Host", "bac.onec.dz");
con.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0");
con.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
con.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
con.setRequestProperty("Accept-Encoding", "gzip, deflate");
con.setRequestProperty("Referer", "http://bac.onec.dz/");
con.setRequestProperty("Cookie", "bbbbbbbbbbbbbbb=ANNCLHAEAAAAAAAAJHKBHDAAAAAAAAAAEADAOFFHFHFHAAAADAAANKIFFKIFAAAA; TS1ff960=20859ee226968392c837af0430f21cf0087e23d48701410f5785a62879b49ee6533a75145e5dca68b041d236; aaaaaaaaaaaaaaa=GAABBCCHICBGBAAECAAAAAKCHHAAAAAAEACAALAAKGFHAAAADAAAAGAACKIFAAAA");
con.setDoOutput(true);
urlParameters = "matriculebac="+mat+"&dobac=%D8%A7%D8%B3%D8%AA%D8%B8%D9%87%D8%A7%D8%B1+%D8%A7%D9%84%D9%86%D8%AA%D9%8A%D8%AC%D8%A9";
DataOutputStream wr = new DataOutputStream(con.getOutputStream());
wr.writeBytes(urlParameters);
wr.flush();
wr.close();
in = new BufferedReader( new InputStreamReader(con.getInputStream()));
response = new StringBuffer();
Object[] aa = in.lines().toArray();
for (Object object : aa) response.append(object.toString()+"\n");
in.close();
Pattern pattern = Pattern.compile("alert\(.*?\);");
Matcher matcher = pattern.matcher(response.toString());
String[] person = null;
if (matcher.find())
{
String p =matcher.group(0).substring(7, matcher.group(0).length()-3);
person = p.split("\\n");
}
try {
String [] pp=
{
person[0 ],
person[1 ].split(":")[1].substring(1),
person[2 ].split(":")[1].substring(1),
person[10].split(":")[1].substring(1),
person[4 ].split(":")[1].substring(1),
person[5 ].split(":")[1].substring(1),
person[6 ].split(":")[1].substring(1),
person[7 ].split(":")[1].substring(1),
};
CvsWrite(pp);
} catch (Exception e) {
}
}
public static void CvsWrite(String[] args) throws IOException {
List<String> pers = new ArrayList<>();
for (String string : args) pers.add(string);
String clct1 = pers.stream().collect(Collectors.joining(",")) + "\r\n";
File f = new File(path);
if (!f.exists())
try {
f.createNewFile();
List<String> test = new ArrayList<>();
test.add("الملاحظة");
test.add("رقم التسجيل");
test.add("الشعبة");
test.add("المعدل");
test.add("اللقب");
test.add("الاسم");
test.add("مكان الميلاد");
test.add("تاريخ الميلاد");
String clct2 = test.stream().collect(Collectors.joining(","))+ "\r\n\r\n";
Files.write(Paths.get(path),clct2.getBytes(), StandardOpenOption.APPEND);
} catch (IOException e) {}
Files.write(Paths.get(path),clct1.getBytes(), StandardOpenOption.APPEND);
}
}
运行 来自 eclipse,输出文件完美支持 UTF-8 编码。
运行 来自导出的 jar,输出文件的一部分是 ANSI 编码。现在,如果我只写这些词,那不会有问题,但是代码用阿拉伯语写其他内容,输出就像
输出文件是用记事本++打开的 在美国标准 http://i.stack.imgur.com/6RGEj.png 在 UTF-8 中 http://i.stack.imgur.com/Li0qf.png
正如我提到的,当 运行 来自 eclipse
时没有遇到这个问题嗯,这听起来好像您在 运行 以不同的方式获得不同的默认编码 - 这在某种程度上是可以预料的。
将文本转换为二进制时,只需指定编码即可:
byte[] bytes = col.getBytes(StandardCharsets.UTF_8);
Files.write(Paths.get(path), bytes, StandardOpenOption.Append);
(我建议使用 Files.write
并直接传入文本,但这将使用平台默认换行符,这将是一个单独的问题...)
您在创建 InputStreamReader
时遇到了同样的问题:
in = new BufferedReader( new InputStreamReader(con.getInputStream()));
这是假设数据采用平台默认编码。 永远不要假设。您应该找出数据的 actual 编码是什么,并使用它来读取。然后决定(作为一个单独的问题)你想写什么编码。
使用的是String.getBytes()
,它使用当前机器的默认操作系统编码。那不是便携式的。指定编码。
由于现有的旧内容是 ANSI,因此继续使用 ANSI。
Files.write(Paths.get(path), clct2.getBytes("Windows-1256"), StandardOpenOption.APPEND);
并使用 ANSI 读取文件:
String s = new String(bytes, "Windows-1256");
第一次和第二次写文件操作使用默认的操作系统编码,或者为两者指定相同的编码,遇到同样的问题,即编码冲突。 解决方法是:将第一次写文件的编码指定为UTF-8。
.
.
String clct2 = test.stream().collect(Collectors.joining(","))+ "\r\n\r\n";
Files.write(Paths.get(path),clct2.getBytes("UTF-8"), StandardOpenOption.APPEND);
} catch (IOException e) {}
Files.write(Paths.get(path),clct1.getBytes(), StandardOpenOption.APPEND);
.
.
This is certainly a dumb solution, since the bug is about portability and default OS encoding, but it worked :)