使用java的native2ascii工具命令来转换编码gbk,gb2312,utf-8

背景:在做Java 开发的时候,常常会出现一些乱码,或者无法正确识别或读取的文件,比如常见的validator验证用的消息资源(properties)文件就需要进行 Unicode重新编码。原因是java默认的编码方式为Unicode,而我们的计算机系统编码常常是GBK等编码。需要将系统的编码转换为java正 确识别的编码问题就解决了。
1、native2ascii简介:native2ascii 是sun java sdk提供的一个工具。用来将别的文本类文件(比如*.txt,*.ini,*.properties,*.java等等)编码转为Unicode编码。 为什么要进行转码,原因在于程序的国际化。Unicode编码的定义:Unicode(统一码、万国码、单一码)是一种在计算机上使用的字符编码。它为每 种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。1990年开始研发,1994年正式公布。随着计算 机工作能力的增强,Unicode也在面世以来的十多年里得到普及。(声明:Unicode编码定义来自互联网)。
2、获取native2ascii:安装了jdk后,假如你是在windows上安装,那么在jdk的安装目录下,会有一个bin目录,其中native2ascii.exe正是。
3、native2ascii的命令行的命名格式
native2ascii -[options] [inputfile [outputfile]]
说明:
-[options]:表示命令开关,有两个选项可供选择
-reverse:将Unicode编码转为本地或者指定编码,不指定编码情况下,将转为本地编码。
-encoding encoding_name:转换为指定编码,encoding_name为编码名称。
[inputfile [outputfile]]
inputfile:表示输入文件全名。
outputfile:输出文件名。如果缺少此参数,将输出到控制台。

类的加载、连接、初始化

 Java类的加载、连接、初始化

遍历map


import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
* 遍历map的几种方法
* @author tpf
*
*/
public class TestMapLookup {

public static void main(String[] args) {
Map map = new HashMap();
map.put(“aaa”, 1);
map.put(“ccc”, 2);
map.put(“bbb”, 3);

//方法一for
for(Map.Entry entry: map.entrySet()){
System.out.println(entry.getKey() + “—>” + entry.getValue());
}

//方法二keySet()
Set set = map.keySet();
Iterator it = set.iterator();
while(it.hasNext()) {
String key = it.next();
int value = map.get(key);
System.out.println(key + “—>” + value);
}

//方法三entrySet()
Set> set1 = map.entrySet();
Iterator > it1 = set1.iterator();
while(it1.hasNext()) {
Map.Entry entry = it1.next();
System.out.println(entry.getKey() + “—->” + entry.getValue());
}
}
}

