磁盘文件数据存储方式.doc

上传人:hw****26 文档编号:3117972 上传时间:2019-05-22 格式:DOC 页数:11 大小:113.50KB
下载 相关 举报
磁盘文件数据存储方式.doc_第1页
第1页 / 共11页
磁盘文件数据存储方式.doc_第2页
第2页 / 共11页
磁盘文件数据存储方式.doc_第3页
第3页 / 共11页
磁盘文件数据存储方式.doc_第4页
第4页 / 共11页
磁盘文件数据存储方式.doc_第5页
第5页 / 共11页
点击查看更多>>
资源描述

1、磁盘文件数据存储方式在介绍各种操作文件方式之前,需要先介绍磁盘上文件数据的组织方式。实际上,文件是在计算机内存中以二进制表示的数据.在外部存储介质上的另一种存放形式。文件通常分为二进制文件和文本文件。根据数据的组织的形式,可分为 ASCII 文件和二进制文件。ASCII 文件又称文本文件,它的每一个字节放一个 ASCII 代码,代表一个字符。二进制文件是把内存中的数据按其在内存中的存储形式原样输出到磁盘上存放。如果有一个整数 10000,在内存中占 2 个字节,如果按 ASCII 码形式输出,则占 5 个字节,而按二进制形式输出 在磁盘上只占 2 个字节。 用 ASCII 码形式输出与字符一一

2、对应,一个字节代表一个字符因而便于对字符进行逐个处理,也便于输出字符 。但一般占存储空间较多,而且要花费转换时间。 用二进制形式输出数值,可以节省外存空间和转换时间,但一个字节并不对应一个字符,不能直接输出字符 形式。 一般中间结果数据需要暂时保存在外存上,以后又需要输入到内存的,常用二进制文件保存。 ASCII 形式 00110001 00110000 00110000 00110000 00110000 内存中的存储形式 00100111 00010000 二进制形式 00100111 00010000比如在内存中数据 00110000 00111001 (十进制为 12345) 在磁盘上

3、可以以 ASCII 码存储为 00110001 00110010 00110011 00110100 00110101 1 2 3 4 5二进制存储格式 00110000 00111001字符,字节和编码摘要:本文介绍了字符与编码的发展过程,相关概念的正确理解。举例说明了一些实际应用中,编码的实现方法。然后,本文讲述了通常对字符与编码的几种误解,由于这些误解而导致乱码产生的原因,以及消除乱码的办法。本文的内容涵盖了“中文问题”,“乱码问题”。掌握编码问题的关键是正确地理解相关概念,编码所涉及的技术其实是很简单的。因此,阅读本文时需要慢读多想,多思考。引言“字符与编码”是一个被经常讨论的话题。即

4、使这样,时常出现的乱码仍然困扰着大家。虽然我们有很多的办法可以用来消除乱 码,但我们并不一定理解这些办法的内在原理。而有的乱码产生的原因,实际上由于底层代码本身有问题所导致的。因此,不仅是初学者会对字符编码感到模糊,有 的底层开发人员同样对字符编码缺乏准确的理解。1. 编码问题的由来,相关概念的理解1.1 字符与编码的发展从计算机对多国语言的支持角度看,大致可以分为三个阶段:系统内码 说明 系统阶段一 ASCII 计算机刚开始只支持英语,其它语言不能够在计算机上存储和显示。 英文 DOS阶段二 ANSI 编码(本地化)为使计算机支持更多语言,通常使用 0x800xFF 范围的 2 个字节来表示

5、 1 个字符。比如:汉字 中 在中文操作系统中,使用 0xD6,0xD0 这两个字节存储。不同的国家和地区制定了不同的标准,由此产生了 GB2312, BIG5, JIS 等各自的编码标准。这些使用 2 个字节来代表一个字符的各种汉字延伸编码方式,称为 ANSI 编码。在简体中文系统下,ANSI 编码代表 GB2312 编码,在日文操作系统下,ANSI 编码代表 JIS 编码。不同 ANSI 编码之间互不兼容,当信息在国际间交流时,无法将属于两种语言中文 DOS,中文 Windows 95/98,日文 Windows 95/98的文字,存储在同一段 ANSI 编码的文本中。阶段三 UNICOD

