`

Java编码及网络传输中的编码问题

    博客分类:
  • Java
阅读更多
近来试着FTP搜索,遇到编码问题,研究了下。
Java内部的String为Unicode编码,每个字符占两个字节。
Java编解码方法如下:

String str = "hi好啊me";
byte[] gbkBytes=str.getBytes("GBK");//将String的Unicode编码转为GBK编码,输出到字节中
String string=new String(gbkBytes,"GBK");//gbkBytes中的字节流以GBK方案解码成Unicode形式的Java字符串


1、表单数据的编码
现在的问题是,在网络中,不知道客户端发过来的字节流的编码方案(发送前浏览器会对数据编码!!!各个浏览器还不一样!!!)
解决方案如下:


当然URLEncoder.encode(str, "utf-8")和URLDecoder.decode(strReceive,"utf-8")方法中的编码方案要一致。

2、网址的编码
但以上方法只适合表单数据的提交;对于URL则不行!!!原因是URLEncoder把'/'也编码了,浏览器发送时报错!!!那么,只要http://IP/子目录把http://IP/这部分原封不动(当然这部分不要有中文),之后的数据以'/'分割后分段编码即可
代码如下:

	/**
	 * 对{@link URLEncoder#encode(String, String)}的封装,但不编码'/'字符,对其他字符分段编码
	 * 
	 * @param str
	 *            要编码的URL
	 * @param encoding
	 *            编码格式
	 * @return 字符串以字符'/'隔开,对每一段单独编码以encoding编码格式编码
	 * @version: 2012_01_10
	 *           <p>
	 *           注意:未考虑':',如直接对http://编解码,会产生错误!!!请在使用前将其分离出来,可以使用
	 *           {@link #encodeURLAfterHost(String, String)}方法解决此问题
	 *           <p>
	 *           注意:对字符/一起编码,导致URL请求异常!!
	 */
	public static String encodeURL(String str, String encoding) {
		final char splitter = '/';
		try {
			StringBuilder sb = new StringBuilder(2 * str.length());
			int start = 0;
			for (int i = 0; i < str.length(); i++) {
				if (str.charAt(i) == splitter) {
					sb.append(URLEncoder.encode(str.substring(start, i),
							encoding));
					sb.append(splitter);
					start = i + 1;
				}
			}
			if (start < str.length())
				sb.append(URLEncoder.encode(str.substring(start), encoding));
			return sb.toString();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 对IP地址后的URL通过'/'分割后进行分段编码.
	 * <p>
	 * 对{@link URLEncoder#encode(String, String)}
	 * 的封装,但不编码'/'字符,也不编码网站部分(如ftp://a.b.c.d/部分,检测方法为对三个'/'字符的检测,且要求前两个连续),
	 * 对其他字符分段编码
	 * 
	 * @param str
	 *            要编码的URL
	 * @param encoding
	 *            编码格式
	 * @return IP地址后字符串以字符'/'隔开,对每一段单独编码以encoding编码格式编码,其他部分不变
	 * @version: 2012_01_10
	 *           <p>
	 *           注意:对字符/一起编码,导致URL请求异常!!
	 */
	public static String encodeURLAfterHost(String str, String encoding) {
		final char splitter = '/';

		int index = str.indexOf(splitter);//第一个'/'的位置
		index++;//移到下一位置!!
		if (index < str.length() && str.charAt(index) == splitter) {//检测第一个'/'之后是否还是'/',如ftp://
			index++;//从下一个开始
			index = str.indexOf(splitter, index);//第三个'/';如ftp://anonymous:tmp@g.cn:219.223.168.20/中的最后一个'/'
			if (index > 0) {
				return str.substring(0, index + 1)
						+ encodeURL(str.substring(index + 1), encoding);//如ftp://anonymous:tmp@g.cn:219.223.168.20/天空
			} else
				return str;//如ftp://anonymous:tmp@g.cn:219.223.168.20
		}

		return encodeURL(str, encoding);

	}

	/**
	 * 对IP地址后的URL通过'/'分割后进行分段编码.
	 * 此方法与{@link #decodeURLAfterHost(String, String)}配对使用
	 * @param str
	 *            要解码的URL
	 * @param encoding
	 *            str的编码格式
	 * @return IP地址后字符串以字符'/'隔开,对每一段单独解码以encoding编码格式解码,其他部分不变
	 * @version: 2012_01_10
	 * 
	 *           <p>
	 *           注意:对字符/一起解码,将导致URL请求异常!!
	 */
	public static String decodeURLAfterHost(String str, String encoding) {
		final char splitter = '/';
		int index = str.indexOf(splitter);//第一个'/'的位置
		index++;//移到下一位置!!
		if (index < str.length() && str.charAt(index) == splitter) {//检测第一个'/'之后是否还是'/',如ftp://
			index++;//从下一个开始
			index = str.indexOf(splitter, index);//第三个'/';如ftp://anonymous:tmp@g.cn:219.223.168.20/中的最后一个'/'
			if (index > 0) {
				return str.substring(0, index + 1)
						+ decodeURL(str.substring(index + 1), encoding);//如ftp://anonymous:tmp@g.cn:219.223.168.20/天空
			} else
				return str;//如ftp://anonymous:tmp@g.cn:219.223.168.20
		}

		return decodeURL(str, encoding);

	}

	/**
	 * 此方法与{@link #encodeURL(String, String)}配对使用
	 * <p>
	 * 对{@link URLDecoder#decode(String, String)}的封装,但不解码'/'字符,对其他字符分段解码
	 * 
	 * @param str
	 *            要解码的URL
	 * @param encoding
	 *            str的编码格式
	 * @return 字符串以字符'/'隔开,对每一段单独编码以encoding编码格式解码
	 * @version: 2012_01_10
	 * 
	 *           <p>
	 *           注意:对字符/一起编码,导致URL请求异常!!
	 */
	public static String decodeURL(String str, String encoding) {
		final char splitter = '/';
		try {
			StringBuilder sb = new StringBuilder(str.length());
			int start = 0;
			for (int i = 0; i < str.length(); i++) {
				if (str.charAt(i) == splitter) {
					sb.append(URLDecoder.decode(str.substring(start, i),
							encoding));
					sb.append(splitter);
					start = i + 1;
				}
			}
			if (start < str.length())
				sb.append(URLDecoder.decode(str.substring(start), encoding));
			return sb.toString();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return null;
	}


3、乱码了还能恢复?
问题如下


貌似图中的utf-8改成iso8859-1是可以的,utf-8在字符串中有中文时不行(但英文部分仍可正确解析)!!!毕竟GBK的字节流对于utf-8可能是无效的,碰到无效的字符怎么解析,是否可逆那可不好说啊。

测试代码如下:

package tests;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

/**
 * @author LC
 * @version: 2012_01_12
 */
public class TestEncoding {
	static String utf8 = "utf-8";
	static String iso = "iso-8859-1";
	static String gbk = "GBK";

	public static void main(String[] args) throws UnsupportedEncodingException {
		String str = "hi好啊me";
		//		System.out.println("?的十六进制为:3F");
		//		System.err
		//				.println("出现中文时,如果编码方案不支持中文,每个字符都会被替换为?的对应编码!(如在iso-8859-1中)");
		System.out.println("原始字符串:\t\t\t\t\t\t" + str);
		String utf8_encoded = URLEncoder.encode(str, "utf-8");
		System.out.println("用URLEncoder.encode()方法,并用UTF-8编码后:\t\t" + utf8_encoded);
		String gbk_encoded = URLEncoder.encode(str, "GBK");
		System.out.println("用URLEncoder.encode()方法,并用GBK编码后:\t\t" + gbk_encoded);
		testEncoding(str, utf8, gbk);
		testEncoding(str, gbk, utf8);
		testEncoding(str, gbk, iso);
		printBytesInDifferentEncoding(str);
		printBytesInDifferentEncoding(utf8_encoded);
		printBytesInDifferentEncoding(gbk_encoded);
	}

	/**
	 * 测试用错误的编码方案解码后再编码,是否对原始数据有影响
	 * 
	 * @param str
	 *            输入字符串,Java的String类型即可
	 * @param encodingTrue
	 *            编码方案1,用于模拟原始数据的编码
	 * @param encondingMidian
	 *            编码方案2,用于模拟中间的编码方案
	 * @throws UnsupportedEncodingException
	 */
	public static void testEncoding(String str, String encodingTrue,
			String encondingMidian) throws UnsupportedEncodingException {
		System.out.println();
		System.out
				.printf("%s编码的字节数据->用%s解码并转为Unicode编码的JavaString->用%s解码变为字节流->读入Java(用%s解码)后变为Java的String\n",
						encodingTrue, encondingMidian, encondingMidian,
						encodingTrue);
		System.out.println("原始字符串:\t\t" + str);
		byte[] trueEncodingBytes = str.getBytes(encodingTrue);
		System.out.println("原始字节流:\t\t" + bytesToHexString(trueEncodingBytes)
				+ "\t\t//即用" + encodingTrue + "编码后的字节流");
		String encodeUseMedianEncoding = new String(trueEncodingBytes,
				encondingMidian);
		System.out.println("中间字符串:\t\t" + encodeUseMedianEncoding + "\t\t//即用"
				+ encondingMidian + "解码原始字节流后的字符串");
		byte[] midianBytes = encodeUseMedianEncoding.getBytes("Unicode");
		System.out.println("中间字节流:\t\t" + bytesToHexString(midianBytes)
				+ "\t\t//即中间字符串对应的Unicode字节流(和Java内存数据一致)");
		byte[] redecodedBytes = encodeUseMedianEncoding
				.getBytes(encondingMidian);
		System.out.println("解码字节流:\t\t" + bytesToHexString(redecodedBytes)
				+ "\t\t//即用" + encodingTrue + "解码中间字符串(流)后的字符串");
		String restored = new String(redecodedBytes, encodingTrue);
		System.out.println("解码字符串:\t\t" + restored + "\t\t和原始数据相同?  "
				+ restored.endsWith(str));
	}

	/**
	 * 将字符串分别编码为GBK、UTF-8、iso-8859-1的字节流并输出
	 * 
	 * @param str
	 * @throws UnsupportedEncodingException
	 */
	public static void printBytesInDifferentEncoding(String str)
			throws UnsupportedEncodingException {
		System.out.println("");
		System.out.println("原始String:\t\t" + str + "\t\t长度为:" + str.length());
		String unicodeBytes = bytesToHexString(str.getBytes("unicode"));
		System.out.println("Unicode bytes:\t\t" + unicodeBytes);
		String gbkBytes = bytesToHexString(str.getBytes("GBK"));
		System.out.println("GBK bytes:\t\t" + gbkBytes);
		String utf8Bytes = bytesToHexString(str.getBytes("utf-8"));
		System.out.println("UTF-8 bytes:\t\t" + utf8Bytes);
		String iso8859Bytes = bytesToHexString(str.getBytes("iso-8859-1"));
		System.out.println("iso8859-1 bytes:\t" + iso8859Bytes + "\t\t长度为:"
				+ iso8859Bytes.length() / 3);
		System.out.println("可见Unicode在之前加了两个字节FE FF,之后则每个字符两字节");
	}

	/**
	 * 将该数组转的每个byte转为两位的16进制字符,中间用空格隔开
	 * 
	 * @param bytes
	 *            要转换的byte序列
	 * @return 转换后的字符串
	 */
	public static final String bytesToHexString(byte[] bytes) {
		StringBuilder sb = new StringBuilder(bytes.length * 2);
		for (int i = 0; i < bytes.length; i++) {
			String hex = Integer.toHexString(bytes[i] & 0xff);// &0xff是byte小于0时会高位补1,要改回0
			if (hex.length() == 1)
				sb.append('0');
			sb.append(hex);
			sb.append(" ");
		}
		return sb.toString().toUpperCase();
	}
}

  • 大小: 32.8 KB
  • 大小: 35.7 KB
分享到:
评论

相关推荐

    Java网络传输中字符编码问题的研究

    Java网络传输中的字符编码问题主要涉及到Java编程语言在处理不同编码格式时的转换和兼容性。Java语言本身采用Unicode字符集,这是一种国际化的标准,能够支持世界上大多数语言,包括中文。然而,在实际的网络环境中...

    Java Http请求传json数据乱码问题的解决

    在实际解决乱码问题的过程中,如果发现使用Base64加密传输中文数据还会出现问题,可以改用URL编码的方式来传输数据,即使用JavaScript的`encodeURI`函数对数据进行两次URL编码,后端接收到后进行一次URL解码即可。...

    java中文乱码问题详解--- java中文乱码问题详解

    **网络传输中的编码问题**:在网络环境中,如Web应用程序中,客户端发送的数据和服务器端接收的数据可能存在编码不一致的情况,尤其是在处理HTTP请求时,若没有明确指定字符集,浏览器通常会默认使用UTF-8编码进行...

    用java代码编写的网络传输文件

    在Java编程语言中,网络传输文件是一个常见的任务,它涉及到客户端和服务器之间的数据交换。这里的“用java代码编写的网络传输文件”程序很可能是利用了Java的Socket编程接口,这是一种基于TCP/IP协议的基础通信机制...

    深入分析Java中的中文编码问题

    ### 深入分析Java中的中文编码问题 #### 一、引言 在软件开发过程中,尤其是涉及到国际化和多语言支持的应用中,编码问题一直是令开发者头疼的问题之一。尤其是在使用Java这种跨平台语言进行开发时,不同的操作...

    彻底解决中文乱码的问题

    在IT行业中,尤其是在Java编程领域,中文乱码问题是一个常见的挑战。这主要涉及到字符编码的处理,涉及到Unicode、GBK、UTF-8等不同编码格式之间的转换和一致性问题。本篇文章将深入探讨这个问题,并提供一种彻底...

    关于java中的编码转换问题(解决乱码问题)

    总之,Java中的编码转换涉及到多个层次,包括字符串、文件、网络请求等。正确理解和使用各种编码方法,以及在适当的地方设置合适的字符集,是避免乱码问题的关键。理解这些概念和操作,对于开发跨平台、多语言的应用...

    java Socket与C#通信中中文乱码问题的解决方案

    在Java和C#之间进行Socket通信时,遇到中文乱码问题主要是由于编码格式不一致导致的。Java默认使用UTF-8编码,而C#在处理字符串时可能使用其他编码,如GBK或ASCII。为了解决这个问题,我们需要确保两端在发送和接收...

    java中文乱码之解决URL中文乱码问题的方法

    总之,解决Java中的URL中文乱码问题需要理解URL编码的原理,并在客户端和服务器端采取相应的措施,确保编码和解码的一致性。无论是通过JavaScript编码、Java服务器端解码,还是调整服务器配置,关键在于确保字符集的...

    Java关于中文乱码问题的多种解决方法

    在Java编程中,中文乱码问题是一个常见的困扰,尤其是在处理文件读写、网络传输或数据库操作时。本文将深入探讨几种解决Java中中文乱码问题的方法,并以MyEclipse为开发环境,结合实际示例进行讲解。 1. 文件读写中...

    Java开发中文乱码问题解决

    在Java中,默认使用的是Unicode的UTF-8编码,但有时由于文件、数据库或网络传输等原因,可能会遇到其他编码格式,从而引发乱码问题。 **乱码问题的常见场景:** 1. **读写文件**:如果文件以GBK或其他非UTF-8编码...

    JAVA中文编码的问题研究

    3. 网络传输编码 在网络通信中,HTTP协议通常使用UTF-8编码。在发送和接收HTTP请求时,Java的`HttpURLConnection`和`HttpServletRequest`等类会处理编码转换。若未正确设置请求头中的`Content-Type`字段,如`charset...

    java中文乱码问题

    在Java编程中,中文乱码问题是一个常见的困扰,尤其是在处理文件读写、网络传输或数据库交互等场景。这里,我们将深入探讨这个问题的原因、解决方法以及相关的编码理论。 首先,我们需要理解编码的基础知识。计算机...

    java中文乱码大全

    3. 网络传输编码:浏览器在发送请求时,默认采用UTF-8编码格式,如果传输的参数中包含中文字符而服务端没有正确处理编码转换,也会引起乱码。 4. 跨平台运行问题:Java程序从一种操作系统移植到另一种操作系统时,...

    Java中的中文编码问题

    - **网络传输**:在网络传输过程中,尤其是在HTTP协议中,客户端和服务器之间的字符编码需要保持一致,以避免乱码问题。 - **数据库操作**:与数据库交互时,确保数据库字段和连接的编码设置正确至关重要。 - **字符...

    java应用中的汉字编码问题

    Java应用程序在处理汉字编码时,常常会遇到一些挑战和陷阱,这是因为编码的多样性和不兼容性。...提供的两个PDF文件,很可能是详细讲解这些问题的教程或指南,阅读它们将加深对Java编码问题的理解。

    Java中文乱码问题研究.pdf

    针对客户端和服务器端传输数据,客户端显示中文字符编码,及应用程序与数据库之间的数据交互等问题,分析了Java乱码产生的原因,并针对每种情况,结合实际的项目开发经验,给出了设置页面编码方式、修改Web服务器...

    Java中文乱码浅析及解决方案

    综上所述,解决Java中文乱码问题的关键在于确保整个程序的编码一致性,包括源代码、编译器、运行环境、文件读写、网络传输以及数据库操作等环节。通过细心配置和适当地指定编码,我们可以有效地避免乱码问题,确保...

    解决中文乱码问题-java

    这主要涉及到字符编码的处理,如果在数据传输、存储或显示过程中没有正确地指定或转换编码,就容易出现乱码现象。以下是对如何在Java中解决中文乱码问题的详细解析。 ### 解决中文乱码问题的核心思路 解决中文乱码...

    js解码 、java编码

    Java的编码问题常常出现在读写文件、网络传输或数据库操作中。例如,如果一个文件以UTF-8编码保存,但程序以GBK编码读取,就会出现乱码。为了避免此类问题,开发人员必须明确指定正确的字符集,并始终确保编码和解码...

Global site tag (gtag.js) - Google Analytics