Thinking in Java 第十二章“Java I/O系统”要点总结

https://blog.csdn.net/weixin_38967434/article/details/80084328

Thinking in Java 第十二章“Java I/O系统”要点总结

1.File类 (更准确的是叫做FilePath类,因为它并不指代一个File)

File类是对文件系统中文件以及文件夹进行封装的对象,可以通过对象的思想来操作文件和文件夹。File类保存文件或目录的各种元数据信息,包括文件名、文件长度、最后修改时间、是否可读、获取当前文件的路径名,判断指定文件是否存在、获得当前目录中的文件列表,创建、删除文件和目录等方法。 

2.输入和输出

流(stream)代表    任何有能力产出数据的数据源对象和任何有能力接受数据的受端对象

流的作用:为数据源和目的地建立一个输送通道

采用数据流的目的就是使得输出输入独立于设备。

3.InputStream 代表那些可以从不同数据源获取输入的类

数据源:bytes数组、String对象、文件、管道、多组流、网络资源。

几种装饰:

Thinking in Java 第十二章“Java I/O系统”要点总结Thinking in Java 第十二章“Java I/O系统”要点总结

4.DataInputStream和DataOutputStream的联合测试

DataInputStream一般是必须和DataOutputStream配合使用的。

writeUTF( ) 和 readUTF( )使用的是适合于 Java 的 UTF-8 变体。所以用其他的程序读writeUTF()所写的字符串,需要晋国特殊处理;而readUTF()可以直接读出来。

关键:用 available 来检查还有没有读的数据!

使用装饰者模式直接创建对象

Thinking in Java 第十二章“Java I/O系统”要点总结

写整数、小数、字符、字符串的方法。其中字符串比较麻烦一点。

Thinking in Java 第十二章“Java I/O系统”要点总结

5.ByteArrayInputStream测试

Thinking in Java 第十二章“Java I/O系统”要点总结

Thinking in Java 第十二章“Java I/O系统”要点总结

6.FileInputStream的测试

复制文件

Thinking in Java 第十二章“Java I/O系统”要点总结

读取文件中的内容

Thinking in Java 第十二章“Java I/O系统”要点总结

7.过时方法StringBufferInputStream的测试

编码会出现问题

Thinking in Java 第十二章“Java I/O系统”要点总结

8.CharArrayReader的测试

Thinking in Java 第十二章“Java I/O系统”要点总结

9.CharArrayWriter的测试

Thinking in Java 第十二章“Java I/O系统”要点总结

10.StringReader的测试

Thinking in Java 第十二章“Java I/O系统”要点总结

11.StringWriter的测试

Thinking in Java 第十二章“Java I/O系统”要点总结

12.将InputStream转化为reader

其实这个过程可以直接用 FileReader完成

Thinking in Java 第十二章“Java I/O系统”要点总结

13.将OutStram转化为Writer

直接用FileWriter完成

Thinking in Java 第十二章“Java I/O系统”要点总结

因为我的intellij idea默认编码是UTF-8 而 记事本的编码也是UTF-8 所以读写都没有问题

但是把记事本另存为Unicode的格式,那么用FileReader读这个文件中的字符就会出现乱码

Thinking in Java 第十二章“Java I/O系统”要点总结

解决:

法一:使用InputStreamReader 在InputStreamReader的构造器有第二个参数,指定字符集

Thinking in Java 第十二章“Java I/O系统”要点总结

法二:非要用FileReader的话,就只有改文件字符集了

14.字节流和字符流的区别

https://www.cnblogs.com/tech-bird/p/4122143.html

字符流处理多个字节

字节流处理单个字节

 

字节流在操作的时候本身是不会用到缓冲区(内存)的,除非你手动装饰,是与文件本身直接操作的

而字符流在操作的时候是使用到缓冲区的

 

字节流在操作文件时,即使不关闭资源(close方法),文件也能输出,

但是如果字符流不使用close方法的话,则不会输出任何内容,说明字符流用的是缓冲区,并且可以使用flush方法强制进行刷新缓冲区,这时才能在不close的情况下输出内容

15.RandomAccessFile

