精华内容
下载资源
问答
  • Windows文件名的编码为GBK,而在Linux文件名的编码为UTF-8。 所以当在Windows上使用ftp方式从Linux上传下拉时,会导致上传文件名的中文变成了乱码,而下拉时找不到指定文件, 解决办法: 1、CentOS 输入 ...

    问题

    在Windows上文件名的编码为GBK,而在Linux上文件名的编码为UTF-8。

    所以当在Windows上使用ftp方式从Linux上传下拉时,会导致上传文件名的中文变成了乱码,而下拉时找不到指定文件,

    解决办法:

    1、CentOS下 输入

    yum install convmv
    convmv -f gbk -t utf-8 -r --notest /home/

    如果显示key报错,可以在安装后面加上 --gpgnocheck

    --notest 后面跟的就是转换编码的目录或者文件名

    2、在Windows端的代码端将文件名转为utf-8

    char* GBKToUTF8( const char* chGBK )
    {
    	DWORD dWideBufSize=MultiByteToWideChar(CP_ACP, 0,(LPCSTR)chGBK,-1, NULL, 0);  
    	wchar_t * pWideBuf[124];  
    	wmemset(pWideBuf, 0, dWideBufSize);  
    	MultiByteToWideChar(CP_ACP,0,(LPCSTR)chGBK,-1,pWideBuf,dWideBufSize);
     
    	DWORD dUTF8BufSize=WideCharToMultiByte(CP_UTF8,0(LPCWSTR)pWideBuf,-1,NULL,0,NULL,NULL); 
    	char * pUTF8Buf=[124];  
    	memset(pUTF8Buf, 0, dUTF8BufSize);  
    	WideCharToMultiByte( CP_UTF8,0,(LPCWSTR)pWideBuf,-1,pUTF8Buf,dUTF8BufSize,NULL,NULL);
     
    	free(pWideBuf);
    	return pUTF8Buf;
    }

     

    展开全文
  • 利用 winSCP 将windows系统下的文件上传到linux 下,含有中文的文件名,其文件在linux下会显示乱码 ,可以在winscp 环境中设置。 linux下经常遇到的编码问题 如果你需要在Linux中操作windows下的文件,那么你...
    利用 winSCP 将windows系统下的文件上传到linux 下,含有中文的文件名,其文件在linux下会显示乱码 ,可以在winscp 环境中设置。


    linux下经常遇到的编码问题
    如果你需要在Linux中操作windows下的文件,那么你可能会经常遇到文件编码转换的问题。Windows中默认的文件格式是GBK(gb2312),而Linux一般都是UTF-8
    查看编码的方法
    方法一:file filename
    方法二:在Vim中可以直接查看文件编码
    :set fileencoding
    如果你只是想查看其它编码格式的文件或者想解决用Vim查看文件乱码的问题,那么你可以在
    ~/.vimrc 文件中添加以下内容:
    set encoding=utf-8 fileencodings=ucs-bom,utf-8,cp936
    这样,就可以让vim自动识别文件编码(可以自动识别UTF-8或者GBK编码的文件),其实就是依照fileencodings提供的编码列表尝试,如果没有找到合适的编码,就用latin-1ASCII)编码打开
    文件编码转换
    多平台方法:
    iconv        提供标准的程序和API来进行编码转换;
    convert_encoding.py    基于Python的文本文件转换工具;
    decodeh.py    提供算法和模块来谈测字符的编码;

    linux下文件编码转换:

    方法一:

    在Vim中直接进行转换文件编码,比如将一个文件转换成utf-8格式
      :set fileencoding=utf-8

    或者

    11)设置文件集合,即要对哪些文件进行操作,可以使用通配符,比如我通常是对 C/C++ 源程序进行编码转换

    :args *.h *.cpp

    2)给出要在每个文件上执行的命令,这里是转换编码:

    :argdo set fenc=utf-8 | update

    方法二:

    iconv 转换

    5.案例:

    假如说我们将windows下的一个UTF-8的文件传到linux环境下,linux环境下的系统编码是GB18030,我们cat的时候就会出现乱码,这个时候就应该想到转码了,下面我们来进行试验:

    我们将windows下一个名为UTF-8.sh的文件传到linux系统中,其中UTF-8.sh的内容如下:

    我是中文编码UTF-8模式~

    而linux系统的系统语言设置为:

    [root@sor-sys zy]# cat /etc/sysconfig/i18n 
    LANG=zh_CN.GB18030
    SYSFONT="latarcyrheb-sun16"
    这个时候查看一下文件的内容及编码:

    [root@sor-sys zy]# file UTF-8.sh 
    UTF-8.sh: UTF-8 Unicode text, with no line terminators
    [root@sor-sys zy]# cat UTF-8.sh 
    锘挎垜鏄腑鏂囩紪鐮乁TF-8妯″紡~[root@sor-sys zy]# 
    [root@sor-sys zy]# 

    这个时候我们就需要转换编码了,记得使用iconv

    [root@sor-sys zy]# iconv -f UTF-8 -t GB18030 UTF-8.sh -o GB18030.sh
    [root@sor-sys zy]# cat GB18030.sh
    ??我是中文编码UTF-8模式~[root@sor-sys zy]# 
    [root@sor-sys zy]# file GB18030.sh 
    GB18030.sh: Non-ISO extended-ASCII text, with no line terminators
    [root@sor-sys zy]# 

    convmv就是更改文件名编码方式的一个工具。
    比如  
     
            sudo convmv -f gbk -t utf-8 -r –notest  /home  
    就是将/home目录下原来文件名是gbk编码方式的全部改为utf-8格式的。这里 -f  后面为原来的编码方式,-t 后面是要更改为的编码方式, -r 表示这个目录下面的所有文件, –notest 表示马上执行,而不是仅仅测试而已。另外这命令好像要root才能执行,因此要加上 sudo。
    展开全文
  • 如果你需要在Linux中操作windows下的文件,那么你可能会经常遇到文件编码转换的问题。Windows中默认的文件格式是GBK(gb2312),而Linux一般都是UTF-8。 查看编码的方法 方法一:file filenam

    via: http://blog.csdn.net/ariessurfer/article/details/8168012

     

    linux下经常遇到的编码问题

    如果你需要在Linux中操作windows下的文件,那么你可能会经常遇到文件编码转换的问题。Windows中默认的文件格式是GBK(gb2312),而Linux一般都是UTF-8。

    查看编码的方法

    方法一:file filename

    方法二:在Vim中可以直接查看文件编码

    :set fileencoding

    如果你只是想查看其它编码格式的文件或者想解决用Vim查看文件乱码的问题,那么你可以在

    ~/.vimrc 文件中添加以下内容:

    set encoding=utf-8 fileencodings=ucs-bom,utf-8,cp936

    这样,就可以让vim自动识别文件编码(可以自动识别UTF-8或者GBK编码的文件),其实就是依照fileencodings提供的编码列表尝试,如果没有找到合适的编码,就用latin-1(ASCII)编码打开

    文件编码转换

    多平台方法:

    iconv        提供标准的程序和API来进行编码转换;

    convert_encoding.py    基于Python的文本文件转换工具;

    decodeh.py    提供算法和模块来谈测字符的编码;

    linux下文件编码转换:

     

    方法一:

     

    在Vim中直接进行转换文件编码,比如将一个文件转换成utf-8格式

      :set fileencoding=utf-8

     

    或者

     

    11)设置文件集合,即要对哪些文件进行操作,可以使用通配符,比如我通常是对 C/C++ 源程序进行编码转换

     

    :args *.h *.cpp

     

    2)给出要在每个文件上执行的命令,这里是转换编码:

     

    :argdo set fenc=utf-8 | update

     

    方法二:

     

    iconv 转换

     

    5.案例:

     

    假如说我们将windows下的一个UTF-8的文件传到linux环境下,linux环境下的系统编码是GB18030,我们cat的时候就会出现乱码,这个时候就应该想到转码了,下面我们来进行试验:

     

    我们将windows下一个名为UTF-8.sh的文件传到linux系统中,其中UTF-8.sh的内容如下:

     

    我是中文编码UTF-8模式~

     

    而linux系统的系统语言设置为:

     

    [root@sor-sys zy]# cat /etc/sysconfig/i18n 

    LANG=zh_CN.GB18030

    SYSFONT="latarcyrheb-sun16"

    这个时候查看一下文件的内容及编码:

     

    [root@sor-sys zy]# file UTF-8.sh 

    UTF-8.sh: UTF-8 Unicode text, with no line terminators

    [root@sor-sys zy]# cat UTF-8.sh 

    锘挎垜鏄腑鏂囩紪鐮乁TF-8妯″紡~[root@sor-sys zy]# 

    [root@sor-sys zy]# 

     

    这个时候我们就需要转换编码了,记得使用iconv,类似的工具还有convmv

     

    [root@sor-sys zy]# iconv -f UTF-8 -t GB18030 UTF-8.sh -o GB18030.sh

    [root@sor-sys zy]# cat GB18030.sh

    ??我是中文编码UTF-8模式~[root@sor-sys zy]# 

    [root@sor-sys zy]# file GB18030.sh 

    GB18030.sh: Non-ISO extended-ASCII text, with no line terminators

    展开全文
  • 在linux(虚拟机)通过挂载系统将该文件挂载在/mnt/hgfs目录,显示为乱码。但是通过ftp将文件上传到linux相应目录中文显示正常。 2.原因分析 windows下文件名编码方式为GBK。linux(虚拟机)系统通过...
    1.现象描述
    
    在windos环境下有一个含有中文的文件名,比如dataset_省调.scd。
    在linux(虚拟机)下通过挂载系统将该文件挂载在/mnt/hgfs目录下,显示为乱码。但是通过ftp将文件上传到linux相应目录下中文显示正常。

    2.原因分析
    windows下的文件名编码方式为GBK。linux(虚拟机)系统下通过挂载方式共享该文件时,文件名的中文自动自动转换为了UTF-8编码方式,在linux系统下中文编码设置为GBK编码方式,所以显示为乱码。

    3.验证
    使用编码转换工具,将查看“省调”两个字的GBK编码为CA A1 B5 F7,UTF8编码为E7 9C 81 E8 B0 83,显示为”鐪佽皟“。该汉字在linux系1.现象描述
    在windos环境下有一个含有中文的文件名,比如dataset_省调.scd。
    在linux(虚拟机)下通过挂载系统将该文件挂载在/mnt/hgfs目录下,显示为乱码。但是通过ftp将文件上传到linux相应目录下中文显示正常。

    2.原因分析
    windows下的文件名编码方式为GBK。linux(虚拟机)系统下通过挂载方式共享该文件时,文件名的中文自动自动转换为了UTF-8编码方式,在linux系统下中文编码设置为GBK编码方式,所以显示为乱码。

    3.验证
    使用编码转换工具,将查看“省调”两个字的GBK编码为CA A1 B5 F7,UTF8编码为E7 9C 81 E8 B0 83,显示为”鐪佽皟“。该汉字在linux系统下显示正好为上述编码的三个乱码汉字。

    4.问题解决
    可以通过FTP或其它一些同步工具将该文件上传到linux系统下。

    5.知识拓展
    字符(Character)是文字与符号的总称,包括文字、图形符号、数学符号等。一组抽象字符的集合就是字符集(Charset)。
    计算机要处理各种字符,就需要将字符和二进制内码对应起来,这种对应关系就是字符编码(Encoding)。
    制定编码首先要确定字符集,并将字符集内的字符排序,然后和二进制数字对应起来。根据字符集内字符的多少,会确定用几个字节来编码。
    每种编码都限定了一个明确的字符集合,叫做被编码过的字符集(Coded Character Set),这是字符集的另外一个含义。通常所说的字符集大多是这个含义。

    常用的字符集有:ASCII、ISO 8859-1、UCS、Unicode、UTF、汉字编码、ANSI
    下面是转的各种编码方式的详细介绍:
    ASCII:
    American Standard Code for Information Interchange,美国信息交换标准码。
    目前计算机中用得最广泛的字符集及其编码,由美国国家标准局(ANSI)制定。
    它已被国际标准化组织(ISO)定为国际标准,称为ISO 646标准。
    ASCII字符集由控制字符和图形字符组成。
    在计算机的存储单元中,一个ASCII码值占一个字节(8个二进制位),其最高位(b7)用作奇偶校验位。
    所谓奇偶校验,是指在代码传送过程中用来检验是否出现错误的一种方法,一般分奇校验和偶校验两种。
    奇校验规定:正确的代码一个字节中1的个数必须是奇数,若非奇数,则在最高位b7添1。
    偶校验规定:正确的代码一个字节中1的个数必须是偶数,若非偶数,则在最高位b7添1。

    ISO 8859-1:
    ISO 8859,全称ISO/IEC 8859,是国际标准化组织(ISO)及国际电工委员会(IEC)联合制定的一系列8位字符集的标准,现时定义了15个字符集。
    ASCII收录了空格及94个“可印刷字符”,足以给英语使用。
    但是,其他使用拉丁字母的语言(主要是欧洲国家的语言),都有一定数量的变音字母,故可以使用ASCII及控制字符以外的区域来储存及表示。
    除了使用拉丁字母的语言外,使用西里尔字母的东欧语言、希腊语、泰语、现代阿拉伯语、希伯来语等,都可以使用这个形式来储存及表示。
    * ISO 8859-1 (Latin-1) - 西欧语言
    * ISO 8859-2 (Latin-2) - 中欧语言
    * ISO 8859-3 (Latin-3) - 南欧语言。世界语也可用此字符集显示。
    * ISO 8859-4 (Latin-4) - 北欧语言
    * ISO 8859-5 (Cyrillic) - 斯拉夫语言
    * ISO 8859-6 (Arabic) - 阿拉伯语
    * ISO 8859-7 (Greek) - 希腊语
    * ISO 8859-8 (Hebrew) - 希伯来语(视觉顺序)
    * ISO 8859-8-I - 希伯来语(逻辑顺序)
    * ISO 8859-9 (Latin-5 或 Turkish) - 它把Latin-1的冰岛语字母换走,加入土耳其语字母。
    * ISO 8859-10 (Latin-6 或 Nordic) - 北日耳曼语支,用来代替Latin-4。
    * ISO 8859-11 (Thai) - 泰语,从泰国的 TIS620 标准字集演化而来。
    * ISO 8859-13 (Latin-7 或 Baltic Rim) - 波罗的语族
    * ISO 8859-14 (Latin-8 或 Celtic) - 凯尔特语族
    * ISO 8859-15 (Latin-9) - 西欧语言,加入Latin-1欠缺的法语及芬兰语重音字母,以及欧元符号。
    * ISO 8859-16 (Latin-10) - 东南欧语言。主要供罗马尼亚语使用,并加入欧元符号。
    很明显,iso8859-1编码表示的字符范围很窄,无法表示中文字符。
    但是,由于是单字节编码,和计算机最基础的表示单位一致,所以很多时候,仍旧使用iso8859-1编码来表示。
    而且在很多协议上,默认使用该编码。

    UCS:
    通用字符集(Universal Character Set,UCS)是由ISO制定的ISO 10646(或称ISO/IEC 10646)标准所定义的字符编码方式,采用4字节编码。
    UCS包含了已知语言的所有字符。
    除了拉丁语、希腊语、斯拉夫语、希伯来语、阿拉伯语、亚美尼亚语、格鲁吉亚语,还包括中文、日文、韩文这样的象形文字,UCS还包括大量的图形、印刷、数学、科学符号。
    * UCS-2: 与unicode的2byte编码基本一样。
    * UCS-4: 4byte编码, 目前是在UCS-2前加上2个全零的byte。

    Unicode:
    Unicode(统一码、万国码、单一码)是一种在计算机上使用的字符编码。
    它是http://www.unicode.org制定的编码机制, 要将全世界常用文字都函括进去。
    它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。
    1990年开始研发,1994年正式公布。随着计算机工作能力的增强,Unicode也在面世以来的十多年里得到普及。
    但自从unicode2.0开始,unicode采用了与ISO 10646-1相同的字库和字码,ISO也承诺ISO10646将不会给超出0x10FFFF的UCS-4编码赋值,使得两者保持一致。
    Unicode的编码方式与ISO 10646的通用字符集(Universal Character Set,UCS)概念相对应,目前的用于实用的Unicode版本对应于UCS-2,使用16位的编码空间。
    也就是每个字符占用2个字节,基本满足各种语言的使用。实际上目前版本的Unicode尚未填充满这16位编码,保留了大量空间作为特殊使用或将来扩展。

    UTF:
    Unicode 的实现方式不同于编码方式。
    一个字符的Unicode编码是确定的,但是在实际传输过程中,由于不同系统平台的设计不一定一致,以及出于节省空间的目的,对Unicode编码的实现方式有所不同。
    Unicode的实现方式称为Unicode转换格式(Unicode Translation Format,简称为 UTF)。
    * UTF-8: 8bit变长编码,对于大多数常用字符集(ASCII中0~127字符)它只使用单字节,而对其它常用字符(特别是朝鲜和汉语会意文字),它使用3字节。
    * UTF-16: 16bit编码,是变长码,大致相当于20位编码,值在0到0x10FFFF之间,基本上就是unicode编码的实现,与CPU字序有关。


    汉字编码:
    * GB2312字集是简体字集,全称为GB2312(80)字集,共包括国标简体汉字6763个。
    * BIG5字集是台湾繁体字集,共包括国标繁体汉字13053个。
    * GBK字集是简繁字集,包括了GB字集、BIG5字集和一些符号,共包括21003个字符。
    * GB18030是国家制定的一个强制性大字集标准,全称为GB18030-2000,它的推出使汉字集有了一个“大一统”的标准。

    ANSI和Unicode big endia:
    我们在Windows系统中保存文本文件时通常可以选择编码为ANSI、Unicode、Unicode big endian和UTF-8,这里的ANSI和Unicode big endia是什么编码呢?
    ANSI:
    使用2个字节来代表一个字符的各种汉字延伸编码方式,称为ANSI编码。
    在简体中文系统下,ANSI编码代表GB2312编码,在日文操作系统下,ANSI编码代表JIS编码。
    Unicode big endia:
    UTF-8以字节为编码单元,没有字节序的问题。UTF-16以两个字节为编码单元,在解释一个UTF-16文本前,首先要弄清楚每个编码单元的字节序。
    Unicode规范中推荐的标记字节顺序的方法是BOM(即Byte Order Mark)。
    在UCS编码中有一个叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。
    UCS规范建议我们在传输字节流前,先传输字符"ZERO WIDTH NO-BREAK SPACE"。
    这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。
    因此字符"ZERO WIDTH NO-BREAK SPACE"又被称作BOM。
    Windows就是使用BOM来标记文本文件的编码方式的。

    编程语言与编码

    C、C++、Python2内部字符串都是使用当前系统默认编码
    Python3、Java内部字符串用Unicode保存
    Ruby有一个内部变量$KCODE用来表示可识别的多字节字符串的编码,变量值为"EUC" "SJIS" "UTF8" "NONE"之一。
    $KCODE的值为"EUC"时,将假定字符串或正则表达式的编码为EUC-JP。
    同样地,若为"SJIS"时则认定为Shift JIS。若为"UTF8"时则认定为UTF-8。
    若为"NONE"时,将不会识别多字节字符串。
    在向该变量赋值时,只有第1个字节起作用,且不区分大小写字母。
    "e" "E" 代表 "EUC","s" "S" 代表 "SJIS","u" "U" 代表 "UTF8",而"n" "N" 则代表 "NONE"。
    默认值为"NONE"。
    即默认情况下Ruby把字符串当成单字节序列来处理。

    为什么会乱码?

    乱码是个老问题,从上面我们知道,字符在保存时的编码格式如果和要显示的编码格式不一样的话,就会出现乱码问题。
    我们的Web系统,从底层数据库编码、Web应用程序编码到HTML页面编码,如果有一项不一致的话,就会出现乱码。
    所以,解决乱码问题说难也难说简单也简单,关键是让交互系统之间编码一致。

    有没有万金油?

    在如此多种编码和字符集弄的我们眼花缭乱的情况下,我们只需选择一种兼容性最好的编码方式和字符集,让它成为我们程序子系统之间
    交互的编码契约,那么从此恼人的乱码问题即将远离我们而去 -- 这种兼容性最好的编码就是UTF-8!
    毕竟GBK/GB2312是国内的标准,当我们大量使用国外的开源软件时,UTF-8才是编码界最通用的语言。

    下面还有一篇关于编码的文章,转自http://kb.cnblogs.com/a/1540382/

    这是一篇程序员写给程序员的趣味读物。所谓趣味是指可以比较轻松地了解一些原来不清楚的概念,

    增进知识,类似于打RPG游戏的升级。整理这篇文章的动机是两个问题:


    问题一:

    使用Windows记事本的“另存为”,可以在GBK、Unicode、Unicode big endian和UTF-8这几种

    编码方式间相互转换。同样是txt文件,Windows是怎样识别编码方式的呢?


    我很早前就发现Unicode、Unicode bigendian和UTF-8编码的txt文件的开头会多出几个字节,

    分别是FF、FE(Unicode),FE、FF(Unicode bigendian),EF、BB、BF(UTF-8)。但这些

    标记是基于什么标准呢?


    问题二:

    最近在网上看到一个ConvertUTF.c,实现了UTF-32、UTF-16和UTF-8这三种编码方式的相互转换。

    对于Unicode(UCS2)、GBK、UTF-8这些编码方式,我原来就了解。但这个程序让我有些糊涂,想不

    起来UTF-16和UCS2有什么关系。查了查相关资料,总算将这些问题弄清楚了,顺带也了解了一些

    Unicode的细节。写成一篇文章,送给有过类似疑问的朋友。本文在写作时尽量做到通俗易懂,但要

    求读者知道什么是字节,什么是十六进制。


    0、big endian和little endian

    bigendian和littleendian是CPU处理多字节数的不同方式。例如“汉”字的Unicode编码是6C49。

    那么写到文件里时,究竟是将6C写在前面,还是将49写在前面?如果将6C写在前面,就是big endian。

    如果将49写在前面,就是little endian。


    “endian”这个词出自《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)

    敲开还是从小头(Little-Endian)敲开,由此曾发生过六次叛乱,一个皇帝送了命,另一个丢了王位。

    我们一般将endian翻译成“字节序”,将big endian和little endian称作“大尾”和“小尾”。


    1、字符编码、内码,顺带介绍汉字编码

    字符必须编码后才能被计算机处理。计算机使用的缺省编码方式就是计算机的内码。早期的计算机使用

    7位的ASCII编码,为了处理汉字,程序员设计了用于简体中文的GB2312和用于繁体中文的big5。

    GB2312(1980年)一共收录了7445个字符,包括6763个汉字和682个其它符号。汉字区的内码范围高

    字节从B0-F7,低字节从A1-FE,占用的码位是72*94=6768。其中有5个空位是D7FA-D7FE。

    GB2312支持的汉字太少。1995年的汉字扩展规范GBK1.0收录了21886个符号,它分为汉字区和图形符

    号区。汉字区包括21003个字符。

    从ASCII、GB2312到GBK,这些编码方法是向下兼容的,即同一个字符在这些方案中总是有相同的编码,

    后面的标准支持更多的字符。在这些编码中,英文和中文可以统一地处理。区分中文编码的方法是高字

    节的最高位不为0。按照程序员的称呼,GB2312、GBK都属于双字节字符集 (DBCS)。


    2000年的GB18030是取代GBK1.0的正式国家标准。该标准收录了27484个汉字,同时还收录了藏文、

    蒙文、维吾尔文等主要的少数民族文字。从汉字字汇上说,GB18030在GB13000.1的20902个汉字的

    基础上增加了CJK扩展A的6582个汉字(Unicode码0x3400-0x4db5),一共收录了27484个汉字。


    CJK就是中日韩的意思。Unicode为了节省码位,将中日韩三国语言中的文字统一编码。GB13000.1

    就是ISO/IEC 10646-1的中文版,相当于Unicode 1.1。


    GB18030的编码采用单字节、双字节和4字节方案。其中单字节、双字节和GBK是完全兼容的。4字节

    编码的码位就是收录了CJK扩展A的6582个汉字。例如:UCS的0x3400在GB18030中的编码应该是

    8139EF30,UCS的0x3401在GB18030中的编码应该是8139EF31。


    微软提供了GB18030的升级包,但这个升级包只是提供了一套支持CJK扩展A的6582个汉字的新字体:

    新宋体-18030,并不改变内码。Windows 的内码仍然是GBK。


    这里还有一些细节:

    GB2312的原文还是区位码,从区位码到内码,需要在高字节和低字节上分别加上A0。


    对于任何字符编码,编码单元的顺序是由编码方案指定的,与endian无关。例如GBK的编码单元是字

    节,用两个字节表示一个汉字。这两个字节的顺序是固定的,不受CPU字节序的影响。UTF-16的编码

    单元是word(双字节),word之间的顺序是编码方案指定的,word内部的字节排列才会受到endian

    的影响。后面还会介绍UTF-16。


    GB2312的两个字节的最高位都是1。但符合这个条件的码位只有128*128=16384个。所以GBK和

    GB18030的低字节最高位都可能不是1。不过这不影响DBCS字符流的解析:在读取DBCS字符流时,

    只要遇到高位为1的字节,就可以将下两个字节作为一个双字节编码,而不用管低字节的高位是什么。


    2、Unicode、UCS和UTF

    前面提到从ASCII、GB2312、GBK到GB18030的编码方法是向下兼容的。而Unicode只与ASCII兼

    容(更准确地说,是与ISO-8859-1兼容),与GB码不兼容。例如“汉”字的Unicode编码是6C49,

    而GB码是BABA。

    Unicode也是一种字符编码方法,不过它是由国际组织设计,可以容纳全世界所有语言文字的编码

    方案。Unicode的学名是"UniversalMultiple-Octet Coded Character Set",简称为UCS。

    UCS可以看作是"Unicode CharacterSet"的缩写。


    根据维基百科全书(http://zh.wikipedia.org/wiki/)的记载:历史上存在两个试图独立设计

    Unicode的组织,即国际标准化组织(ISO)和一个软件制造商的协会(unicode.org)。ISO开

    发了ISO10646项目,Unicode协会开发了Unicode项目。


    在1991年前后,双方都认识到世界不需要两个不兼容的字符集。于是它们开始合并双方的工作成果,

    并为创立一个单一编码表而协同工作。从Unicode2.0开始,Unicode项目采用了与ISO 10646-1

    相同的字库和字码。


    目前两个项目仍都存在,并独立地公布各自的标准。Unicode协会现在的最新版本是2005年的Unicode

    4.1.0。ISO的最新标准是ISO 10646-3:2003。


    UCS只是规定如何编码,并没有规定如何传输、保存这个编码。例如“汉”字的UCS编码是6C49,我可

    以用4个ascii数字来传输、保存这个编码;也可以用utf-8编码:3个连续的字节E6 B1 89来表示它。

    关键在于通信双方都要认可。UTF-8、UTF-7、UTF-16都是被广泛接受的方案。UTF-8的一个特别的

    好处是它与ISO-8859-1完全兼容。UTF是“UCS Transformation Format”的缩写。


    IETF的RFC2781和RFC3629以RFC的一贯风格,清晰、明快又不失严谨地描述了UTF-16和UTF-8的

    编码方法。我总是记不得IETF是InternetEngineering Task Force的缩写。但IETF负责维护

    的RFC是Internet上一切规范的基础。


    2.1、内码和code page

    目前Windows的内核已经支持Unicode字符集,这样在内核上可以支持全世界所有的语言文字。但是

    由于现有的大量程序和文档都采用了某种特定语言的编码,例如GBK,Windows不可能不支持现有的

    编码,而全部改用Unicode。


    Windows使用代码页(code page)来适应各个国家和地区。code page可以被理解为前面提到的内码。

    GBK对应的code page是CP936。


    微软也为GB18030定义了code page:CP54936。但是由于GB18030有一部分4字节编码,而Windows

    的代码页只支持单字节和双字节编码,所以这个code page是无法真正使用的。


    3、UCS-2、UCS-4、BMP

    UCS有两种格式:UCS-2和UCS-4。顾名思义,UCS-2就是用两个字节编码,UCS-4就是用4个字节

    (实际上只用了31位,最高位必须为0)编码。下面让我们做一些简单的数学游戏:

    UCS-2有2^16=65536个码位,UCS-4有2^31=2147483648个码位。


    UCS-4根据最高位为0的最高字节分成2^7=128个group。每个group再根据次高字节分为256个plane。

    每个plane根据第3个字节分为256行 (rows),每行包含256个cells。当然同一行的cells只是最后

    一个字节不同,其余都相同。


    group 0的plane 0被称作Basic Multilingual Plane, 即BMP。或者说UCS-4中,高两个字节

    为0的码位被称作BMP。


    将UCS-4的BMP去掉前面的两个零字节就得到了UCS-2。在UCS-2的两个字节前加上两个零字节,就得

    到了UCS-4的BMP。而目前的UCS-4规范中还没有任何字符被分配在BMP之外。


    4、UTF编码


    UTF-8就是以8位为单元对UCS进行编码。从UCS-2到UTF-8的编码方式如下:

    UCS-2编码(16进制) UTF-8 字节流(二进制)

    0000 - 007F 0xxxxxxx

    0080 - 07FF 110xxxxx 10xxxxxx

    0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx


    例如“汉”字的Unicode编码是6C49。6C49在0800-FFFF之间,所以肯定要用3字节模板了:

    1110xxxx 10xxxxxx 10xxxxxx。将6C49写成二进制是:0110 110001 001001, 用这个比特流

    依次代替模板中的x,得到:1110011010110001 10001001,即E6 B1 89。


    读者可以用记事本测试一下我们的编码是否正确。需要注意,UltraEdit在打开utf-8编码的文本文

    件时会自动转换为UTF-16,可能产生混淆。你可以在设置中关掉这个选项。更好的工具是Hex Workshop。


    UTF-16以16位为单元对UCS进行编码。对于小于0x10000的UCS码,UTF-16编码就等于UCS码对应

    的16位无符号整数。对于不小于0x10000的UCS码,定义了一个算法。不过由于实际使用的UCS2,

    或者UCS4的BMP必然小于0x10000,所以就目前而言,可以认为UTF-16和UCS-2基本相同。但UCS-2

    只是一个编码方案,UTF-16却要用于实际的传输,所以就不得不考虑字节序的问题。


    5、UTF的字节序和BOM

    UTF-8以字节为编码单元,没有字节序的问题。UTF-16以两个字节为编码单元,在解释一个UTF-16

    文本前,首先要弄清楚每个编码单元的字节序。例如“奎”的Unicode编码是594E,“乙”的Unicode

    编码是4E59。如果我们收到UTF-16字节流“594E”,那么这是“奎”还是“乙”?


    Unicode规范中推荐的标记字节顺序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是

    Byte Order Mark。BOM是一个有点小聪明的想法:

    在UCS编码中有一个叫做"ZERO WIDTH NO-BREAKSPACE"的字符,它的编码是FEFF。而FFFE在UCS

    中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输字符

    "ZERO WIDTH NO-BREAK SPACE"。


    这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流

    是Little-Endian的。因此字符"ZERO WIDTH NO-BREAK SPACE"又被称作BOM。


    UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字符"ZERO WIDTH NO-BREAK SPACE"

    的UTF-8编码是EFBB BF(读者可以用我们前面介绍的编码方法验证一下)。所以如果接收者收到以

    EF BB BF开头的字节流,就知道这是UTF-8编码了。



    Windows就是使用BOM来标记文本文件的编码方式的。


    6、进一步的参考资料

    本文主要参考的资料是 "Short overview of ISO-IEC 10646 and Unicode"

    (http://www.nada.kth.se/i18n/ucs/unicode-iso10646-oview.html)。


    我还找了两篇看上去不错的资料,不过因为我开始的疑问都找到了答案,所以就没有看:


    "Understanding
    Unicode A general introduction to the Unicode Standard"
    (http://scrīpts.sil.org/cms/scrīpts/page.php?site_id=nrsi&item_id=IWS-Chapter04a)

    "Character set encoding basics Understanding character set
    encodings and legacy encodings"
    (http://scrīpts.sil.org/cms/scrīpts/page.php?site_id=nrsi&item_id=IWS-Chapter03)

    我写过UTF-8、UCS-2、GBK相互转换的软件包,包括使用Windows API和不使用Windows API的

    版本。以后有时间的话,我会整理一下放到我的个人主页上(http://fmddlmyy.home4u.china.com)。


    我是想清楚所有问题后才开始写这篇文章的,原以为一会儿就能写好。没想到考虑措辞和查证细节花

    费了很长时间,竟然从下午1:30写到9:00。希望有读者能从中受益。


    附录1 再说说区位码、GB2312、内码和代码页

    有的朋友对文章中这句话还有疑问:

    “GB2312的原文还是区位码,从区位码到内码,需要在高字节和低字节上分别加上A0。”


    我再详细解释一下:


    “GB2312的原文”是指国家1980年的一个标准《中华人民共和国国家标准 信息交换用汉字编码字符集

    基本集 GB2312-80》。这个标准用两个数来编码汉字和中文符号。第一个数称为“区”,第二个数称为

    “位”。所以也称为区位码。1-9区是中文符号,16-55区是一级汉字,56-87区是二级汉字。现在Windows

    也还有区位输入法,例如输入1601得到“啊”。(这个区位输入法可以自动识别16进制的GB2312和10

    进制的区位码,也就是说输入B0A1同样会得到“啊”。)


    内码是指操作系统内部的字符编码。早期操作系统的内码是与语言相关的。现在的Windows在系统内

    部支持Unicode,然后用代码页适应各种语言,“内码”的概念就比较模糊了。微软一般将缺省代码页

    指定的编码说成是内码。


    内码这个词汇,并没有什么官方的定义,代码页也只是微软这个公司的叫法。作为程序员,我们只要

    知道它们是什么东西,没有必要过多地考证这些名词。


    所谓代码页(code page)就是针对一种语言文字的字符编码。例如GBK的code page是CP936,BIG5

    的code page是CP950,GB2312的code page是CP20936。


    Windows中有缺省代码页的概念,即缺省用什么编码来解释字符。例如Windows的记事本打开了一个

    文本文件,里面的内容是字节流:BA、BA、D7、D6。Windows应该去怎么解释它呢?


    是按照Unicode编码解释、还是按照GBK解释、还是按照BIG5解释,还是按照ISO8859-1去解释?如

    果按GBK去解释,就会得到“汉字”两个字。按照其它编码解释,可能找不到对应的字符,也可能找到错

    误的字符。所谓“错误”是指与文本作者的本意不符,这时就产生了乱码。


    答案是Windows按照当前的缺省代码页去解释文本文件里的字节流。缺省代码页可以通过控制面板的

    区域选项设置。记事本的另存为中有一项ANSI,其实就是按照缺省代码页的编码方法保存。


    Windows的内码是Unicode,它在技术上可以同时支持多个代码页。只要文件能说明自己使用什么编

    码,用户又安装了对应的代码页,Windows就能正确显示,例如在HTML文件中就可以指定charset。


    有的HTML文件作者,特别是英文作者,认为世界上所有人都使用英文,在文件中不指定charset。

    如果他使用了0x80-0xff之间的字符,中文Windows又按照缺省的GBK去解释,就会出现乱码。这时

    只要在这个html文件中加上指定charset的语句,例如:

    <meta http-equiv="Content-Type" content="text/html; charset=ISO8859-1">

    如果原作者使用的代码页和ISO8859-1兼容,就不会出现乱码了。


    再说区位码,啊的区位码是1601,写成16进制是0x10,0x01。这和计算机广泛使用的ASCII编码冲突。

    为了兼容00-7f的ASCII编码,我们在区位码的高、低字节上分别加上A0。这样“啊”的编码就成为B0A1。

    我们将加过两个A0的编码也称为GB2312编码,虽然GB2312的原文根本没提到这一点。


    统下显示正好为上述编码的三个乱码汉字。

    4.问题解决
    可以通过FTP或其它一些同步工具将该文件上传到linux系统下。

    5.知识拓展
    字符(Character)是文字与符号的总称,包括文字、图形符号、数学符号等。一组抽象字符的集合就是字符集(Charset)。
    计算机要处理各种字符,就需要将字符和二进制内码对应起来,这种对应关系就是字符编码(Encoding)。
    制定编码首先要确定字符集,并将字符集内的字符排序,然后和二进制数字对应起来。根据字符集内字符的多少,会确定用几个字节来编码。
    每种编码都限定了一个明确的字符集合,叫做被编码过的字符集(Coded Character Set),这是字符集的另外一个含义。通常所说的字符集大多是这个含义。

    常用的字符集有:ASCII、ISO 8859-1、UCS、Unicode、UTF、汉字编码、ANSI
    下面是转的各种编码方式的详细介绍:
    ASCII:
    American Standard Code for Information Interchange,美国信息交换标准码。
    目前计算机中用得最广泛的字符集及其编码,由美国国家标准局(ANSI)制定。
    它已被国际标准化组织(ISO)定为国际标准,称为ISO 646标准。
    ASCII字符集由控制字符和图形字符组成。
    在计算机的存储单元中,一个ASCII码值占一个字节(8个二进制位),其最高位(b7)用作奇偶校验位。
    所谓奇偶校验,是指在代码传送过程中用来检验是否出现错误的一种方法,一般分奇校验和偶校验两种。
    奇校验规定:正确的代码一个字节中1的个数必须是奇数,若非奇数,则在最高位b7添1。
    偶校验规定:正确的代码一个字节中1的个数必须是偶数,若非偶数,则在最高位b7添1。

    ISO 8859-1:
    ISO 8859,全称ISO/IEC 8859,是国际标准化组织(ISO)及国际电工委员会(IEC)联合制定的一系列8位字符集的标准,现时定义了15个字符集。
    ASCII收录了空格及94个“可印刷字符”,足以给英语使用。
    但是,其他使用拉丁字母的语言(主要是欧洲国家的语言),都有一定数量的变音字母,故可以使用ASCII及控制字符以外的区域来储存及表示。
    除了使用拉丁字母的语言外,使用西里尔字母的东欧语言、希腊语、泰语、现代阿拉伯语、希伯来语等,都可以使用这个形式来储存及表示。
    * ISO 8859-1 (Latin-1) - 西欧语言
    * ISO 8859-2 (Latin-2) - 中欧语言
    * ISO 8859-3 (Latin-3) - 南欧语言。世界语也可用此字符集显示。
    * ISO 8859-4 (Latin-4) - 北欧语言
    * ISO 8859-5 (Cyrillic) - 斯拉夫语言
    * ISO 8859-6 (Arabic) - 阿拉伯语
    * ISO 8859-7 (Greek) - 希腊语
    * ISO 8859-8 (Hebrew) - 希伯来语(视觉顺序)
    * ISO 8859-8-I - 希伯来语(逻辑顺序)
    * ISO 8859-9 (Latin-5 或 Turkish) - 它把Latin-1的冰岛语字母换走,加入土耳其语字母。
    * ISO 8859-10 (Latin-6 或 Nordic) - 北日耳曼语支,用来代替Latin-4。
    * ISO 8859-11 (Thai) - 泰语,从泰国的 TIS620 标准字集演化而来。
    * ISO 8859-13 (Latin-7 或 Baltic Rim) - 波罗的语族
    * ISO 8859-14 (Latin-8 或 Celtic) - 凯尔特语族
    * ISO 8859-15 (Latin-9) - 西欧语言,加入Latin-1欠缺的法语及芬兰语重音字母,以及欧元符号。
    * ISO 8859-16 (Latin-10) - 东南欧语言。主要供罗马尼亚语使用,并加入欧元符号。
    很明显,iso8859-1编码表示的字符范围很窄,无法表示中文字符。
    但是,由于是单字节编码,和计算机最基础的表示单位一致,所以很多时候,仍旧使用iso8859-1编码来表示。
    而且在很多协议上,默认使用该编码。

    UCS:
    通用字符集(Universal Character Set,UCS)是由ISO制定的ISO 10646(或称ISO/IEC 10646)标准所定义的字符编码方式,采用4字节编码。
    UCS包含了已知语言的所有字符。
    除了拉丁语、希腊语、斯拉夫语、希伯来语、阿拉伯语、亚美尼亚语、格鲁吉亚语,还包括中文、日文、韩文这样的象形文字,UCS还包括大量的图形、印刷、数学、科学符号。
    * UCS-2: 与unicode的2byte编码基本一样。
    * UCS-4: 4byte编码, 目前是在UCS-2前加上2个全零的byte。

    Unicode:
    Unicode(统一码、万国码、单一码)是一种在计算机上使用的字符编码。
    它是http://www.unicode.org制定的编码机制, 要将全世界常用文字都函括进去。
    它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。
    1990年开始研发,1994年正式公布。随着计算机工作能力的增强,Unicode也在面世以来的十多年里得到普及。
    但自从unicode2.0开始,unicode采用了与ISO 10646-1相同的字库和字码,ISO也承诺ISO10646将不会给超出0x10FFFF的UCS-4编码赋值,使得两者保持一致。
    Unicode的编码方式与ISO 10646的通用字符集(Universal Character Set,UCS)概念相对应,目前的用于实用的Unicode版本对应于UCS-2,使用16位的编码空间。
    也就是每个字符占用2个字节,基本满足各种语言的使用。实际上目前版本的Unicode尚未填充满这16位编码,保留了大量空间作为特殊使用或将来扩展。

    UTF:
    Unicode 的实现方式不同于编码方式。
    一个字符的Unicode编码是确定的,但是在实际传输过程中,由于不同系统平台的设计不一定一致,以及出于节省空间的目的,对Unicode编码的实现方式有所不同。
    Unicode的实现方式称为Unicode转换格式(Unicode Translation Format,简称为 UTF)。
    * UTF-8: 8bit变长编码,对于大多数常用字符集(ASCII中0~127字符)它只使用单字节,而对其它常用字符(特别是朝鲜和汉语会意文字),它使用3字节。
    * UTF-16: 16bit编码,是变长码,大致相当于20位编码,值在0到0x10FFFF之间,基本上就是unicode编码的实现,与CPU字序有关。


    汉字编码:
    * GB2312字集是简体字集,全称为GB2312(80)字集,共包括国标简体汉字6763个。
    * BIG5字集是台湾繁体字集,共包括国标繁体汉字13053个。
    * GBK字集是简繁字集,包括了GB字集、BIG5字集和一些符号,共包括21003个字符。
    * GB18030是国家制定的一个强制性大字集标准,全称为GB18030-2000,它的推出使汉字集有了一个“大一统”的标准。

    ANSI和Unicode big endia:
    我们在Windows系统中保存文本文件时通常可以选择编码为ANSI、Unicode、Unicode big endian和UTF-8,这里的ANSI和Unicode big endia是什么编码呢?
    ANSI:
    使用2个字节来代表一个字符的各种汉字延伸编码方式,称为ANSI编码。
    在简体中文系统下,ANSI编码代表GB2312编码,在日文操作系统下,ANSI编码代表JIS编码。
    Unicode big endia:
    UTF-8以字节为编码单元,没有字节序的问题。UTF-16以两个字节为编码单元,在解释一个UTF-16文本前,首先要弄清楚每个编码单元的字节序。
    Unicode规范中推荐的标记字节顺序的方法是BOM(即Byte Order Mark)。
    在UCS编码中有一个叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。
    UCS规范建议我们在传输字节流前,先传输字符"ZERO WIDTH NO-BREAK SPACE"。
    这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。
    因此字符"ZERO WIDTH NO-BREAK SPACE"又被称作BOM。
    Windows就是使用BOM来标记文本文件的编码方式的。

    编程语言与编码

    C、C++、Python2内部字符串都是使用当前系统默认编码
    Python3、Java内部字符串用Unicode保存
    Ruby有一个内部变量$KCODE用来表示可识别的多字节字符串的编码,变量值为"EUC" "SJIS" "UTF8" "NONE"之一。
    $KCODE的值为"EUC"时,将假定字符串或正则表达式的编码为EUC-JP。
    同样地,若为"SJIS"时则认定为Shift JIS。若为"UTF8"时则认定为UTF-8。
    若为"NONE"时,将不会识别多字节字符串。
    在向该变量赋值时,只有第1个字节起作用,且不区分大小写字母。
    "e" "E" 代表 "EUC","s" "S" 代表 "SJIS","u" "U" 代表 "UTF8",而"n" "N" 则代表 "NONE"。
    默认值为"NONE"。
    即默认情况下Ruby把字符串当成单字节序列来处理。

    为什么会乱码?

    乱码是个老问题,从上面我们知道,字符在保存时的编码格式如果和要显示的编码格式不一样的话,就会出现乱码问题。
    我们的Web系统,从底层数据库编码、Web应用程序编码到HTML页面编码,如果有一项不一致的话,就会出现乱码。
    所以,解决乱码问题说难也难说简单也简单,关键是让交互系统之间编码一致。

    有没有万金油?

    在如此多种编码和字符集弄的我们眼花缭乱的情况下,我们只需选择一种兼容性最好的编码方式和字符集,让它成为我们程序子系统之间
    交互的编码契约,那么从此恼人的乱码问题即将远离我们而去 -- 这种兼容性最好的编码就是UTF-8!
    毕竟GBK/GB2312是国内的标准,当我们大量使用国外的开源软件时,UTF-8才是编码界最通用的语言。

    下面还有一篇关于编码的文章,转自http://kb.cnblogs.com/a/1540382/

    这是一篇程序员写给程序员的趣味读物。所谓趣味是指可以比较轻松地了解一些原来不清楚的概念,

    增进知识,类似于打RPG游戏的升级。整理这篇文章的动机是两个问题:


    问题一:

    使用Windows记事本的“另存为”,可以在GBK、Unicode、Unicode big endian和UTF-8这几种

    编码方式间相互转换。同样是txt文件,Windows是怎样识别编码方式的呢?


    我很早前就发现Unicode、Unicode bigendian和UTF-8编码的txt文件的开头会多出几个字节,

    分别是FF、FE(Unicode),FE、FF(Unicode bigendian),EF、BB、BF(UTF-8)。但这些

    标记是基于什么标准呢?


    问题二:

    最近在网上看到一个ConvertUTF.c,实现了UTF-32、UTF-16和UTF-8这三种编码方式的相互转换。

    对于Unicode(UCS2)、GBK、UTF-8这些编码方式,我原来就了解。但这个程序让我有些糊涂,想不

    起来UTF-16和UCS2有什么关系。查了查相关资料,总算将这些问题弄清楚了,顺带也了解了一些

    Unicode的细节。写成一篇文章,送给有过类似疑问的朋友。本文在写作时尽量做到通俗易懂,但要

    求读者知道什么是字节,什么是十六进制。


    0、big endian和little endian

    bigendian和littleendian是CPU处理多字节数的不同方式。例如“汉”字的Unicode编码是6C49。

    那么写到文件里时,究竟是将6C写在前面,还是将49写在前面?如果将6C写在前面,就是big endian。

    如果将49写在前面,就是little endian。


    “endian”这个词出自《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)

    敲开还是从小头(Little-Endian)敲开,由此曾发生过六次叛乱,一个皇帝送了命,另一个丢了王位。

    我们一般将endian翻译成“字节序”,将big endian和little endian称作“大尾”和“小尾”。


    1、字符编码、内码,顺带介绍汉字编码

    字符必须编码后才能被计算机处理。计算机使用的缺省编码方式就是计算机的内码。早期的计算机使用

    7位的ASCII编码,为了处理汉字,程序员设计了用于简体中文的GB2312和用于繁体中文的big5。

    GB2312(1980年)一共收录了7445个字符,包括6763个汉字和682个其它符号。汉字区的内码范围高

    字节从B0-F7,低字节从A1-FE,占用的码位是72*94=6768。其中有5个空位是D7FA-D7FE。

    GB2312支持的汉字太少。1995年的汉字扩展规范GBK1.0收录了21886个符号,它分为汉字区和图形符

    号区。汉字区包括21003个字符。

    从ASCII、GB2312到GBK,这些编码方法是向下兼容的,即同一个字符在这些方案中总是有相同的编码,

    后面的标准支持更多的字符。在这些编码中,英文和中文可以统一地处理。区分中文编码的方法是高字

    节的最高位不为0。按照程序员的称呼,GB2312、GBK都属于双字节字符集 (DBCS)。


    2000年的GB18030是取代GBK1.0的正式国家标准。该标准收录了27484个汉字,同时还收录了藏文、

    蒙文、维吾尔文等主要的少数民族文字。从汉字字汇上说,GB18030在GB13000.1的20902个汉字的

    基础上增加了CJK扩展A的6582个汉字(Unicode码0x3400-0x4db5),一共收录了27484个汉字。


    CJK就是中日韩的意思。Unicode为了节省码位,将中日韩三国语言中的文字统一编码。GB13000.1

    就是ISO/IEC 10646-1的中文版,相当于Unicode 1.1。


    GB18030的编码采用单字节、双字节和4字节方案。其中单字节、双字节和GBK是完全兼容的。4字节

    编码的码位就是收录了CJK扩展A的6582个汉字。例如:UCS的0x3400在GB18030中的编码应该是

    8139EF30,UCS的0x3401在GB18030中的编码应该是8139EF31。


    微软提供了GB18030的升级包,但这个升级包只是提供了一套支持CJK扩展A的6582个汉字的新字体:

    新宋体-18030,并不改变内码。Windows 的内码仍然是GBK。


    这里还有一些细节:

    GB2312的原文还是区位码,从区位码到内码,需要在高字节和低字节上分别加上A0。


    对于任何字符编码,编码单元的顺序是由编码方案指定的,与endian无关。例如GBK的编码单元是字

    节,用两个字节表示一个汉字。这两个字节的顺序是固定的,不受CPU字节序的影响。UTF-16的编码

    单元是word(双字节),word之间的顺序是编码方案指定的,word内部的字节排列才会受到endian

    的影响。后面还会介绍UTF-16。


    GB2312的两个字节的最高位都是1。但符合这个条件的码位只有128*128=16384个。所以GBK和

    GB18030的低字节最高位都可能不是1。不过这不影响DBCS字符流的解析:在读取DBCS字符流时,

    只要遇到高位为1的字节,就可以将下两个字节作为一个双字节编码,而不用管低字节的高位是什么。


    2、Unicode、UCS和UTF

    前面提到从ASCII、GB2312、GBK到GB18030的编码方法是向下兼容的。而Unicode只与ASCII兼

    容(更准确地说,是与ISO-8859-1兼容),与GB码不兼容。例如“汉”字的Unicode编码是6C49,

    而GB码是BABA。

    Unicode也是一种字符编码方法,不过它是由国际组织设计,可以容纳全世界所有语言文字的编码

    方案。Unicode的学名是"UniversalMultiple-Octet Coded Character Set",简称为UCS。

    UCS可以看作是"Unicode CharacterSet"的缩写。


    根据维基百科全书(http://zh.wikipedia.org/wiki/)的记载:历史上存在两个试图独立设计

    Unicode的组织,即国际标准化组织(ISO)和一个软件制造商的协会(unicode.org)。ISO开

    发了ISO10646项目,Unicode协会开发了Unicode项目。


    在1991年前后,双方都认识到世界不需要两个不兼容的字符集。于是它们开始合并双方的工作成果,

    并为创立一个单一编码表而协同工作。从Unicode2.0开始,Unicode项目采用了与ISO 10646-1

    相同的字库和字码。


    目前两个项目仍都存在,并独立地公布各自的标准。Unicode协会现在的最新版本是2005年的Unicode

    4.1.0。ISO的最新标准是ISO 10646-3:2003。


    UCS只是规定如何编码,并没有规定如何传输、保存这个编码。例如“汉”字的UCS编码是6C49,我可

    以用4个ascii数字来传输、保存这个编码;也可以用utf-8编码:3个连续的字节E6 B1 89来表示它。

    关键在于通信双方都要认可。UTF-8、UTF-7、UTF-16都是被广泛接受的方案。UTF-8的一个特别的

    好处是它与ISO-8859-1完全兼容。UTF是“UCS Transformation Format”的缩写。


    IETF的RFC2781和RFC3629以RFC的一贯风格,清晰、明快又不失严谨地描述了UTF-16和UTF-8的

    编码方法。我总是记不得IETF是InternetEngineering Task Force的缩写。但IETF负责维护

    的RFC是Internet上一切规范的基础。


    2.1、内码和code page

    目前Windows的内核已经支持Unicode字符集,这样在内核上可以支持全世界所有的语言文字。但是

    由于现有的大量程序和文档都采用了某种特定语言的编码,例如GBK,Windows不可能不支持现有的

    编码,而全部改用Unicode。


    Windows使用代码页(code page)来适应各个国家和地区。code page可以被理解为前面提到的内码。

    GBK对应的code page是CP936。


    微软也为GB18030定义了code page:CP54936。但是由于GB18030有一部分4字节编码,而Windows

    的代码页只支持单字节和双字节编码,所以这个code page是无法真正使用的。


    3、UCS-2、UCS-4、BMP

    UCS有两种格式:UCS-2和UCS-4。顾名思义,UCS-2就是用两个字节编码,UCS-4就是用4个字节

    (实际上只用了31位,最高位必须为0)编码。下面让我们做一些简单的数学游戏:

    UCS-2有2^16=65536个码位,UCS-4有2^31=2147483648个码位。


    UCS-4根据最高位为0的最高字节分成2^7=128个group。每个group再根据次高字节分为256个plane。

    每个plane根据第3个字节分为256行 (rows),每行包含256个cells。当然同一行的cells只是最后

    一个字节不同,其余都相同。


    group 0的plane 0被称作Basic Multilingual Plane, 即BMP。或者说UCS-4中,高两个字节

    为0的码位被称作BMP。


    将UCS-4的BMP去掉前面的两个零字节就得到了UCS-2。在UCS-2的两个字节前加上两个零字节,就得

    到了UCS-4的BMP。而目前的UCS-4规范中还没有任何字符被分配在BMP之外。


    4、UTF编码


    UTF-8就是以8位为单元对UCS进行编码。从UCS-2到UTF-8的编码方式如下:

    UCS-2编码(16进制) UTF-8 字节流(二进制)

    0000 - 007F 0xxxxxxx

    0080 - 07FF 110xxxxx 10xxxxxx

    0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx


    例如“汉”字的Unicode编码是6C49。6C49在0800-FFFF之间,所以肯定要用3字节模板了:

    1110xxxx 10xxxxxx 10xxxxxx。将6C49写成二进制是:0110 110001 001001, 用这个比特流

    依次代替模板中的x,得到:1110011010110001 10001001,即E6 B1 89。


    读者可以用记事本测试一下我们的编码是否正确。需要注意,UltraEdit在打开utf-8编码的文本文

    件时会自动转换为UTF-16,可能产生混淆。你可以在设置中关掉这个选项。更好的工具是Hex Workshop。


    UTF-16以16位为单元对UCS进行编码。对于小于0x10000的UCS码,UTF-16编码就等于UCS码对应

    的16位无符号整数。对于不小于0x10000的UCS码,定义了一个算法。不过由于实际使用的UCS2,

    或者UCS4的BMP必然小于0x10000,所以就目前而言,可以认为UTF-16和UCS-2基本相同。但UCS-2

    只是一个编码方案,UTF-16却要用于实际的传输,所以就不得不考虑字节序的问题。


    5、UTF的字节序和BOM

    UTF-8以字节为编码单元,没有字节序的问题。UTF-16以两个字节为编码单元,在解释一个UTF-16

    文本前,首先要弄清楚每个编码单元的字节序。例如“奎”的Unicode编码是594E,“乙”的Unicode

    编码是4E59。如果我们收到UTF-16字节流“594E”,那么这是“奎”还是“乙”?


    Unicode规范中推荐的标记字节顺序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是

    Byte Order Mark。BOM是一个有点小聪明的想法:

    在UCS编码中有一个叫做"ZERO WIDTH NO-BREAKSPACE"的字符,它的编码是FEFF。而FFFE在UCS

    中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输字符

    "ZERO WIDTH NO-BREAK SPACE"。


    这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流

    是Little-Endian的。因此字符"ZERO WIDTH NO-BREAK SPACE"又被称作BOM。


    UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字符"ZERO WIDTH NO-BREAK SPACE"

    的UTF-8编码是EFBB BF(读者可以用我们前面介绍的编码方法验证一下)。所以如果接收者收到以

    EF BB BF开头的字节流,就知道这是UTF-8编码了。



    Windows就是使用BOM来标记文本文件的编码方式的。


    6、进一步的参考资料

    本文主要参考的资料是 "Short overview of ISO-IEC 10646 and Unicode"

    (http://www.nada.kth.se/i18n/ucs/unicode-iso10646-oview.html)。


    我还找了两篇看上去不错的资料,不过因为我开始的疑问都找到了答案,所以就没有看:


    "Understanding
    Unicode A general introduction to the Unicode Standard"
    (http://scrīpts.sil.org/cms/scrīpts/page.php?site_id=nrsi&item_id=IWS-Chapter04a)

    "Character set encoding basics Understanding character set
    encodings and legacy encodings"
    (http://scrīpts.sil.org/cms/scrīpts/page.php?site_id=nrsi&item_id=IWS-Chapter03)

    我写过UTF-8、UCS-2、GBK相互转换的软件包,包括使用Windows API和不使用Windows API的

    版本。以后有时间的话,我会整理一下放到我的个人主页上(http://fmddlmyy.home4u.china.com)。


    我是想清楚所有问题后才开始写这篇文章的,原以为一会儿就能写好。没想到考虑措辞和查证细节花

    费了很长时间,竟然从下午1:30写到9:00。希望有读者能从中受益。


    附录1 再说说区位码、GB2312、内码和代码页

    有的朋友对文章中这句话还有疑问:

    “GB2312的原文还是区位码,从区位码到内码,需要在高字节和低字节上分别加上A0。”


    我再详细解释一下:


    “GB2312的原文”是指国家1980年的一个标准《中华人民共和国国家标准 信息交换用汉字编码字符集

    基本集 GB2312-80》。这个标准用两个数来编码汉字和中文符号。第一个数称为“区”,第二个数称为

    “位”。所以也称为区位码。1-9区是中文符号,16-55区是一级汉字,56-87区是二级汉字。现在Windows

    也还有区位输入法,例如输入1601得到“啊”。(这个区位输入法可以自动识别16进制的GB2312和10

    进制的区位码,也就是说输入B0A1同样会得到“啊”。)


    内码是指操作系统内部的字符编码。早期操作系统的内码是与语言相关的。现在的Windows在系统内

    部支持Unicode,然后用代码页适应各种语言,“内码”的概念就比较模糊了。微软一般将缺省代码页

    指定的编码说成是内码。


    内码这个词汇,并没有什么官方的定义,代码页也只是微软这个公司的叫法。作为程序员,我们只要

    知道它们是什么东西,没有必要过多地考证这些名词。


    所谓代码页(code page)就是针对一种语言文字的字符编码。例如GBK的code page是CP936,BIG5

    的code page是CP950,GB2312的code page是CP20936。


    Windows中有缺省代码页的概念,即缺省用什么编码来解释字符。例如Windows的记事本打开了一个

    文本文件,里面的内容是字节流:BA、BA、D7、D6。Windows应该去怎么解释它呢?


    是按照Unicode编码解释、还是按照GBK解释、还是按照BIG5解释,还是按照ISO8859-1去解释?如

    果按GBK去解释,就会得到“汉字”两个字。按照其它编码解释,可能找不到对应的字符,也可能找到错

    误的字符。所谓“错误”是指与文本作者的本意不符,这时就产生了乱码。


    答案是Windows按照当前的缺省代码页去解释文本文件里的字节流。缺省代码页可以通过控制面板的

    区域选项设置。记事本的另存为中有一项ANSI,其实就是按照缺省代码页的编码方法保存。


    Windows的内码是Unicode,它在技术上可以同时支持多个代码页。只要文件能说明自己使用什么编

    码,用户又安装了对应的代码页,Windows就能正确显示,例如在HTML文件中就可以指定charset。


    有的HTML文件作者,特别是英文作者,认为世界上所有人都使用英文,在文件中不指定charset。

    如果他使用了0x80-0xff之间的字符,中文Windows又按照缺省的GBK去解释,就会出现乱码。这时

    只要在这个html文件中加上指定charset的语句,例如:

    <meta http-equiv="Content-Type" content="text/html; charset=ISO8859-1">

    如果原作者使用的代码页和ISO8859-1兼容,就不会出现乱码了。


    再说区位码,啊的区位码是1601,写成16进制是0x10,0x01。这和计算机广泛使用的ASCII编码冲突。

    为了兼容00-7f的ASCII编码,我们在区位码的高、低字节上分别加上A0。这样“啊”的编码就成为B0A1。

    我们将加过两个A0的编码也称为GB2312编码,虽然GB2312的原文根本没提到这一点。


    展开全文
  • 安装 convmv 这个软件. convmv -f 源编码 -t 新编码 [选项] 文件名 ...--notest 真正进行操作,请注意默认情况是不对文件进行真实操作的,而只是试验。 --list 显示所有支持的编码 --unescap 可以做一下转义,比
  • windows上使用ftp上传文件到Linux上,中文名称在Linux系统中显示为乱码。虽然将Linux的env设置了LANG=en_US.UTF-8,并且本地的Shell客户端编码也设置成UTF-8,但在Shell中(或通过http访问),仍是乱码……原因在于...
  • 问题出压缩和解压的时候对文件名的编码不一致所致 解决方法:linux下用7z压缩文件,windows下就不会乱码了,用tar和zip,rar等等都不行
  • 当我把中文文件名文件cp到windows的fat32盘后,重起进入windows后发现文件名全是乱码。       首先google,baidu了,发现都推荐用convmv,这个工具是用perl编写的,确实非常好用的工具,不过我这里它不...
  • 在JAVA中生成文件,文件名生成在windows下就正常,但是在linux下生成就乱码。 解决方式 代码中文件名用这样的方式转换 String remoteFileName = new String(sendModel.getString("fileName").getBytes("GBK"), ...
  • Linux下中文显示乱码是因为Linux中使用的是UTF-8编码 WINDOWS使用的是GBK编码 可以在LINUX中使用convmv工具来对文件名进行转码 当然如果文件名转码为UTF-8后 在WINDWOS资源管理器中使用FTP进行查看时就会乱码 可以把...
  • windows文件名正常,但部署linux下文件名却出现乱码 搞了一个晚上,知道是编码的问题,网上查到的大致有两种解决方面(好像都不行):...这种方法在window下支持中文了,但在linux下还是会乱码。<br /
  • 在windows文件名正常,但部署linux下文件名却出现乱码搞了一个晚上,知道是编码的问题,网上查到的大致有两种解决方面(好像都不行):1、修改java.util.zip下对应的类。这个方法改了太麻烦了,而且ant包中的已经...
  • 程序文件是在windows下创建的,或是在windows压缩,然后上传到linux 解压的,或者直接上传的,Windows 的文件名中文编码默认为GBK,压缩或者上传后,文件名还会是GBK编码,虽然ftp或者其它查看工具显示中 文,但...
  • windows上使用ftp上传文件到Linux上,中文名称在Linux系统中显示为乱码。虽然将Linux的env设置了LANG=en_US.UTF-8,并且本地的Shell客户端编码也设置成UTF-8,但在Shell中(或通过http访问),仍是乱码…… 原因...
  • 说明:在Linux下编码为utf-8,在windows下位GBK 1. 2. 3. 4. 5. 6. 7. 8. 转载于:https://www.cnblogs.com/gaoguofeng/p/6406531.html
  • 解决linux下中文文件名显示乱码问题

    万次阅读 2018-03-06 18:35:39
    windows上使用ftp上传文件到Linux上,中文名称在Linux系统中显示为乱码。虽然将Linux的env设置了LANG=en_US.UTF-8,并且本地的Shell客户端编码也设置成UTF-8,但在Shell中(或通过http访问),仍是乱码…… 原因...
  • linux下java读取文件名乱码

    千次阅读 2016-07-18 17:50:19
    linux下文件名乱码的原因主要是编码问题造成的。 一般在Windows机器上生成的文件名为GBK,通过ftp、CVS等方式传输到linux上,与linux的系统编码UTF-8不相符,这样就造成读取的文件名乱码,从而程序异常。 解决...
  • Linux下文件名乱码的解决方法

    万次阅读 2012-02-24 22:31:19
    文件是在Windows下创建的,而Windows文件名中文编码默认GBK,Linux中默认文件名编码为UTF-8,编码不一致导致了文件名乱码的问题,解决这个问题需要对文件名进行转码,这个工具就是convmv。 SYNOPSIS: con
  • 文件是在WIndows 创建的,Windows文件名中文编码默认为GBK,而Linux中默认文件名编码为UTF8,由于编码不一致所以导致了文件名乱码的问题,解决这个问题需要对文件名进行转码。文件名转码工具convmv没安装的话用yum...

空空如也

空空如也

1 2 3 4 5 ... 12
收藏数 227
精华内容 90
关键字:

windows文件名在linux下乱码

linux 订阅