详解Java中字符流与字节流的区别
作者:absfree 发布时间:2023-01-14 00:19:58
本文为大家分析了Java中字符流与字节流的区别,供大家参考,具体内容如下
1. 什么是流
Java中的流是对字节序列的抽象,我们可以想象有一个水管,只不过现在流动在水管中的不再是水,而是字节序列。和水流一样,Java中的流也具有一个“流动的方向”,通常可以从中读入一个字节序列的对象被称为输入流;能够向其写入一个字节序列的对象被称为输出流。
2. 字节流
Java中的字节流处理的最基本单位为单个字节,它通常用来处理二进制数据。Java中最基本的两个字节流类是InputStream和OutputStream,它们分别代表了组基本的输入字节流和输出字节流。InputStream类与OutputStream类均为抽象类,我们在实际使用中通常使用Java类库中提供的它们的一系列子类。下面我们以InputStream类为例,来介绍下Java中的字节流。
InputStream类中定义了一个基本的用于从字节流中读取字节的方法read,这个方法的定义如下:
public abstract int read() throws IOException;
这是一个抽象方法,也就是说任何派生自InputStream的输入字节流类都需要实现这一方法,这一方法的功能是从字节流中读取一个字节,若到了末尾则返回-1,否则返回读入的字节。关于这个方法我们需要注意的是,它会一直阻塞知道返回一个读取到的字节或是-1。另外,字节流在默认情况下是不支持缓存的,这意味着每调用一次read方法都会请求操作系统来读取一个字节,这往往会伴随着一次磁盘IO,因此效率会比较低。有的小伙伴可能认为InputStream类中read的以字节数组为参数的重载方法,能够一次读入多个字节而不用频繁的进行磁盘IO。那么究竟是不是这样呢?我们来看一下这个方法的源码:
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}
它调用了另一个版本的read重载方法,那我们就接着往下追:
public int read(byte b[], int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if (off < 0 || len < 0 || len > b.length - off) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
}
int c = read();
if (c == -1) {
return -1;
}
b[off] = (byte)c;
int i = 1;
try {
for (; i < len ; i++) {
c = read();
if (c == -1) {
break;
}
b[off + i] = (byte)c;
}
} catch (IOException ee) {
}
return i;
}
从以上的代码我们可以看到,实际上read(byte[])方法内部也是通过循环调用read()方法来实现“一次”读入一个字节数组的,因此本质来说这个方法也未使用内存缓冲区。要使用内存缓冲区以提高读取的效率,我们应该使用BufferedInputStream。
3. 字符流
Java中的字符流处理的最基本的单元是Unicode码元(大小2字节),它通常用来处理文本数据。所谓Unicode码元,也就是一个Unicode代码单元,范围是0x0000~0xFFFF。在以上范围内的每个数字都与一个字符相对应,Java中的String类型默认就把字符以Unicode规则编码而后存储在内存中。然而与存储在内存中不同,存储在磁盘上的数据通常有着各种各样的编码方式。使用不同的编码方式,相同的字符会有不同的二进制表示。实际上字符流是这样工作的:
输出字符流:把要写入文件的字符序列(实际上是Unicode码元序列)转为指定编码方式下的字节序列,然后再写入到文件中;
输入字符流:把要读取的字节序列按指定编码方式解码为相应字符序列(实际上是Unicode码元序列从)从而可以存在内存中。
我们通过一个demo来加深对这一过程的理解,示例代码如下:
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterDemo {
public static void main(String[] args) {
FileWriter fileWriter = null;
try {
try {
fileWriter = new FileWriter("demo.txt");
fileWriter.write("demo");
} finally {
fileWriter.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
以上代码中,我们使用FileWriter向demo.txt中写入了“demo”这四个字符,我们用十六进制编辑器WinHex查看下demo.txt的内容:
从上图可以看出,我们写入的“demo”被编码为了“64 65 6D 6F”,但是我们并没有在上面的代码中显式指定编码方式,实际上,在我们没有指定时使用的是操作系统的默认字符编码方式来对我们要写入的字符进行编码。
由于字符流在输出前实际上是要完成Unicode码元序列到相应编码方式的字节序列的转换,所以它会使用内存缓冲区来存放转换后得到的字节序列,等待都转换完毕再一同写入磁盘文件中。
4. 字符流与字节流的区别
经过以上的描述,我们可以知道字节流与字符流之间主要的区别体现在以下几个方面:
字节流操作的基本单元为字节;字符流操作的基本单元为Unicode码元。
字节流默认不使用缓冲区;字符流使用缓冲区。
字节流通常用于处理二进制数据,实际上它可以处理任意类型的数据,但它不支持直接写入或读取Unicode码元;字符流通常处理文本数据,它支持写入及读取Unicode码元。
以上是我对Java中字符流与字节流的一些认识,如有叙述不清晰或是不准确的地方希望大家可以指正,谢谢大家。
猜你喜欢
- 引言:在使用循环的时候,循环里面带有break、continue、return的时候经常弄混,今天特意整理了下,以待后用... f
- 场景我们团队现在面临着多端数据接口对接的问题,为了解决这个问题我们定义了接口对接的规范,前端(安卓,Ios,web前端)和后端进行了数据的格
- 一、静态代理模式1.1、 代理模式的定义:由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标
- ElGamal数字签名,供大家参考,具体内容如下一、实验目的学习ElGamal算法在数字签名方面的使用,掌握教科书版本的ElGamal数字签
- 简单实现了下:import javax.crypto.BadPaddingException;import javax.crypto.Cip
- 一,Maven 依赖 pom.xml配置1, 去掉默认日志,以便切换到log4j2的日志依赖2, 然后添加如下两个日志依赖二,在工程根目录下
- 在 Java 中,LinkedList 和 ArrayList 的性能是不同的,具体取决于你所需要的操作。对于频繁的插入和删除操作,Link
- 1、jdbc1) 含义:JDBC是java语言连接数据库,Java Date Base Connectivity2) jdbc的本质:在编程
- 目录前言实践部分测试部分总结前言今天跟小伙伴们分享一个实战内容,使用Spring Boot+Shiro实现一个简单的Http认证。场景是这样
- 返回值类型:System.Int64表示为 Windows 文件时间的当前 DateTime 对象的值。例如:DateTime.Now.To
- 在前面的文章中有介绍到我们在微信web开发过程中常常用到的 【微信JSSDK中Config配置】 ,但是我们在真正的使用中我们不仅仅只是为了
- 数据导出到Excel几乎是所有客户都会提出的一个需求。下面我就分享一下我的代码。首先需要引入的jar包:然后就是正式代码了。package
- 在 javax.validation.constraints包中定义了非常多的校验注解,引入依赖:<dependency> &n
- 在前面的文章<Mybatis配置之<properties>属性配置元素详述>,我们讲述了<properties
- 问题描述在开发批量删除功能时,往往都是多条数据,所以前台需要传一个数组给后台,但是怎么在URL中绑定一个数组,同时在后台用@PathVari
- 本文介绍了Java实现动态获取图片验证码的示例代码,分享给大家,具体如下:import javax.imageio.ImageIO;impo
- 1、通过查找API文档:2、Map.Entry是一个接口,所以不能直接实例化。3、Map.entrySet( )返回的是一个collecti
- 功能介绍大家都知道在Spring boot开发过程中,需要在配置文件里配置许多信息,如数据库的连接信息等,如果不加密,传明文,数据库就直接暴
- 前言在最近的一个项目需要用JAVA来解析DICOM图片,DICOM被广泛应用于放射医疗,心血管成像以及放射诊疗诊断设备(X射线,CT,核磁共
- 1、使用JPA 的@Enumerated 注解 ,可以直接将Enum映射到数据库中。但是value的值只有两种方式选择,一种是使用枚举的序号