6、E(国际化)为了使国际间信息交流更加方便,国际组织制定了 UNICODE 字符集,为各种语言中的每一个字符设定了统一并且唯一的数字编号,以满足跨语言、跨平台进行文本转换、处理的要求。Windows NT/2000/XP,Linux,Java字符串在内存中的存放方法:在 ASCII 阶段,单字节字符串使用一个字节存放一个字符(SBCS)。比如,“Bob123“ 在内存中为:42 6F 62 31 32 33 00B o b 1 2 3 0在使用 ANSI 编码支持多种语言阶段,每个字符使用一个字节或多个字节来表示(MBCS),因此,这种方式存放的字符也被称作多字节字符。比如,“中文123“ 在中

7、文 Windows 95 内存中为 7 个字节,每个汉字占 2 个字节,每个英文和数字字符占 1 个字节:D6 D0 CE C4 31 32 33 00中 文 1 2 3 0在 UNICODE 被采用之后,计算机存放字符串时,改为存放每个字符在 UNICODE 字符集中的序号。目前计算机一般使用 2 个字节(16 位)来存放一个序号(DBCS),因此,这种方式存放的字符也被称作宽字节字符。比如,字符串 “中文 123“ 在 Windows 2000 下,内存中实际存放的是 5 个序号:2D 4E 87 65 31 00 32 00 33 00 00 00 在 x86 CPU 中,低字节在前中

8、文 1 2 3 0 一共占 10 个字节。1.2 字符,字节,字符串理解编码的关键,是要把字符的概念和字节的概念理解准确。这两个概念容易混淆,我们在此做一下区分:概念描述 举例字符 人们使用的记号,抽象意义上的一个符号。 1, 中, a, $, ¥, 字节 计算机中存储数据的单元,一个 8 位的二进制数,是一个很具体的存储空间。 0x01, 0x45, 0xFA, ANSI字符串在内存中,如果“字符”是以 ANSI 编码形式存在的,一个字符可能使用一个字节或多个字节来表示,那么我们称这种字符串为 ANSI 字符串或者多字节字符串。“中文 123“(占 7 字节)UNICODE字符串在内存中,如

9、果“字符”是以在 UNICODE 中的序号存在的,那么我们称这种字符串为 UNICODE 字符串或者宽字节字符串。L“中文 123“(占 10 字节)由于不同 ANSI 编码所规定的标准是不相同的,因此,对于一个给定的多字节字符串,我们必须知道它采用的是哪一种编码规则,才能够知道它包含了哪些“字符”。而对于 UNICODE 字符串来说,不管在什么环境下,它所代表的“字符”内容总是不变的。1.3 字符集与编码各个国家和地区所制定的不同 ANSI 编码标准中,都只规定了各自语言所需的“字符”。比如:汉字标准(GB2312)中没有规定韩国语字符怎样存储。这些 ANSI 编码标准所规定的内容包含两层含

10、义:1. 使用哪些字符。也就是说哪些汉字,字母和符号会被收入标准中。所包含“字符”的集合就叫做“字符集”。 2. 规定每个“字符”分别用一个字节还是多个字节存储,用哪些字节来存储,这个规定就叫做“编码”。 各个国家和地区在制定编码标准的时候,“字符的集合”和“编码”一般都是同时制定的。因此,平常我们所说的“字符集”,比如:GB2312, GBK, JIS 等,除了有“字符的集合”这层含义外,同时也包含了“编码”的含义。“UNICODE 字符集”包含了各种语言中使用到的所有“字符”。用来给 UNICODE 字符集编码的标准有很多种,比如:UTF-8, UTF-7, UTF-16, Unicode

