字符集、字符编码、文件类型的理解

字符集:字符集就是许多字符的一个集合,例如:ascii码就是所有英文字符和各种符号的一个集合,gbk就是中文所要用到的字符的一个集合。

字符编码:将字符集编码成指定集合的某一对象(如:比特、电脉冲),以便文本在计算机种欧冠存储和通过通信网络传递。对程序员来说,就是将字符编码成二进制存储或在网络传递。

区别和联系:每一种字符集都有一张不同的码表,这张表与字符与数字一一对应,当存储字符时,只需要查找码表,找到该字符对应的数字,然后该数字就能被转换成二进制被计算机识别了。常见的字符集有ascii、gbk、unicode,这三种字符集对应有三张表,其中gbk和unicode包含ascii这张表,在英文字符的对应关系上是一致的,所以乱码问题常出现在中文字符而不是英文字符。当找到字符对应的数字时,ascii和gbk是直接将数字转换成二进制,而unicode会将数字经过不同的处理转换成二进制,狭义上说,字符编码就是将字符对应的数字转换成二进制的方式。ascii、gbk字符集转换成二进制不需要特殊处理,所以编码方式也叫做ascii和gbk编码,而unicode转换成二进制的方式有很多,包括utf8、utf16、utf32编码。

文件格式理解:
dos格式的文件以'CR/LF'做终结符
unix格式的文件以'LF'做终结符
mac格式的文件以'CR'做终结符
是指电脑为了存储信息而使用的对信息的特殊编码方式,是用于识别内部储存的资料。
除此之外,比如有的储存图片,有的储存文字信息。每一类信息,都可以一种或多种文件格式保存在电脑存储中。每一种文件格式通常会有一种或多种扩展名可以用来识别,但也可能没有扩展名。扩展名可以帮助应用程序识别的文件格式。

字符集编码的发展:
1、单字节
计算机开始产生时只支持ascii,传入欧洲后对ascii码进行扩展,根据每个国家的地区形成了许多标准,如iso-8859-1、iso-8859-2、iso-8859-3.
2、双字节
计算机传入亚洲,亚洲国家的字符更多,一个字节最多表示256个字符,所以亚洲的国家需要两个字节表示所有的字符,后根据不同地区对ascii进行扩展形成自己的标准,比如中国gb2312和gbk,其中gbk是对gb2312的扩展,包含了更多的汉字,gbk码表包含gb2312。ansi编码是对两字节本地化编码的一个统称,再简化中文系统下,ansi就代表gb2312编码,在日文系统下ansi就代表jis编码。
ansi编码:各个国家和地区所独立指定的既兼容ascii又互相之间不完全兼容的字符,微软统称为ansi编码。(ansi:american national standards institute,美国国家标准协议)
ansi并不是某一种特定的字符编码,而是在不同的系统中,ansi表示不同的编码。比如:你的美国同事的系统中ansi编码其实是ascii编码(ascii编码不能表示汉字,所以汉字为乱码),而你的系统中(“汉字”正常显示)ansi编码其实是gbk编码,而韩文系统中(韩文正常实现)ansi编码其实是euc-kr编码。

