字节流VS字符流:揭秘两者的神秘面纱!

先上结论

两者的组成不同:

  1. 字节流的组成:字节流是由字节组成的。

  2. 字符流的组成:字符流是由字符组成的。

两者的处理不同:

  1. 字节流的处理:主要用在处理二进制数据,它是按字节来处理的但实际中很多的数据是文本。

  2. 字符流的处理:按虚拟机的encode来处理,也就是要进行字符集的转化。

总额来说:

  1. 字节流是由字节组成的; 字符流是由字符组成的;

  2. Java里字符由两个字节组成. 1字符=2字节

  3. JAVA中的字节流是采用ASCII编码的, 字符流是采用好似UTF编码,支持中文的

  4. 字节流与字符流主要的区别是他们的的处理方式,字节流是最基本的,采用ASCII编码,所有的InputStream和OutputStream的子类都是,主要用在处理二进制数据,它是按字节来处理的,但实际中很多的数据是文本,又提出了字符流的概念,采用Unicode编码.它是按虚拟机的encode来处理,也就是要进行字符集的转化,这两个之间通过InputStreamReader,OutputStreamWriter来关联,实际上是通过byte[]和String来关联

什么是流

在Java中,流主要用于处理字节序列,它们可以是文件、网络连接或其他I/O设备。流的核心概念是将数据从源头到目的地的过程分解为一系列的操作,这些操作可以是中间操作或终止操作。

Java中的流可以分为字节流和字符流两种类型。字节流主要处理字节序列,而字符流主要处理字符序列。字节流和字符流之间的主要区别在于它们处理数据的方式:字节流直接处理字节,而字符流则处理字符,并且字符流需要处理字符编码。

Java中的流可以分为输入流和输出流两种类型。输入流用于从某个来源读取数据,而输出流用于将数据写入某个目的地。输入流和输出流之间的主要区别在于它们处理数据的方向:输入流从来源读取数据,而输出流将数据写入目的地。

Java中的流可以分为文件流、网络流和过滤流三种类型。文件流用于处理文件,网络流用于处理网络连接,而过滤流用于对其他类型的流进行过滤和转换。

字节流

在Java编程语言中,字节流处理的最基本单位为单个字节,它通常用来处理二进制数据。Java中最基本的两个字节流类是InputStream和OutputStream,它们分别代表了基本的输入字节流和输出字节流。这两个类都是java.io包中面向字节操作的顶级抽象类,关于Java同步IO字节流的操作都是基于这两个的。

InputStream类是所有字节输入流的父类,它是一个抽象类,提供了读取字节的方法。它可以用于读取诸如图像、视频、文本等各种类型的文件。常见的实现类有FileInputStream(从文件中读取数据)、ByteArrayInputStream(从字节数组中读取数据)和BufferedInputStream(提供缓冲功能,提高读取效率)等。

另一方面,OutputStream类则是所有字节输出流的父类,它也是一个抽象类,提供了写入字节的方法。常见的实现类有FileOutputStream(向文件中写入数据)、ByteArrayOutputStream(向字节数组中写入数据)等。

下面我们以InputStream类为例,来介绍下Java中的字节流。InputStream类中定义了一个基本的用于从字节流中读取字节的方法read,这个方法的定义如下:


字节流VS字符流:揭秘两者的神秘面纱!
这是一个抽象方法,也就是说任何派生自InputStream的输入字节流类都需要实现这一方法,这一方法的功能是从字节流中读取一个字节,若到了末尾则返回-1,否则返回读入的字节。关于这个方法我们需要注意的是,它会一直阻塞知道返回一个读取到的字节或是-1。另外,字节流在默认情况下是不支持缓存的,这意味着每调用一次read方法都会请求操作系统来读取一个字节,这往往会伴随着一次磁盘IO,因此效率会比较低。有的小伙伴可能认为InputStream类中read的以字节数组为参数的重载方法,能够一次读入多个字节而不用频繁的进行磁盘IO。那么究竟是不是这样呢?我们来看一下这个方法的源码:



字节流VS字符流:揭秘两者的神秘面纱!
它调用了另一个版本的read重载方法,那我们就接着往下追:



字节流VS字符流:揭秘两者的神秘面纱!
从以上的代码我们可以看到,实际上read(byte[])方法内部也是通过循环调用read()方法来实现“一次”读入一个字节数组的,因此本质来说这个方法也未使用内存缓冲区。要使用内存缓冲区以提高读取的效率,我们应该使用BufferedInputStream。


字符流

在Java编程语言中,字符流的基本处理单位是Unicode码元,每个码元占用2字节的空间。这种码元主要被用来处理文本形式的数据。进一步解释,所谓的Unicode码元,其实就是一个Unicode的代码单元,它的数值范围落在0x0000至0xFFFF之间。在这个范围内,每一个码元都对应着一个唯一的字符。在Java中,String类型的数据在内存中的存储方式默认是采用Unicode规则进行编码的。然而,值得注意的是,数据在磁盘上的存储方式和在内存中的存储方式通常是不一样的,磁盘上的数据可以有多种多样的编码方式。由于编码方式的不同,相同的字符可能会有不同的二进制表现形式。

实际上字符流是这样工作的:

  1. 输出字符流:把要写入文件的字符序列(实际上是Unicode码元序列)转为指定编码方式下的字节序列,然后再写入到文件中;

  2. 输入字符流:把要读取的字节序列按指定编码方式解码为相应字符序列(实际上是Unicode码元序列从)从而可以存在内存中。

我们通过一个demo来加深对这一过程的理解,示例代码如下:


字节流VS字符流:揭秘两者的神秘面纱!
由于字符流在输出前实际上是要完成Unicode码元序列到相应编码方式的字节序列的转换,所以它会使用内存缓冲区来存放转换后得到的字节序列,等待都转换完毕再一同写入磁盘文件中。


最后总结

经过以上的描述,我们可以知道字节流与字符流之间主要的区别体现在以下几个方面:

  1. 字节流操作的基本单元为字节;字符流操作的基本单元为Unicode码元。

  2. 字节流默认不使用缓冲区;字符流使用缓冲区。

  3. 字节流通常用于处理二进制数据,实际上它可以处理任意类型的数据,但它不支持直接写入或读取Unicode码元;字符流通常处理文本数据,它支持写入及读取Unicode码元。


原文始发于微信公众号(南说北道):字节流VS字符流:揭秘两者的神秘面纱!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/187863.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!