11、Little, UnicodeBig 等。1.4 常用的编码简介简单介绍一下常用的编码规则,为后边的章节做一个准备。在这里,我们根据编码规则的特点,把所有的编码分成三类:分类 编码标准 说明单字节字符编码 ISO-8859-1 最简单的编码规则,每一个字节直接作为一个 UNICODE 字符。比如,0xD6, 0xD0 这两个字节,通过 iso-8859-1 转化为字符串时,将直接得到 0x00D6, 0x00D0 两个 UNICODE 字符,即 “。反之,将 UNICODE 字符串通过 iso-8859-1 转化为字节串时,只能正常转化 0255 范围的字符。ANSI 编码GB2312,BIG

12、5,Shift_JIS,ISO-8859-2 把 UNICODE 字符串通过 ANSI 编码转化为“字节串”时,根据各自编码的规定,一个 UNICODE 字符可能转化成一个字节或多个字节。反之,将字节串转化成字符串时,也可能多个字节转化成一个字符。比如,0xD6, 0xD0 这两个字节,通过 GB2312 转化为字符串时,将得到 0x4E2D 一个字符,即 中 字。“ANSI 编码”的特点:1. 这些“ANSI 编码标准”都只能处理各自语言范围之内的 UNICODE 字符。2. “UNICODE 字符”与“转换出来的字节”之间的关系是人为规定的。UNICODE 编码UTF-8,UTF-16,

13、UnicodeBig 与“ANSI 编码”类似的,把字符串通过 UNICODE 编码转化成“字节串”时,一个 UNICODE 字符可能转化成一个字节或多个字节。与“ANSI 编码”不同的是:1. 这些“UNICODE 编码”能够处理所有的 UNICODE 字符。2. “UNICODE 字符”与“转换出来的字节”之间是可以通过计算得到的。我们实际上没有必要去深究每一种编码具体把某一个字符编码成了哪几个字节,我们只需要知道“编码”的概念就是把“字符”转 化成“字节”就可以了。对于“UNICODE 编码”,由于它们是可以通过计算得到的,因此,在特殊的场合,我们可以去了解某一种“UNICODE 编码”

14、是怎样的规则。2. 字符与编码在程序中的实现2.1 程序中的字符与字节在 C+ 和 Java 中,用来代表“字符”和“字节”的数据类型,以及进行编码的方法:类型或操作 C+ Java字符 wchar_t char字节 char byteANSI 字符串 char byteUNICODE 字符串 wchar_t String字节串字符串 mbstowcs(), MultiByteToWideChar() string = new String(bytes, “encoding“)字符串字节串 wcstombs(), WideCharToMultiByte() bytes = string.get

15、Bytes(“encoding“)以上需要注意几点:1. Java 中的 char 代表一个“UNICODE 字符(宽字节字符)”,而 C+ 中的 char 代表一个字节。2. MultiByteToWideChar() 和 WideCharToMultiByte() 是 Windows API 函数。2.2 C+ 中相关实现方法声明一段字符串常量:/ ANSI 字符串,内容长度 7 字节char sz20 = “中文 123“;/ UNICODE 字符串,内容长度 5 个 wchar_t(10 字节)wchar_t wsz20 = L“x4E2Dx6587x0031x0032x0033“;U

16、NICODE 字符串的 I/O 操作,字符与字节的转换操作:/ 运行时设定当前 ANSI 编码,VC 格式setlocale(LC_ALL, “.936“);/ GCC 中格式setlocale(LC_ALL, “zh_CN.GBK“);/ Visual C+ 中使用小写 %s,按照 setlocale 指定编码输出到文件/ GCC 中使用大写 %Sfwprintf(fp, L“%sn“, wsz);/ 把 UNICODE 字符串按照 setlocale 指定的编码转换成字节wcstombs(sz, wsz, 20);/ 把字节串按照 setlocale 指定的编码转换成 UNICODE 字符

