字符与字节
该部分转载字符与字节
在Java中有输入、输出两种IO流,每种输入、输出流又分为字节流和字符流两大类。关于字节,我们在学习8大基本数据类型中都有了解,每个字节(byte)有8bit组成,每种数据类型又几个字节组成等。关于字符,我们可能知道代表一个汉字或者英文字母。
但是字节与字符之间的关系是怎样的?
Java采用unicode编码,2个字节来表示一个字符,这点与C语言中不同,C语言中采用ASCII,在大多数系统中,一个字符通常占1个字节,但是在0~127整数之间的字符映射,unicode向下兼容ASCII。而Java采用unicode来表示字符,一个中文或英文字符的unicode编码都占2个字节。但如果采用其他编码方式,一个字符占用的字节数则各不相同。可能有点晕,举个例子解释下。
例如:Java中的String类是按照unicode进行编码的,当使用String(byte[] bytes, String encoding)构造字符串时,encoding所指的是bytes中的数据是按照那种方式编码的,而不是最后产生的String是什么编码方式,换句话说,是让系统把bytes中的数据由encoding编码方式转换成unicode编码。如果不指明,bytes的编码方式将由jdk根据操作系统决定。
getBytes(String charsetName)使用指定的编码方式将此String编码为byte序列,并将结果存储到一个新的 byte 数组中。如果不指定将使用操作系统默认的编码方式,我的电脑默认的是GBK编码。
1 | public class Hel { |
输出结果
1 | 字节长度为:9 |
这是因为:在 GB 2312 编码或 GBK 编码中,一个英文字母字符存储需要1个字节,一个汉字字符存储需要2个字节。 在UTF-8编码中,一个英文字母字符存储需要1个字节,一个汉字字符储存需要3到4个字节。在UTF-16编码中,一个英文字母字符存储需要2个字节,一个汉字字符储存需要3到4个字节(Unicode扩展区的一些汉字存储需要4个字节)。在UTF-32编码中,世界上任何字符的存储都需要4个字节。
简单来讲,一个字符表示一个汉字或英文字母,具体字符与字节之间的大小比例视编码情况而定。有时候读取的数据是乱码,就是因为编码方式不一致,需要进行转换,然后再按照unicode进行编码。
字节输入/输出流
这类流的操作是基于单个字节因此不便于处理以Unicode形式储存的信息,比如用这个操作中文字符会出现乱码


字符输入/输出流
这类流的操作都是基于两个字节的char值的(即,Unicode码元),而不是基于byte值的。


流的接口
Closeable
InputStream,OutputStream,Reader和Writer都实现了Closeable接口。
1 | public interface Closeable extends AutoCloseable { |
从上面的定义可知Closeable扩展AutoCloseable.实现AutoCloseable的类都可以使用try-with-resource.
为什么需要两个接口,因为
AutoCloseable.close方法可以抛出任何异常,而Closeable.close方法
只能抛出IOException
Flushable
OutputStream和Writer实现了Flushable
Readable
Reader实现了Readable接口
1 | public interface Readable { |
Appendable
只有Writer实现了Appendable接口
1 |
|
文件的操作
File
File 是磁盘文件和目录路径名的一种抽象形式,其直接继承自 Object,实现了 Serializable 接口和 Comparable 接口;实现 Serializable 接口意味着 File 对象可以被序列化,而实现 Comparable 接口意味着 File 对象可以比较大小;此外 File 并没有什么特殊之处,就是对文件的一种上层抽象封装实现,方便操作文件。
File类共提供了四个不同的构造函数,以不同的参数形式灵活地接收文件和目录名信息。构造函数:
1 | File (String pathname) |
File的常用方法
1 | public boolean exists( ) 判断文件或目录是否存在 |
注意:当需要创建D:\\test\\test1.txt文件时,如果test目录不存在,则不可以直接使用createNewFile()创建;
同样不能使用mkdir(),因为mkdir()会把D:\\test\\test1.txt中的test和test1.txt都当做文件夹而mkdir()
只能创建一个文件夹;如果使用mkdirs()则会生成test和test1.txt两个文件.
创建一个文件夹和文件
1 | File file = new File("D:\\test"); |
FileDescriptor
File 是磁盘文件和目录路径名的一种抽象形式,其直接继承自 Object,实现了 Serializable 接口和 Comparable 接口;实现 Serializable 接口意味着 File 对象可以被序列化,而实现 Comparable 接口意味着 File 对象可以比较大小;此外 File 并没有什么特殊之处,就是对文件的一种上层抽象封装实现,方便操作文件。
FileDescriptor 是文件描述符,用来表示开放文件、开放套接字等。当 FileDescriptor 表示文件时,我们可以通俗的将 FileDescriptor 看成是该文件,但是不能直接通过 FileDescriptor 对该文件进行操作,若要通过 FileDescriptor 对该文件进行操作,则需要新创建 FileDescriptor 对应的 FileOutputStream,然后再对文件进行操作。
1 | public final class FileDescriptor { |
所以,针对 System.X 的 API 来说 FileDescriptor 是一种更加底层的操作,其不与文件名相互关联,只与操作系统中对应文件的句柄关联。
RandomAccessFile
RandomAccessFile类可以在文件的任何位置查找或写入数据
构造方法
1 | //模式有四种:r 表示只读 rw 表示读写模式 rws 表示每次更新时都对数据和元数据 |
常用方法
1 | long getFilePointer() 返回文件指针的位置 |
注:在Java中char有两个字节,double有八个字节,int有四个字节float有四个字节,boolean有一个字节
详细的参考:
java io系列26之 RandomAccessFile
RandomAccessFile类使用详解
RandomAccessFile 文件读写中文乱码解决方案