目 录CONTENT

文章目录

Java核心卷(二)输入与输出

Jinty
2023-12-15 / 0 评论 / 0 点赞 / 10 阅读 / 11031 字

Provides for system input and output through data streams, serialization and the file system.

IO流

缓存、文件、字符串、管道、字节数组、字符数组、过滤、Object对象

bit、字节、字符

字符集、字符编码

字符集(character set)是一个系统支持的所有抽象字符的集合。字符(character)就是各种文字和符号,包括国家文字、标点符号、图形符号、数字等。

常见的编码字符集有:

Unicode:也叫统一字符集,它包含了几乎世界上所有的已经发现且需要使用的字符(如中文、英文、德文等)。

ASCII:早期的计算机系统只能处理英文,所以ASCII成为了计算机的缺省字符集,包含了英文所需要的所有字符。

GB2312:中文字符集,包含ASCII字符集。ASCII部分用单字节表示,剩余部分用双字节表示。

GBK:GB2312的扩展,完整包含了GB2312的所有内容。

GB18030:GBK字符集的超集,常叫大汉字字符集,也叫CJK(Chinese,Japanese,Korea)字符集,包含了中、日、韩三国语言中的所有字符。

字符编码(character encoding),是编码字符集的字符和实际的存储值之间的转换关系。

常见的编码方式有:

UTF-8(Unicode字符集的编码方式)

UTF-16(Unicode字符集的编码方式)

UTF-32(Unicode字符集的编码方式)

ASCII(ASCII字符集的编码方式)

Java字符串由char序列组成,char数据类型是一个采用UTF-16编码表示Unicode代码点的代码单元,大多数的常用Unicode字符使用一个代码单元就可以表示,而增补字符需要一对代码单元表示。我们所熟知的String类型的length方法,它返回的是UTF-16编码表示的给定字符串的代码单元的数量,如果想要得到代码点的数量,可以调用codePointCount()方法,charAt方法返回位于指定位置的代码单元,codePointAt方法则返回指定位置的代码点。

原文链接: https://blog.csdn.net/nlznlz/article/details/80950596

字节流、字符流

字节流继承inputStream和OutputStream

字符流继承自InputSteamReader和OutputStreamWriter

都实现了Closeable, Flushable, Appendable这些接口

输入输出流是相对于内存而言的

区别

字节流没有缓冲区,是直接输出的,而字符流是输出到缓冲区的。因此在输出时,字节流不调用close()方法时,信息已经输出了,而字符流只有在调用close()方法关闭缓冲区时,信息才输出。要想字符流在未关闭时输出信息,则需要手动调用flush()方法。

读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。

处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据,不能用于处理图像视频等非文本类型的文件。

转换流

NIO

NIO(Non-blocking I/O,在Java领域,也称为New I/O),是一种同步非阻塞的I/O模型,也是I/O多路复用的基础,已经被越来越多地应用到大型应用服务器,成为解决高并发与大量连接、I/O处理问题的有效方式。

https://tech.meituan.com/2016/11/04/nio.html

对于NIO,它是非阻塞式,核心类:

1.Buffer为所有的原始类型提供 (Buffer)缓存支持。

2.Charset字符集编码解码解决方案

3.Channel一个新的原始 I/O抽象,用于读写Buffer类型,通道可以认为是一种连接,可以是到特定设备,程序或者是网络的连接

https://ifeve.com/overview/

https://blog.csdn.net/luoshenfu001/article/details/5812041

节点流、处理流

节点流:从或向一个特定的地方(节点)读写数据。如FileInputStream。

处理流(包装流):是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。如BufferedReader。处理流的构造方法总是要带一个其他的流对象做参数。

一个流对象经过其他流的多次包装,称为流的链接。

装饰者模式

序列化、反序列化

将保存在内存中的对象数据转化为二进制数据流进行传输,任何对象都可以序列化

实现方法:实现java.io.Serializable接口

把一个Java对象写入到硬盘或者传输到网路上面的其它计算机,这时我们就需要自己去通过java把相应的对象写成转换成字节流。ObjectOutputStream(OutputStream oS)