17、串mbstowcs(wsz, sz, 20);在 Visual C+ 中,UNICODE 字符串常量有更简单的表示方法。如果源程序的编码与当前默认 ANSI 编码不符,则需要使用 #pragma setlocale,告诉编译器源程序使用的编码:/ 如果源程序的编码与当前默认 ANSI 编码不一致,/ 则需要此行,编译时用来指明当前源程序使用的编码#pragma setlocale(“.936“)/ UNICODE 字符串常量,内容长度 10 字节wchar_t wsz20 = L“中文 123“;以上需要注意 #pragma setlocale 与 setlocale(LC_ALL, “) 的

18、作用是不同的,#pragma setlocale 在编译时起作用,setlocale() 在运行时起作用。2.3 Java 中相关实现方法字符串类 String 中的内容是 UNICODE 字符串:/ Java 代码,直接写中文String string = “中文 123“;/ 得到长度为 5,因为是 5 个字符System.out.println(string.length();字符串 I/O 操作,字符与字节转换操作。在 Java 包 java.io.* 中,以“Stream”结尾的类一般是用来操作“字节串”的类,以“Reader”,“Writer”结尾的类一般是用来操作“字符串”的类。

19、/ 字符串与字节串间相互转化/ 按照 GB2312 得到字节(得到多字节字符串)byte bytes = string.getBytes(“GB2312“);/ 从字节按照 GB2312 得到 UNICODE 字符串string = new String(bytes, “GB2312“);/ 要将 String 按照某种编码写入文本文件,有两种方法:/ 第一种办法:用 Stream 类写入已经按照指定编码转化好的字节串OutputStream os = new FileOutputStream(“1.txt“);os.write(bytes);os.close();/ 第二种办法:构造指定编码

20、的 Writer 来写入字符串Writer ow = new OutputStreamWriter(new FileOutputStream(“2.txt“), “GB2312“);ow.write(string);ow.close();/* 最后得到的 1.txt 和 2.txt 都是 7 个字节 */如果 java 的源程序编码与当前默认 ANSI 编码不符,则在编译的时候,需要指明一下源程序的编码。比如:E:javac -encoding BIG5 Hello.java以上需要注意区分源程序的编码与 I/O 操作的编码,前者是在编译时起作用,后者是在运行时起作用。3. 几种误解,以及乱码

21、产生的原因和解决办法3.1 容易产生的误解对编码的误解误解一在将“字节串”转化成“UNICODE 字符串”时,比如在读取文本文件时,或者通过网络传输文本时,容易将“字节串”简单地作为单字节字符串,采用每“一个字节”就是“一个字符”的方法进行转化。而实际上,在非英文的环境中,应该将“字节串”作为 ANSI 字符串,采用适当的编码来得到 UNICODE 字符串,有可能“多个字节”才能得到“一个字符”。通常,一直在英文环境下做开发的程序员们,容易有这种误解。误解二在 DOS,Windows 98 等非 UNICODE 环境下,字符串都是以 ANSI 编码的字节形式存在的。这种以字节形式存在的字符串,

22、必须知道是哪种编码才能被正确地使用。这使我们形成了一个惯性思维:“字符串的编码”。当 UNICODE 被支持后,Java 中的 String 是以字符的“序号”来存储的,不是以“某种编码的字节”来存储的,因此已经不存在“字符串的编码”这个概念了。只有在“字符串”与“字节串”转化时,或 者,将一个“字节串”当成一个 ANSI 字符串时,才有编码的概念。不少的人都有这个误解。第一种误解,往往是导致乱码产生的原因。第二种误解,往往导致本来容易纠正的乱码问题变得更复杂。在这里,我们可以看到,其中所讲的“误解一”,即采用每“一个字节”就是“一个字符”的转化方法,实际上也就等同于采用 iso-8859-1

23、 进行转化。因此,我们常常使用 bytes = string.getBytes(“iso-8859-1“) 来进行逆向操作,得到原始的“字节串”。然后再使用正确的 ANSI 编码,比如 string = new String(bytes, “GB2312“),来得到正确的“UNICODE 字符串”。3.2 非 UNICODE 程序在不同语言环境间移植时的乱码非 UNICODE 程序中的字符串,都是以某种 ANSI 编码形式存在的。如果程序运行时的语言环境与开发时的语言环境不同,将会导致 ANSI 字符串的显示失败。比如,在日文环境下开发的非 UNICODE 的日文程序界面,拿到中文环境下运行时