[ad#468*60-t2]

java的数据类型

Java中数据类型分为两大类:基本类型和对象类型

相应的,变量也就有两种类型:基本类型和引用类型

基本类型的值可能是一个数字,一个字符或一个布尔值。

引用类型,它是一个对象类型,它的值是指向内存空间的引用,就是地址,所指向的内存中保存着变量所表示的一个值或一组值。

[ad#468*60-t3]

java的数据结构

线性表,链表,哈希表是常用的数据结构,在进行Java开发时,JDK已经为我们提供了一系列相应的类来实现基本的数据结构。这些类均在java.util包中。本文试图通过简单的描述,向读者阐述各个类的作用以及如何正确使用这些类。
Collection
├ List
│├ LinkedList
│├ ArrayList
│└ Vector
│ └ Stack
└ Set

Map
├ Hashtable
├ HashMap
└ WeakHashMap

Collection接口:
    Collection是最基本的集合接口,一个Collection代表一组Object,即Collection的元素(Elements)。一些 Collection允许相同的元素而另一些不行。一些能排序而另一些不行。Java SDK不提供直接继承自Collection的类, Java SDK提供的类都是继承自Collection的“子接口”如List和Set。  所有实现Collection接口的类都必须提供 两个标准的构造函数:无参数的构造函数用于创建一个空的Collection,有一个Collection参数的构造函数用于创建一个新的 Collection,这个新的Collection与传入的Collection有相同的元素。后一个构造函数允许用户复制一个Collection。  如何遍历Collection中的每一个元素?不论Collection的实际类型如何,它都支持一个iterator()的方法,该方法返回一个迭代子,使用该迭代子即可逐一访问Collection中每一个元素。典型的用法如下:

Java代码


Iterator it = collection.iterator(); // 获得一个迭代子    

while(it.hasNext()) {      

  Object obj = it.next(); // 得到下一个元素    

}

由Collection接口派生的两个接口是List和Set。主要方法:
boolean add(Object o)添加对象到集合
boolean remove(Object o)删除指定的对象
int size()返回当前集合中元素的数量
boolean contains(Object o)查找集合中是否有指定的对象
boolean isEmpty()判断集合是否为空
Iterator iterator()返回一个迭代器
boolean containsAll(Collection c)查找集合中是否有集合c中的元素
boolean addAll(Collection c)将集合c中所有的元素添加给该集合
void clear()删除集合中所有元素
void removeAll(Collection c)从集合中删除c集合中也有的元素
void retainAll(Collection c)从集合中删除集合c中不包含的元素

List接口
    List是有序的Collection,使用此接口能够精确的控制每个元素插入的位置。用户能够使用索引(元素在List中的位置,类似于数组下标)来访问List中的元素,这类似于Java的数组。和下面要提到的Set不同,List允许有相同的元素。   
    除了具有Collection接口必备的iterator()方法外,List还提供一个listIterator()方法,返回一个 ListIterator接口,和标准的Iterator接口相比,ListIterator多了一些add()之类的方法,允许添加,删除,设定元素, 还能向前或向后遍历。  
    实现List接口的常用类有LinkedList,ArrayList,Vector和Stack。
    主要方法:
void add(int index,Object element)在指定位置上添加一个对象
boolean addAll(int index,Collection c)将集合c的元素添加到指定的位置
Object get(int index)返回List中指定位置的元素
int indexOf(Object o)返回第一个出现元素o的位置.
Object removeint(int index)删除指定位置的元素
Object set(int index,Object element)用元素
element取代位置index上的元素,返回被取代的元素

LinkedList类(非同步的)  
     LinkedList实现了List接口,允许null元素。此外LinkedList提供额外的get,remove,insert方法在 LinkedList的首部或尾部。这些操作使LinkedList可被用作堆栈(stack),队列(queue)或双向队列(deque)。  
     注意LinkedList没有同步方法。如果多个线程同时访问一个List,则必须自己实现访问同步。一种解决方法是在创建List时构造一个同步的List:    
     List list = Collections.synchronizedList(new LinkedList(…));

ArrayList类(非同步的)  
     ArrayList实现了可变大小的数组。它允许所有元素,包括null。ArrayList没有同步。size,isEmpty,get,set方法运行时间为常数。但是add方法开销为分摊的常数,添加n个元素需要O(n)的时间。其他的方法运行时间为线性。   
     每个ArrayList实例都有一个容量(Capacity),即用于存储元素的数组的大小。这个容量可随着不断添加新元素而自动增加,但是增长算法并 没有定义。当需要插入大量元素时,在插入前可以调用ensureCapacity方法来增加ArrayList的容量以提高插入效率。  
     和LinkedList一样,ArrayList也是非同步的(unsynchronized)。
     主要方法:
Boolean add(Object o)将指定元素添加到列表的末尾
Boolean add(int index,Object element)在列表中指定位置加入指定元素
Boolean addAll(Collection c)将指定集合添加到列表末尾
Boolean addAll(int index,Collection c)在列表中指定位置加入指定集合
Boolean clear()删除列表中所有元素Boolean clone()返回该列表实例的一个拷贝
Boolean contains(Object o)判断列表中是否包含元素
Boolean ensureCapacity(int m)增加列表的容量,如果必须,该列表能够容纳m个元素
Object get(int index)返回列表中指定位置的元素
Int indexOf(Object elem)在列表中查找指定元素的下标
Int size()返回当前列表的元素个数

Vector类(同步的)   
   Vector非常类似ArrayList,但是Vector是同步的。由Vector创建的Iterator,虽然和ArrayList创建的 Iterator是同一接口,但是,因为Vector是同步的,当一个Iterator被创建而且正在被使用,另一个线程改变了Vector的状态(例如,添加或删除了一些元素),这时调用Iterator的方法时将抛出ConcurrentModificationException,因此必须捕获该异常。

Stack 类(同步的)  
     Stack继承自Vector,实现一个后进先出的堆栈。Stack提供5个额外的方法使得 Vector得以被当作堆栈使用。基本的push和pop方法,还有peek方法得到栈顶的元素,empty方法测试堆栈是否为空,search方法检测一个元素在堆栈中的位置。Stack刚创建后是空栈。

Set接口  
      Set是一种不包含重复的元素的Collection,即任意的两个元素e1和e2都有e1.equals(e2)=false,Set最多有一个null元素。  
      很明显,Set的构造函数有一个约束条件,传入的Collection参数不能包含重复的元素。  
      请注意:必须小心操作可变对象(Mutable Object)。如果一个Set中的可变元素改变了自身状态导致Object.equals(Object)=true将导致一些问题。

Map接口   
    请注意,Map没有继承Collection接口,Map提供key到value的映射。一个Map中不能包含相同的key,每个key只能映射一个 value。Map接口提供3种集合的视图,Map的内容可以被当作一组key集合,一组value集合,或者一组key-value映射。
    主要方法:
boolean equals(Object o)比较对象
boolean remove(Object o)删除一个对象
put(Object key,Object value)添加key和value

Hashtable类(同步的)  
     Hashtable继承Map接口,实现一个key-value映射的哈希表。任何非空(non-null)的对象都可作为key或者value。  
    添加数据使用put(key, value),取出数据使用get(key),这两个基本操作的时间开销为常数。Hashtable 通过initial capacity和load factor两个参数调整性能。通常缺省的load factor 0.75较好地实现了时间和空间的 均衡。增大load factor可以节省空间但相应的查找时间将增大,这会影响像get和put这样的操作。使用Hashtable的简单示例如下,将1,2,3放到Hashtable中,他们的key分别是”one”,”two”, ”three”:

Java代码

Hashtable numbers = new Hashtable();    

numbers.put(“one”, new Integer(1));    

numbers.put(“two”, new Integer(2));    

numbers.put(“three”, new Integer(3));

要取出一个数,比如2,用相应的key:

Java代码

 Integer n = (Integer)numbers.get(“two”);    

System.out.println(“two = ” + n);

    由于作为key的对象将通过计算其散列函数来确定与之对应的value的位置,因此任何作为key的对象都必须实现hashCode和equals方 法。hashCode和equals方法继承自根类Object,如果你用自定义的类当作key的话,要相当小心,按照散列函数的定义,如果两个对象相 同,即obj1.equals(obj2)=true,则它们的hashCode必须相同,但如果两个对象不同,则它们的hashCode不一定不同,如果两个不同对象的hashCode相同,这种现象称为冲突,冲突会导致操作哈希表的时间开销增大,所以尽量定义好的hashCode()方法,能加快哈希 表的操作。  
    如果相同的对象有不同的hashCode,对哈希表的操作会出现意想不到的结果(期待的get方法返回null),要避免这种问题,只需要牢记一条:要同时复写equals方法和hashCode方法,而不要只写其中一个。  Hashtable是同步的。

HashMap类(非同步的)
    HashMap 和Hashtable类似,不同之处在于HashMap是非同步的,并且允许null,即null value和null key。,但是将 HashMap视为Collection时(values()方法可返回Collection),其迭代子操作时间开销和HashMap的容量成比例。因 此,如果迭代操作的性能相当重要的话,不要将HashMap的初始化容量设得过高,或者load factor过低。WeakHashMap类(非同步的)  
     WeakHashMap是一种改进的HashMap,它对key实行“弱引用”,如果一个key不再被外部所引用,那么该key可以被GC回收。

总结  
   如果涉及到堆栈,队列等操作,应该考虑用List,对于需要快速插入,删除元素,应该使用LinkedList,如果需要快速随机访问元素,应该使用ArrayList。  
    如果程序在单线程环境中,或者访问仅仅在一个线程中进行,考虑非同步的类,其效率较高,如果多个线程可能同时操作一个类,应该使用同步的类。
同步的类:
Vector
Stack 
Hashtable
不同步的类:
LinkedList
ArrayList
HashMap
  要特别注意对哈希表的操作,作为key的对象要正确复写equals和hashCode方法。  尽量返回接口而非实际的类型,如返回List而非ArrayList,这样如果以后需要将ArrayList换成LinkedList时,客户端代码不用改变。这就是针对抽象(接口)编程。

Wait sleep区别

  • 来源不同
    • Sleep是Thread提供的方法
    • Wait继承自Object
  • 代码位置不同
    • Wait需要写在Synchronize语句块里面
  • 是否释放锁定对象
    • 调用wait方法,释放锁定该对象
    • Sleep时别的线程也不可以访问锁定对象

Synchronized总结

  • 无论synchronized关键字加在方法上还是对象上,它取得的锁都是锁在了对象上,而不是把一段代码或函数当作锁――而且同步方法很可能还会被其他线程的对象访问。
  • 每个对象只有一个锁(lock)与之相关联。
  • 实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。
  • 搞清楚synchronized锁定的是哪个对象,就能帮助我们设计更安全的多线程程序。
  • 还有一些技巧可以让我们对共享资源的同步访问更加安全:
    • 定义private 的instance变量+它的 get方法,而不要定义public/protected的instance变量。如果将变量定义为public,对象在外界可以绕过同步方法的控制而直接取得它,并改动它。
    • 如果instance变量是一个对象,如数组或ArrayList什么的,那上述方法仍然不安全,因为当外界对象通过get方法拿到这个instance对象的引用后,又将其指向另一个对象,那么这个private变量也就变了,岂不是很危险。 这个时候就需要将get方法也加上synchronized同步,并且,只返回这个private对象的clone()――这样,调用端得到的就是对象副本的引用了。

对于synchronized,其使用原则就是能同步两行就不要同步三步,能同步一部分代码就不要同步整个方法,尽量少用同步

关于锁的理解:

关键是看它锁定的对象或者引用所指向的对象是否一致。同步的时候就用锁对对象进行加锁,有了这锁就可以防止对方访问,要访问就要排队,但是对自身来说要访问则没任何障碍。

JAVA是解释型语言还是编译型语言

 

JAVA是解释型语言还是编译型语言

概念:

  • 编译型语言:把做好的源程序全部编译成二进制代码的可运行程序。然后,可直接运行这个程序。
  • 解释型语言:把做好的源程序翻译一句,然后执行一句,直至结束!

 

区别:

  • 编译型语言,执行速度快、效率高;依赖编译器、跨平台性差些。如C、C++、Delphi、Pascal,Fortran。
  • 解释型语言,执行速度慢、效率低;依赖解释器、跨平台性好。如Java、Basic.

 

通俗的讲,编译语言是在编译后可以直接运行,而解释语言的执行需要一个解释环境。

 java很特殊,java程序也需要编译,但是没有直接编译称为机器语言,而是编译称为字节码,然后用解释方式执行字节码。

JIT:

  • 首先采用编译形式生成某种中介代码(Java bytecode/MSIL),然后在运行时将其(通常以函数或Block为单位)最终转换成机器码,然后执行,转化的机器码可以被cache,以提高重复执行的效率

动态语言和静态语言

 

1.动态语言Dynamically Typed Language

例如:ECMAScript(JavaScript)、Ruby、Python、VBScript、php

也叫动态类型定义语言

与静态类型定义相反,一种在执行期间才去发现数据类型的语言,

动态语言是指程序在运行时可以改变其结构:新的函数可以被引进,已有的函数可以被删除等在结构上的变化。

动态语言的类型检查是在运行时做的。

它的优点是方便阅读,不需要写非常多的类型相关的代码;

缺点是不方便调试,命名不规范时会造成读不懂,不利于理解等。

目前java平台下的动态语言有Groovy、nice、BeanShell、Jython、JRuby、Rhino(JavaScript)、Jacl(TCL)、Bistro(SmallTalk)、Kawa(Lisp/Schema),真是越来越多了。java下这么多的动态语言建议选择Groovy,感觉血统较为正宗,兼容Java的语法,java程序员学习起来较为容易,上手较快。

2.静态语言Statically Typed Language

例如:C、C++、Java

也叫静态类型定义语言。即一种在编译时,数据类型是固定的语言。大多数静态类型定义语言强制这一点,它要求你在使用所有变量之前要声明它们的数据类型。

在使用数据之前,我们必须首先定义数据类型,这些数据类型包括int ,float,double等等。就相当于在使用它们之前,首先要为它们分配好内存空间。

静态类型语言的主要优点在于其结构非常规范,便于调试,方便类型安全;

缺点是为此需要写更多的类型相关代码,导致不便于阅读、不清晰明了。

3.强类型定义语言

一种总是强制类型定义的语言。Java和Python是强制类型定义的。如果你有一个整数,如果不显示地进行转换,你不能将其视为一个字符串

4.弱类型定义语言

一种类型可以被忽略的语言,与强类型定义相反。VBScript是弱类型定义

的。在VBScript中,可以将字符串 ’12′ 和整数 3 进行连接得到字符串 ’123′,

然后可以把它看成整数 123,而不需要显示转换。

5.脚本语言

脚本语言代表一套与系统程序设计语言不同的协定。

它们牺牲执行速度和与系统程序设计语言相关的类型长度而提供更高的编程创作力和软件重用。

脚本语言更适合在联系复杂的应用程序中进行胶着。

为了简化连接组件的工作,脚本语言被设计为无类型的,脚本语言一般是面向字符的,因为字符为许多不同的事物提供了一致的描述。

事实上,脚本语言都是动态语言,而动态语言都是解释型语言,不管它们是不是面向对象。

ASCII,Unicode和UTF-8 字符编码问题

 

ASCII,Unicode和UTF-8

ASCII码

  • 我们知道,在计算机内部,所有的信息最终都表示为一个二进制的字符串。每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出 256种状态,这被称为一个字节(byte)。
  • 也就是说,一个字节一共可以用来表示256种不同的状态,每一个状态对应一个符号,就是256个符号,从 0000000到11111111。
  • 上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定。这被称为ASCII码,一直沿用至今。
  • ASCII码一共规定了128个字符的编码,比如空格“SPACE”是32(二进制00100000),大写的字母A是65(二进制01000001)。这128个符号(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前面的1位统一规定为0。

非ASCII编码

  • 英语用128个符号编码就够了,但是用来表示其他语言,128个符号是不够的。比如,在法语中,字母上方有注音符号,它就无法用ASCII码表示。 于是,一些欧洲国家就决定,利用字节中闲置的最高位编入新的符号。比如,法语中的é的编码为130(二进制10000010)。这样一来,这些欧洲国家使 用的编码体系,可以表示最多256个符号。
  • 但是,这里又出现了新的问题。不同的国家有不同的字母,因此,哪怕它们都使用256个符号的编码方式,代表的字母却不一样。比如,130在法语编码 中代表了é,在希伯来语编码中却代表了字母Gimel (ג),在俄语编码中又会代表另一个符号。但是不管怎样,所有这些编码方式中,0—127表示的符号是一样的,不一样的只是128—255的这一段。
  • 至于亚洲国家的文字,使用的符号就更多了,汉字就多达10万左右。一个字节只能表示256种符号,肯定是不够的,就必须使用多个字节表达一个符号。 比如,简体中文常见的编码方式是GB2312,使用两个字节表示一个汉字,所以理论上最多可以表示256×256=65536个符号。
  • 中文编码的问题需要专文讨论,这篇笔记不涉及。这里只指出,虽然都是用多个字节表示一个符号,但是GB类的汉字编码与后文的Unicode和UTF-8是毫无关系的。

Unicode

  • 正如上一节所说,世界上存在着多种编码方式,同一个二进制数字可以被解释成不同的符号。因此,要想打开一个文本文件,就必须知道它的编码方式,否则用错误的编码方式解读,就会出现乱码。为什么电子邮件常常出现乱码?就是因为发信人和收信人使用的编码方式不一样。
  • 可以想象,如果有一种编码,将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码,那么乱码问题就会消失。这就是Unicode,就像它的名字都表示的,这是一种所有符号的编码。
  • Unicode当然是一个很大的集合,现在的规模可以容纳100多万个符号。每个符号的编码都不一样,比如,U+0639表示阿拉伯字母Ain,U+0041表示英语的大写字母A,U+4E25表示汉字“严”。具体的符号对应表,可以查询unicode.org,或者专门的汉字对应表

Unicode的问题

  • 需要注意的是,Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。
  • 比如,汉字“严”的unicode是十六进制数4E25,转换成二进制数足足有15位(100111000100101),也就是说这个符号的表示至少需要2个字节。表示其他更大的符号,可能需要3个字节或者4个字节,甚至更多。
  • 这里就有两个严重的问题,第一个问题是,如何才能区别unicode和ascii?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号 呢?第二个问题是,我们已经知道,英文字母只用一个字节表示就够了,如果unicode统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必 然有二到三个字节是0,这对于存储来说是极大的浪费,文本文件的大小会因此大出二三倍,这是无法接受的。
  • 它们造成的结果是:1)出现了unicode的多种存储方式,也就是说有许多种不同的二进制格式,可以用来表示unicode。2)unicode在很长一段时间内无法推广,直到互联网的出现。

UTF-8

  • 互联网的普及,强烈要求出现一种统一的编码方式。UTF-8就是在互联网上使用最广的一种unicode的实现方式。其他实现方式还包括UTF-16和UTF-32,不过在互联网上基本不用。重复一遍,这里的关系是,UTF-8是Unicode的实现方式之一。
  • UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。
  • UTF-8的编码规则很简单,只有二条:
  • 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。
  • 对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。
  • 下表总结了编码规则,字母x表示可用编码的位。

Unicode符号范围 | UTF-8编码方式

(十六进制) | (二进制)

——————–+———————————————

0000 0000-0000 007F | 0xxxxxxx

0000 0080-0000 07FF | 110xxxxx 10xxxxxx

0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx

0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

  • 下面,还是以汉字“严”为例,演示如何实现UTF-8编码。
  • 已知“严”的unicode是4E25(100111000100101),根据上表,可以发现4E25处在第三行的范围内(0000 0800-0000 FFFF),因此“严”的UTF-8编码需要三个字节,即格式是“1110xxxx 10xxxxxx 10xxxxxx”。然后,从“严”的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,“严”的UTF-8编码是 “11100100 10111000 10100101”,转换成十六进制就是E4B8A5。

Unicode与UTF-8之间的转换

  • 通过上一节的例子,可以看到“严”的Unicode码是4E25,UTF-8编码是E4B8A5,两者是不一样的。它们之间的转换可以通过程序实现。
  • 在Windows平台下,有一个最简单的转化方法,就是使用内置的记事本小程序Notepad.exe。打开文件后,点击“文件”菜单中的“另存为”命令,会跳出一个对话框,在最底部有一个“编码”的下拉条。
  • UTF-8
  • 里面有四个选项:ANSI,Unicode,Unicode big endian 和 UTF-8。
  • ANSI是默认的编码方式。对于英文文件是ASCII编码,对于简体中文文件是GB2312编码(只针对Windows简体中文版,如果是繁体中文版会采用Big5码)。
  • Unicode编码指的是UCS-2编码方式,即直接用两个字节存入字符的Unicode码。这个选项用的little endian格式。
  • Unicode big endian编码与上一个选项相对应。我在下一节会解释little endian和big endian的涵义。
  • UTF-8编码,也就是上一节谈到的编码方法。
  • 选择完”编码方式“后,点击”保存“按钮,文件的编码方式就立刻转换好了。

Little endian和Big endian

  • 上一节已经提到,Unicode码可以采用UCS-2格式直接存储。以汉字”严“为例,Unicode码是4E25,需要用两个字节存储,一个字节 是4E,另一个字节是25。存储的时候,4E在前,25在后,就是Big endian方式;25在前,4E在后,就是Little endian方式。
  • 这两个古怪的名称来自英国作家斯威夫特的《格列佛游记》。在该书中,小人国里爆发了内战,战争起因是人们争论,吃鸡蛋时究竟是从大头(Big- Endian)敲开还是从小头(Little-Endian)敲开。为了这件事情,前后爆发了六次战争,一个皇帝送了命,另一个皇帝丢了王位。
  • 因此,第一个字节在前,就是”大头方式“(Big endian),第二个字节在前就是”小头方式“(Little endian)。
  • 那么很自然的,就会出现一个问题:计算机怎么知道某一个文件到底采用哪一种方式编码?
  • Unicode规范中定义,每一个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做”零宽度非换行空格“(ZERO WIDTH NO-BREAK SPACE),用FEFF表示。这正好是两个字节,而且FF比FE大1。
  • 如果一个文本文件的头两个字节是FE FF,就表示该文件采用大头方式;如果头两个字节是FF FE,就表示该文件采用小头方式。

实例

  • 下面,举一个实例。
  • 打开”记事本“程序Notepad.exe,新建一个文本文件,内容就是一个”严“字,依次采用ANSI,Unicode,Unicode big endian 和 UTF-8编码方式保存。
  • 然后,用文本编辑软件UltraEdit中的”十六进制功能“,观察该文件的内部编码方式。
  • ANSI:文件的编码就是两个字节“D1 CF”,这正是“严”的GB2312编码,这也暗示GB2312是采用大头方式存储的。
  • Unicode:编码是四个字节“FF FE 25 4E”,其中“FF FE”表明是小头方式存储,真正的编码是4E25。
  • Unicode big endian:编码是四个字节“FE FF 4E 25”,其中“FE FF”表明是大头方式存储。
  • UTF-8:编码是六个字节“EF BB BF E4 B8 A5”,前三个字节“EF BB BF”表示这是UTF-8编码,后三个“E4B8A5”就是“严”的具体编码,它的存储顺序与编码顺序是一致的。
字体大小: 减小一号 减小一号
▲ Back to top 繁體