在使用tomcat开发JavaEE相关项目的时候,我们关闭tomcat后,相应的session中的对象就存储在了硬盘上,如果我们想要在tomcat重启的时候能够从tomcat上面读取对应session中的内容,那么保存在session中的内容就必须实现相关的序列化操作,还有jdbc加载驱动用的就是反序列化,将字符串变为对象。ObjectInputStream(inputStream iS)

采用类实现Serializable接口的序列化很简单,Java自动会将非transient修饰属性序列化到指定文件中去。

序列化版本号

反序列化必须拥有 class 文件,但随着项目的升级,class文件也会升级

序列化版本号可自由指定,如果不指定,JVM会根据类信息自己计算一个版本号,这样随着class的升级,就无法正确反序列化;不指定版本号另一个明显隐患是,不利于jvm间的移植,可能class文件没有更改,但不同jvm可能计算的规则不一样,这样也会导致无法反序列化。

transient关键字

一个类某些属性不需要序列化的,可用transient关键字修饰

如果只想将部分属性进行序列化,可以采用如下几种方法:

  1. 使用transient关键字

  2. 添加writeObject和readObject方法

  3. 使用Externalizable实现

Serializable与Externalizable

  1. Serializable 是标识接口,实现该接口,无需重写任何方法;

Externalizable 接口继承于Serializable,实现该接口,需要重写readExternal和writeExternal方法

  1. Serializable提供了两种方式进行对象的序列化,

  • 采用默认序列化方式,将非transatient和非static的属性进行序列化

  • 编写readObject和writeObject完成部分属性的序列化

Externalizable 接口的序列化,需要重写writeExternal和readExternal方法,并且在方法中编写相关的逻辑完成序列化和反序列化

  1. Externalizable接口的实现方式一定要有默认的无参构造函数

Serializable接口实现,其采用反射机制完成内容恢复,没有一定要有无参构造函数的限制

  1. 采用Externalizable无需产生序列化ID(serialVersionUID),而Serializable接口则需要

  2. 相比较Serializable, Externalizable序列化、反序列更加快速,占用相比较小的内存

在项目中,大部分的类还是推荐使用Serializable, 有些类可以使用Externalizable接口,如:

  • 完全控制序列的流程和逻辑

  • 需要大量的序列化和反序列化操作,而你比较关注资源和性能~ 当然,这种情况下,我们一般还会考虑第三方序列化/反序列化工具,如protobuf等进行序列化和反序列化操作~

流的关闭问题

包装流的close方法是否会自动关闭被包装的流?

包装的流都会自动调用被包装的流的关闭方法,无需自己调用

JVM中对于那些打开了没有关闭的IO文件流,会在不再被使用的情况下,等到下次做Full GC的时候把他们全部回收,但是让JVM去干这些事总归还是不好的,还是那句老话,自己的事情自己做

FileInputStream

底层输入流,用于从文件中读取数据

FileInputStream inputStream = new FileInputStream("R:\\personal\\jclab\\man.temp");
byte[] buffer = new byte[64];
int count = inputStream.read(buffer);
while (count > 0){
    System.out.println(count);
    count = inputStream.read(buffer);
}
inputStream.close();

DataInputStream

数据输入流允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型

DataInputStream inputStream = new DataInputStream(new FileInputStream("R:\\personal\\jclab\\man.txt"));
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line = bufferedReader.readLine();
while (null != line) {
    System.out.println(line);
    line = bufferedReader.readLine();
}
System.out.println("流未关闭,此时无法删除文件");
bufferedReader.close();
System.out.println("关闭包装流会关闭被包装的流");

File

常用方法

文件分片与文件断点续传

大文件内容查询与排序

FastDFS

FastDFS + nignx 搭建分布式文件服务器

FastDFS + nignx + SpringCloud 实现文件分片与断点续传

参考

https://blog.csdn.net/chengyuqiang/article/details/79183748

https://blog.csdn.net/sinat_37064286/article/details/86537354

https://www.cnblogs.com/whgk/p/5326568.html

https://my.oschina.net/wangmengjun/blog/1588096

0

评论区