24、,界面上将显示乱码。如果这个日文程序界面改为采用 UNICODE 来记录字符串,那么当在中文环境下运行时,界面上将可以显示正常的日文。由于客观原因,有时候我们必须在中文操作系统下运行非 UNICODE 的日文软件,这时我们可以采用一些工具,比如,南极星,AppLocale 等,暂时的模拟不同的语言环境。3.3 网页提交字符串当页面中的表单提交字符串时,首先把字符串按照当前页面的编码,转化成字节串。然后再将每个字节转化成 “%XX“ 的格式提交到 Web 服务器。比如,一个编码为 GB2312 的页面,提交 “中“ 这个字符串时,提交给服务器的内容为 “%D6%D0“。在服务器端,Web 服务器

25、把收到的 “%D6%D0“ 转化成 0xD6, 0xD0 两个字节,然后再根据 GB2312 编码规则得到 “中“ 字。在 Tomcat 服务器中,request.getParameter() 得到乱码时,常常是因为前面提到的“误解一”造成的。默认情况下,当提交 “%D6%D0“ 给 Tomcat 服务器时,request.getParameter() 将返回 0x00D6, 0x00D0 两个 UNICODE 字符,而不是返回一个 “中“ 字符。因此,我们需要使用 bytes = string.getBytes(“iso-8859-1“) 得到原始的字节串,再用 string = new S

26、tring(bytes, “GB2312“) 重新得到正确的字符串 “中“。3.4 从数据库读取字符串通过数据库客户端(比如 ODBC 或 JDBC)从数据库服务器中读取字符串时,客户端需要从服务器获知所使用的 ANSI 编码。当数据库服务器发送字节流给客户端时,客户端负责将字节流按照正确的编码转化成 UNICODE 字符串。如果从数据库读取字符串时得到乱码,而数据库中存放的数据又是正确的,那么往往还是因为前面提到的“误解一”造成的。解决 的办法还是通过 string = new String( string.getBytes(“iso-8859-1“), “GB2312“) 的方法,重新得到

27、原始的字节串,再重新使用正确的编码转化成字符串。3.5 电子邮件中的字符串当一段 Text 或者 HTML 通过电子邮件传送时,发送的内容首先通过一种指定的字符编码转化成“字节串”,然后再把“字节串”通过一种指定的传输编码(Content-Transfer-Encoding)进行转化得到另一串“字节串”。比如,打开一封电子邮件源代码,可以看到类似的内容:Content-Type: text/plain;charset=“gb2312“Content-Transfer-Encoding: base64sbG+qcrQuqO17cf4yee74bGjz9W7+b3wudzA7dbQ0MQNCg0KvPKzxqO6uqO17cnnsaPW0NDEDQoNCg=最常用的 Content-Transfer-Encoding 有 Base64 和 Quoted-Printable 两种。在对二进制文件或者中文文本进行转化时,Base64 得到的“字节串”比 Quoted-Printable 更短。在对英文文本进行转化时,Quoted-Printable 得到的“字节串”比 Base64 更短。邮件的标题,用了一种更简短的格式来标注“字符编码”和“传输编码”。比如,标题内容为 “中“,则在邮件源代码中表示为:/ 正确的标题格式Subject: =?GB2312?B?1tA=?=其中,

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 教育教学资料库 > 精品笔记

Copyright © 2018-2021 Wenke99.com All rights reserved

工信部备案号浙ICP备20026746号-2  

公安局备案号:浙公网安备33038302330469号

本站为C2C交文档易平台,即用户上传的文档直接卖给下载用户,本站只是网络服务中间平台,所有原创文档下载所得归上传人所有,若您发现上传作品侵犯了您的权利,请立刻联系网站客服并提供证据,平台将在3个工作日内予以改正。