windows系统是如何区分ansi背后的真实编码的呢?
微软用一个叫windows code pages(在命令行下执行chcp命令可以查看当前code page的值)的值来判断系统默认编码,iru简体中文的code page值为936(他表示gbk编码,win95之前表示gb2312,详见:microsoft windows's code page 936),繁体中文的code page 值为936(表示big-5编码)。在命令提示符向下,我们可以通过chcp命令来修改当前中欧高端的active code page,从而来改变ansi编码,但这种方式只在当前终端起作用。想要修改系统默认的ansi编码,我们可以通过修改系统区域来实现(控制面板=>时钟、语言和地区=>区域和语言=>管理=>更改系统区域设置……)

linux是如何区分ansi编码的底层编码?
linux的local命令是lc_all就是ansi的真实编码,可以痛殴该国修改这个变量来修改真实编码,如export lc_all=zh_ch.gbk

3、多字节(unicode字符集)
由于不同的国家有着不通的编码标准,在互联网时代对跨语言的文本信息转换不是很方便。所以unicode字符集将世界上各种语言的每个字符定义一个唯一的编码,其中ascii这个鼻祖仍然不变,但是中文字符对应的编码与gbk不同。
(1)、utf-8
是一种变长字符编码,被定义为将编码值为1至4个字节,具体取决于字符在unicode字符集所对应的码值的大小。
下表为unicode至对应的utf8需要的字节数量。
(2)、utf-16
utf-16使用2个字节或者4个字节来存储。
1、对于unicode编号范围在0~ffff之间的字符,utf-16使用两个字节存储,并且直接存储unicode编号,不用进行编码转换,这跟utf-32非常类似。
2、对于unicode编号范围在10000~10ffff之间的字符,utf-16使用四个字节存储。
3、utf-32
utf-32是固定长度的编码,始终占用4个字节,足以容纳所有的unicode字符,所以直接存储unicode编号即可,不需要任何编码转换。浪费了空间,提高了效率。
4、utf bom
utf-16,utf-32都是多个字节表示一个字符,就存在大小端的问题。bom(byte order mark)字节序(字节顺序的标识),其实就是用大段(BE)还是小端(LE)。utf16、utf32又可以继续细分成打断存储和小段存储。
utf-16be,其后后缀是be即big-endian,是utf16的大端存储。utf-16le,其后缀是le即little-endian,是utf8的小端存储。
utf在文件中存储。utf格式在文件中总有固定文件头:

什么是大端和小端?
所谓的大端模式,就是高位字节排放在内存的低地址段,低位字节排放在内存的高地址端。
所谓的小端模式,就是地位字节排放在内存的低地址段,高位字节排放在内存的高地址端。
大端和小端没有谁优谁劣,各自优势便是对方劣势:
小端模式:强制转换数据不需要调整字节内容,1、2、4字节的存储方式不一样。
大端模式:符号位的判定固定为低一个字节,容易判断正负。
为什么会有大小端模式之分呢?
这是因为在计算机中,我们以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。但是在c语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如和将多个字节安排的问题。因此就导致了大端存储模式还是小端存储模式。例如一个16bit的short型x,在内存中的地址为0x0010,x的值为0x1122,那么0x11位高字节,0x22位低字节。对于大端模式,就将0x11放在低地址,即0x0010中,0x22放在高地址中,即0x0010中。小端模式,刚好相反。我们常用的x86结构是小端模式,而keil c51则为大端模式。很多的arm,dsp都为小端模式。有些arm处理器还可以由硬件来选择是大端模式还是小端模式。

如何判断机器的字节序?
一般都是通过union来测试的,下面这段代码可以用来测试以下你的编译器是大端模式还是小端模式:
#include <stdio.h>
int main (void)
{
    union
    {
        short i;
        char a[2];
    }u;
    u.a[0] = 0x11;
    u.a[1] = 0x22;
    printf("0x%x",u.i); //0x2211为小端 0x1122为大端
    return 0;
}
输入结果:
0x2211

不同编码方式的对比分析:
存储空间对比:gbk编码:ascii编码占用1个字节,汉字占用2字节。unicode字符集中utf8编码:ascii码占用1字节,汉字占用3字节。utf16:汉字和ascii码都占用2字节。utf32:汉字和ascii码都占用4字节。所以不管汉字和ascii码的比例多少,gbk编码都是最节省空间。当汉字较多utf16比utf8节省空哦关键。当ascii码过多则utf8更节省空间。utf32不管怎样都是最浪费空间的。
gbk和unicode对比:gbk是国人自己的标准,在变成中不能够使用其他国家的字符,需要单独的gbk码表才能解码,当访问gbk编码的网页时,需要有单独的中文语言包支持。unicode则是一种国际化的方式,全世界使用一张码表,你能够使用其他国家的字符,也能解码其他国家的字符,全世界人民都直接访问unicode编码的网页。
utf-8和utf-16对比:utf-8没有字节序的概念,不用考虑大小端问题,特别适合用于字符串的网络传输。utf-8属于变字节存储,对ascii码来说没有区别,对汉字来说一个汉字要占3个char,所以不能在通过字符数组的下表来操作汉字。utf-16由于ascii码也是2个字节存储,可以将其于汉字进行同一,用wchar_t来进行存储,一个wchar能够存储一个汉字或字符,能够方便的通过下标来进行字符操作。但是wchar_t在windows和linux没有进行同一,wchar_t在windows中占2字节,wchar_在linux中占用4个字节,所以跨平台会有一定问题。

乱码出现的原因分析及避免:
1、用一种编辑器打开某个文件出现乱码:
原因:保存文件的字符编码和打开文件的字符编码不兼容,例如,保存文件的编码以gbk进行保存,而打开文件用utf8打开就会出现乱码。因为gbk和unicode需要查找不同的表,如果文件编辑器按照utf8的方式解码查找unicode表就会出现乱码。以utf8保存的文件以utf16打开可能也会出现蓝马,因为虽然都是查找一张表但是对有原文件的读取按照utf16的格式进行解码。
解决方式:linux下用file -i查看保存文件的编码方式,编辑器用同样的编码方式进行打开;也可以用命令iconv将文件转换成能够正确打开的编码方式。windows下直接用nodepade进行打开选择能够解码的方式。如果文件为二进制文件(不能被某一编码所识别)则不论以何种方式打开都会出现乱码,可以用base64编码将二进制文件可视化成字符串进行打开。
总结:猜想一个文本编辑器打开一个文件的大概过程是,读取二进制数据,通过二进制数据的特殊格式如bom,能够知道该二进制数据的编码方式,然后按照特定的编码方式通过查找特定的码表来获取字符,然后显示到文件编辑器当中。所以一个成熟的编辑器打开一个文件时,它应该能够自己以特定的编码方式进行打开。注意:当打开文件是一个乱码文件时,如果你以改变吗将这个乱码保存了,那么这个乱码文件将会永久的乱码,不论哪种编码都不能使其恢复正常。

2、可执行程序将字符输出到终端或者文件当中出现乱码。
原因:可执行文件的字符编码方式与输出终端或文件打开的编码方式不一致。
解决办法:
(1)、控制输出程序中字符的编码
在linux系统和windows中用gcc进行编码实验得:直接对源文件进行编译时,编译的可执行程序的字符编码格式与源文件的字符编码格式一致。例如元年文件保存编码格式为gbk,编译的可执行程序格式也是gbk,源文件保存编码格式utf8,编译执行程序字符格式也是utf8,往终端输出是也是utf8格式。源文件只能是gbk和utf8两种形式才能编译通过。
通过编码选项控制可执行程序字符的编码格式:
-finput-charset=utf-8//源文件得编码格式
-fexec-charset=gbk//可执行程序中的字符的编码格式
-fwide-exec-charset=utf-16LE//源文件中宽字符得输出格式
当指定-finput-charset而不指定输出格式时,默认输出可执行程序为utf8,当指定-fexec-charset时,就能输出指定可执行程序的格式。
输入输出的格式都只能指定成gbk或utf8的一种。当使用了wchar_t存储宽字符时,可以用-fwide-exec-charset选项指定宽字符的输出编码格式,不指定编译器也能进行编译。
(2)、控制终端输出的编码方式
linux终端的输出方式默认为utf8格式,如果可执行程序性为gbk就会出现乱码。
可使用locale查看语言环境。可以通过export lang*临时改变。也可通过修改/etc/ecvirnment永久修改。

/etc/environment 和 /etc/profile 是 Linux 系统中用于定义环境变量和启动脚本的两个不同的配置文件。它们的作用和应用场景有所区别:

/etc/environment:

这是系统范围内的环境配置文件。
它是由 PAM (Pluggable Authentication Module) 模块读取的,适用于所有通过 PAM 的会话。
/etc/environment 的内容被解析为环境变量,但不被解释为脚本。环境变量设置为 KEY=“value” 的形式,没有导出(export)语句,每行一个变量定义。
通常用于设置系统范围内的简单环境变量,这些变量对所有用户和守护进程均有效。
/etc/profile:

这是针对登录会话的全局初始化脚本,仅在启动登录 shell 时执行(如通过控制台、ssh 等登录系统)。
/etc/profile 是一个 shell 脚本,可以包含详细的编程逻辑,如条件语句等。
通常在 /etc/profile 内部使用“export”命令来设置环境变量,并且其内容可以根据需要运行各种初始化命令。
它可能会调用其他脚本,比如 /etc/profile.d/*.sh,以进一步进行环境或行为的定制化。
总结区别:

/etc/environment 用于定义全系统范围内必须的环境变量。
/etc/profile 通常用于执行更复杂的初始化命令和环境设置,并且是特定于 shell 登录会话的。
修改 /etc/environment 后通常需要重新登录或重启系统,而 /etc/profile 对于新的登录会话立即生效。
/etc/profile 可以用于执行配置环境变量之外的其他任何启动命令或脚本。
因此,基于配置需求使用这两个文件时,要考虑其加载时机和针对性以确保环境变量和启动脚本按预期运行。

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值