热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

如何解决Java编码及网络传输中的编码问题

这篇文章给大家介绍如何解决Java编码及网络传输中的编码问题,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。近来试着FT

这篇文章给大家介绍如何解决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、表单数据的编码

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

解决方案如下:

如何解决Java编码及网络传输中的编码问题

当然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   *           

   *           注意:未考虑':',如直接对http://编解码,会产生错误!!!请在使用前将其分离出来,可以使用   *           {@link #encodeURLAfterHost(String, String)}方法解决此问题   *           

   *           注意:对字符/一起编码,导致URL请求异常!!   */ public static String encodeURL(String str, String encoding) {      final char splitter = &#39;/&#39;;      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通过&#39;/&#39;分割后进行分段编码.   * 

   * 对{@link URLEncoder#encode(String, String)}   * 的封装,但不编码&#39;/&#39;字符,也不编码网站部分(如ftp://a.b.c.d/部分,检测方法为对三个&#39;/&#39;字符的检测,且要求前两个连续),   * 对其他字符分段编码   *    * @param str   *            要编码的URL   * @param encoding   *            编码格式   * @return IP地址后字符串以字符&#39;/&#39;隔开,对每一段单独编码以encoding编码格式编码,其他部分不变   * @version: 2012_01_10   *           

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

   *           注意:对字符/一起解码,将导致URL请求异常!!   */ public static String decodeURLAfterHost(String str, String encoding) {      final char splitter = &#39;/&#39;;      int index = str.indexOf(splitter);//***个&#39;/&#39;的位置      index++;//移到下一位置!!      if (index < str.length() && str.charAt(index) == splitter) {//检测***个&#39;/&#39;之后是否还是&#39;/&#39;,如ftp://          index++;//从下一个开始          index = str.indexOf(splitter, index);//第三个&#39;/&#39;;如ftp://anonymous:tmp@g.cn:219.223.168.20/中的***一个&#39;/&#39;          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)}配对使用   * 

   * 对{@link URLDecoder#decode(String, String)}的封装,但不解码&#39;/&#39;字符,对其他字符分段解码   *    * @param str   *            要解码的URL   * @param encoding   *            str的编码格式   * @return 字符串以字符&#39;/&#39;隔开,对每一段单独编码以encoding编码格式解码   * @version: 2012_01_10   *    *           

   *           注意:对字符/一起编码,导致URL请求异常!!   */ public static String decodeURL(String str, String encoding) {      final char splitter = &#39;/&#39;;      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、乱码了还能恢复?

问题如下:

如何解决Java编码及网络传输中的编码问题

貌似图中的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(&#39;0&#39;);              sb.append(hex);              sb.append(" ");          }          return sb.toString().toUpperCase();      }  }

关于如何解决Java编码及网络传输中的编码问题就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。


推荐阅读
  • 在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板
    本文介绍了在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板的方法和步骤,包括将ResourceDictionary添加到页面中以及在ResourceDictionary中实现模板的构建。通过本文的阅读,读者可以了解到在Xamarin XAML语言中构建控件模板的具体操作步骤和语法形式。 ... [详细]
  • 本文介绍了使用kotlin实现动画效果的方法,包括上下移动、放大缩小、旋转等功能。通过代码示例演示了如何使用ObjectAnimator和AnimatorSet来实现动画效果,并提供了实现抖动效果的代码。同时还介绍了如何使用translationY和translationX来实现上下和左右移动的效果。最后还提供了一个anim_small.xml文件的代码示例,可以用来实现放大缩小的效果。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • Android系统移植与调试之如何修改Android设备状态条上音量加减键在横竖屏切换的时候的显示于隐藏
    本文介绍了如何修改Android设备状态条上音量加减键在横竖屏切换时的显示与隐藏。通过修改系统文件system_bar.xml实现了该功能,并分享了解决思路和经验。 ... [详细]
  • PHPMailer邮件类邮件发送功能的使用教学及注意事项
    本文介绍了使用国外开源码PHPMailer邮件类实现邮件发送功能的简单教学,同时提供了一些注意事项。文章涵盖了字符集设置、发送HTML格式邮件、群发邮件以及避免类的重定义等方面的内容。此外,还提供了一些与PHP相关的资源和服务,如传奇手游游戏源码下载、vscode字体调整、数据恢复、Ubuntu实验环境搭建、北京爬虫市场、进阶PHP和SEO人员需注意的内容。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • 本文讨论了在PHP中将空格转换为问号的问题,并提供了解决方案。文章指出,空格不是标准的空格,而是特殊的0xC2 0xA0字符。作者尝试使用mb_convert_encoding函数将utf8字符串转换为gbk编码,但未成功。文章建议检查编辑器是否对空格进行了特殊处理,并提供了使用base64_encode函数打印结果的方法。最后,给出了完整的代码示例。 ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
author-avatar
顺辉1988
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有