对象并不是流体系中的一员,其封装了字节流,同时还封装了一个缓冲区(字符数组),通过内部的指针来操作字符数组中的数据。它的父类是Object

1.    该对象只能操作文件,所以构造函数接收两种类型的参数:a.字符串文件路径;b.File对象。

2.    该对象既可以对文件进行读操作,也能进行写操作,在进行对象实例化时可指定操作模式(r,rw)

Thinking in Java 第十二章“Java I/O系统”要点总结

long getFilePointer():  获得指针位置

void seek(long pos):  指定指针位置

int skipBytes(int n):跳过多少字节

该对象在实例化时,如果要操作的文件不存在,会自动创建;如果文件存在,写数据未指定位置,会从头开始写,即覆盖原有的内容

RandomAccessFile 读写文件时,不管文件中保存的数据编码格式是什么   使用 RandomAccessFile对象方法的 readLine() 都会将编码格式转换成 ISO-8859-1 所以 输出显示是还要在进行一次转码

 

16.UTF-8和Unicode的区别

Unicode把每个字符都用两个字节保存,而UTF-8把ASCII有的字符用一个字节保存,把非ASCII嘛用2个字节保存

Thinking in Java 第十二章“Java I/O系统”要点总结

Thinking in Java 第十二章“Java I/O系统”要点总结

17.标准I/O

System.out   System,err :均被包装成   PrintStream

可以把PrintStream转化为PrintWriter: 

Thinking in Java 第十二章“Java I/O系统”要点总结

System.in :是个未被包装的   InputStream

18.标准I/O的重定向

这样可以把异常信息输出到本地文件

Thinking in Java 第十二章“Java I/O系统”要点总结

同样的,可以把标准输出和输入流都改变

Thinking in Java 第十二章“Java I/O系统”要点总结

 

Thinking in Java 第十二章“Java I/O系统”要点总结

19. 新的I/O  new I/O

基础是     java.lang.nio.ByteBuffer  : 它是一个非常“低级的对象”,它只能put或者get byte或基础类型,但是它不能put或get对象Object,连String也不行。

FileInputStream 、 FileOutputStream 、 RandomAccessFile 都可以产生一个通道 FileChannel 。这三个类都是操作字节流,和底层的nio一样。通道是一种相 当基础的东西:我们可以向它传送用于读写的 ByteBuffer。

20.FileChannel类

1.将用于读写的ByteBuffer传入Channel。将数据传入ByteBuffer的方法:1.用put方法(较少);2.用wrap方法,将byte包装进去。

2.分配一个ByteBuffer空间: ByteBuffer buffer  = ByteBuffer.allocate(int size);   nio 的目 标就是要快速移动大量数据,因此 ByteBuffer 的大小就显得尤为重要,size时byte数组的容量。

也可以使用allocateDirect( ) ,这回产生一个于产生一个在更 高层次上耦合操作系统的“直接”缓冲器。但是,这种分配的开支会更大。

3.想往ByteBuffer里面装东西时,记得调用      buffer.clear();想从ByteBuffer里面拿东西出来时,记得调用  buffer.flip() 让buffer做好准备。

4.ByteBuffer的hasRemaining方法,可以判断ByteBuffer里面position和limit之间还有没有字节。

5.ByteBuffer的get方法可以获得一个字节。

6.ByteBuffer的rewind方法可以让指针回到最开头

7.ByteBuffer的asCharBuffer、asIntBuffer、asDoubleBuffer等。

21.transferTo和transferFrom

这两个方法将两个通道连在一起,很容易实现文件的复制。

Thinking in Java 第十二章“Java I/O系统”要点总结

22. CharBuffer类

可以将ByteBuffer类转化为CharBuffer类。 1.使用ByteBuffer的asCharBuffer方法。2.CharSet.forName(字符集名字).decode(ByteBuffer buffer)。

CharBuffer有个toString方法,可以将CharBuffer存储的字符拼成一个字符串然后返回。需要自己设计解码器。

Thinking in Java 第十二章“Java I/O系统”要点总结

23.flip方法

Flips this buffer. The limit is set to the current position and then the position is set to zero. If the mark is defined then it is discarded.

24.IntBuffer类(基础类型的Buffer类)

Thinking in Java 第十二章“Java I/O系统”要点总结Thinking in Java 第十二章“Java I/O系统”要点总结

25.视图缓冲器

as基本类型Buffer 可以按照基本类型的大小操作ByteBuffer , 比较方便,

Thinking in Java 第十二章“Java I/O系统”要点总结

26.Endians

Big Endians:高位优先

Little Endians:低位优先

Thinking in Java 第十二章“Java I/O系统”要点总结

27.几个属性:mark、position、limit、capacity

mark:标志,默认是-1 。可以用,mark()方法设置标志位。并用reset()方法使得position移动到mark位

position:当前位置,调用put方法会移动position位。

limit:不调用flip()就是capacity。调用flip后,即为position。(flip:limit=position;postion=0;)

capacity:Buffer的长度。

28.MappedByteBuffer

https://www.jianshu.com/p/f90866dcbffc

https://blog.csdn.net/whoamiyang/article/details/53365385

https://www.cnblogs.com/huanxiyun/articles/5443754.html

https://blog.csdn.net/im_cheer/article/details/78409573

可以说MMap就是省略了内核空间和用户空间的数据交换

这个类让我们可以把很大的文件都看成一个Byte数组。因为他可以看截取想要的部分出来修改。

Thinking in Java 第十二章“Java I/O系统”要点总结

29.性能测试

Thinking in Java 第十二章“Java I/O系统”要点总结

内存映射文件是由一个文件到一块内存的映射,使进程虚拟地址空间的某个区域与磁盘上某个文件的部分或全部内容的建立映射。
建立映射后,通过该区域可以直接对被映射的磁盘文件进行访问.而不必执行文件I/O操作也无需对文件内容进行缓冲处理。
就好像整个被映射的文件都加载到了内存一样,因此内存文件映射非常适合于用来管理大文件。

30.文件锁

由于进程还没学到,所以现在先不学此部分内容。

31.文件压缩

GZIPOutputStream和GZIPInputStream。前者可以用来压缩数据,后者可以用来解压数据。

Thinking in Java 第十二章“Java I/O系统”要点总结

这样可以把数据压缩到compress里面。

Thinking in Java 第十二章“Java I/O系统”要点总结

这样可以解压到stream4里面。

压缩过的流,必须要解压才能出现想要的内容:

Thinking in Java 第十二章“Java I/O系统”要点总结

32.ZIP

关于添加压缩文件:

ZIPOutputStream里面的putNextEntry(ZIPEntry entry)方法提醒系统马上往压缩包里面添加一个新的文件。

然后调用write方法即可。

Thinking in Java 第十二章“Java I/O系统”要点总结

关于抽取压缩文件:

用ZIPEntry来遍历。

Thinking in Java 第十二章“Java I/O系统”要点总结

对于每一个要加入压缩文档的文件,都必须调用 putNextEntry(),并将其传递给一个 ZipEntry 对象。ZipEntry 对象包含了一个功能广泛的接口,允许你获取和设置 Zip 文件 内该特定项上所有可利用的数据:名字、压缩的和未压缩的文件大小、日期、CRC 校验和、 额外域的数据、注释、压缩方法以及它是否是一个目录入口等等。然而,即使 Zip 格式提 供了设置密码的方法,但 Java 的 Zip 类库并不提供这方面的支持。

33.java文档文件jar

Zip 格式也被应用于 JAR(Java ARchive)文件格式中。这种文件格式就象 Zip 一样可以 将一组文件压缩到单个压缩文件中。同 Java 中其他任何东西一样,JAR 文件是跨平台的, 所以不必担心跨平台的问题。声音和图像文件可以像类文件一样被包含在其中。 
JAR 文件非常有用,尤其是在涉及因特网应用的时候。如果不采用 JAR 文件,Web 浏览器 为了下载构成一个应用的所有文件时必须重复多次请求 Web 服务器。而且所有这些文件都 是未经压缩的。如果将所有这些文件合并到一个 JAR 文件中,只需向远程服务器发出一次 请求即可。同时,由于采用了压缩技术,可以使传输时间更短。另外,出于安全的考虑,JAR 文件中的每个条目都可以加上数字化签名

34.对象序列化

Java 的对象序列化(Object Serialization)将那些实现了 Serializable 接口的对象转换 成一个字节序列,并可以在以后将这个字节序列完全恢复为原来的对象。这一过程甚至可通 过网络进行。这意味着序列化机制能自动弥补不同操作系统之间的差异。在windows操作系统下序列化的东西可以直接在linux下使用。

实现轻量级持久化

持久化:一个对象的生存周期并不取决于程序是否 正在执行。在城西中通过将序列化对象写入磁盘,就可以在重新调用该程序时恢复该对象。

轻量级:对象必须在程序中显式地序列化和重组。

只要对象实现了 Serializable 接口(该接口仅是一个标记接口,不包括任何方法),对象的 序列化处理就会非常简单。为了序列化一个对象,首先要创建某些 OutputStream 对象,然后将其封装在一个 ObjectOutputStream 对象内。这时,只需调用 writeObject()即可将对象序列化,并将 其发送给 OutputStream。要将一个序列重组为一个对象,需要将一个 InputStream 封 装在 ObjectInputStream 内,然后调用 readObject()。和往常一样,我们后获得的是 指向一个向上转型为 Object 的句柄,所以必须向下转型,以便能够直接对其进行设置。 对象序列化特别“聪明”的一个地方是它不仅保存了对象的“全景图”,而且能追踪对象内包含 的所有引用并保存那些对象;接着又能对每个这样的对象内包含的引用进行追踪;以此类推。 

Thinking in Java 第十二章“Java I/O系统”要点总结

Thinking in Java 第十二章“Java I/O系统”要点总结

Thinking in Java 第十二章“Java I/O系统”要点总结

使用对象序列化,必须得保证JVM里面有相关的.class文件

35.能够控制的序列化

Serializable对象完全以二进制位为基础重组,不调用构造器

Externalizable对象会调用缺省构造器,建立该对象,域里面的值,如果不在externalWrite和externalRead里面做处理,就会是默认值(int就是0,对象就是null)

Thinking in Java 第十二章“Java I/O系统”要点总结

Thinking in Java 第十二章“Java I/O系统”要点总结

Thinking in Java 第十二章“Java I/O系统”要点总结

注意,这里的User的构造器必须是public的。

36.transient关键字

如果有些不想序列化的数据(例如密码),那么就需要特殊处理:

1.使用Externalizable接口,这样就可以保存我们想要的信息。

2.在Serializable对象中,使用transient关键字关闭序列化。(在域中可以直接声明)

Thinking in Java 第十二章“Java I/O系统”要点总结

37.替代Externalizable

如果我们不是特别想要实现 Externalizable 接口,那么就还有另一种方法。我们可以实现 Serializable 接口,并添加(注意我说的是“添加”,而非“重载”或者“实现”)名为 writeObject()和 readObject()的方法。这样一旦对象被序列化或者被反序列化,就会自 动地分别调用这两个方法。也就是说,只要我们提供了这两个方法,就会使用它们而不是缺 省的序列化机制。 
这些方法必须具有准确的方法签名: 

private void writeObject(ObjectOutputStream stream) throws IOException; 
 
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException

在你调用 ObjectOutputStream.writeObject( )时,会检查你所传递的 Serializable 对 象,看看是否实现了它自己的 writeObject( )。如果是这样,就跳过正常的序列化过程并 调用它的 writeObject( )。readObject( )的情形与此相同。 

transient域也可以被序列化:在自己写的writeObject方法和readObject方法里面,先调用defaultWriteObject和defaultReadObject方法进行transient域的序列化,然后在第二步可以手动地将transient域序列化。

38.可以利用序列化来实现deep copy,因为恢复的时候会产生不一样的对象。

39.静态数据手动序列化

40.正则表达式、标记模式

Pattern p = Pattern.compile(String regex);

boolean p.matcher(待判断).matches();

41.写入文件时,换行符是\r\n 而不是\n