13.流与文件

1.流

1.1 概述

  • java将所有的输入输出使用流进行操作
  • InputOutput都是相对于程序的。比如从一个文件读取信息对于程序来说是读数据进程序,程序通过流往文本写数据是Output
  • 输入输出可能来自文件、网络、zip包等,所以流也有多种实现。
  • 但是所有流都继承于抽象的InputStream和OutputStream
  • 流的读写在需要读取的数据读取完毕时,没有数据可读时,可能会阻塞,因此使用完流之后要close,否则将会耗尽cpu资源
  • output流的flush将缓冲区的数据写进目标,并刷新缓冲区

1.2流的家族

  • 按处理字符和字节的方式区分
    • InputStreamOutputStream
  • 对于读取``unicode`文本--也就是读取字符
    • Reader和Writer

1.3 FileInputStream和FileOutputStream

  • 所有在java.io中的类都将相对路径名解释为以用户工作目录开始,你可以通过调用System.getProperty("user.dir")来获得这个信息
·FileInputStream(String name)
·FileInputStream(File file)
使用由name字符串或file对象指定路径名的文件创建一个新的文件输入流。非绝对的路径名将按照相对于VM启动时所设置的工作目录来解析。
java.io.FileOutputStream 1.0
·FileOutputStream(String name)
·FileOutputStream(String name,boolean append)
·FileOutputStream(File file)
·FileOutputStream(File file,boolean append)
使用由name字符串或file对象指定路径名的文件创建一个新的文件输出流(File类在本章结尾处描述)。如果append参数为true,那么数据将被添加到文件尾,而具有相同名字的已有文件不会被删除;否则,这个方法会删除所有具有相同名字的已有文件。
1.3.1组合流过滤器
  • 先看下面一些流
java.io.BufferedInputStream 1.0
·BufferedInputStream(InputStream in)
创建一个带缓冲区的流。带缓冲区的输入流在从流中读入字符时,不会每次都对设备访问。当缓冲区为空时,会向缓冲区中读入一个新的数据块。
java.io.BufferedOutputStream 1.0
·BufferedOutputStream(OutputStream out)
创建一个带缓冲区的流。带缓冲区的输出流在收集要写出的字符时,不会每次都对设备访问。当缓冲区填满或当流被冲刷时,数据就被写出。
java.io.PushbackInputStream 1.0
·PushbackInputStream(InputStream in)
·PushbackInputStream(InputStream in,int size)
构建一个可以预览一个字节或者具有指定尺寸的回推缓冲区的流。
·void unread(int b)回推一个字节,它可以在下次调用read时被再次获取。参数:b 要再次读入的字节。
  • 一种流只有符合他自己特性的一些操作,比如FileInputStream只有对文件进行读取,但是无法读取数字,而DataInputStream无法读取文件,只能读取数字。向要从文件中读取数字,就需要用到组合流过滤器
  • 可以将多个流进行嵌套
FileInputStream fis = new FileInputStream("java.text");
DataInputStream dis = new DataInputStream(fis);
Double num = dis.readDouble();

2.文本的输入与输出

  • 数据“1234”可以存成文本“1234”或者二进制的形式
  • 文本便于人们阅读,二进制形式便于高效传输,但是不便于人们阅读
  • 存储文本时,需要考虑字符编码格式

2.1 字符编码

  • ASCII

    • 统一规定了常用符号、字母等用哪些二进制数来表示
    • 最初由美国制定,后来本定为国际标准,称为ISO 646标准。适用于所有拉丁文字字母 。
    • ASCII 码使用指定的7 位或8 位二进制数组合来表示128 或256 种可能的字符
  • Unicode

    • Unicode码扩展自ASCII字元集,使用16位二进制数表示字符
    • Unicode 编码共有三种具体实现,分别为utf-8,utf-16,utf-32,其中utf-8占用一到四个字节,utf-16占用二或四个字节,utf-32占用四个字节
    • 码点
      • 一个字符集一般可以用一张或多张由多个行和多个列所构成的二维表来表示
      • 二维表中行与列相交的点,称之为码点(Code Point代码点),
      • 每个码点分配一个唯一的编号,称之为码点值或码点编号
    • 码元
      • 在计算机存储和网络传输时,码点值(即字符编号)被映射到一个或多个码元(Code Unit代码单元、编码单元)
      • 而码元的实质,就是机器硬件层面(汇编语言)的数据类型;不同的码元,代表着不同位数的数据类型:比如char、int等

    参考:Unicode字符集的编码方式以及码点、码元

2.2 文本如何输出-以文本格式写出数据,需要使用PrintWriter

  • OutputStreamWriter类将使用选定的字符编码方式,把Unicode字符流转换为字节流。而InputStreamReader类将包含字节(用某种字符编码方式表示的字符)的输入流转换为可以产生Unicode码元的读入器
java.io.PrintWriter 1.1
·PrintWriter(Writer out)
·PrintWriter(Writer out,boolean autoFlush)
创建一个新的PrintWriter。
参数:out 一个用于字符输出的写出器
autoflush 如果为true,则println方法将冲刷输出缓冲区(默认值:false)
·PrintWriter(OutputStream out)
·PrintWriter(OutputStream out,boolean autoflush)
通过创建必需的中介OutputStreamWriter,从已有的OutputStream中创建一个新的PrintWriter。·PrintWriter(String filename)
·PrintWriter(File file)
通过创建必需的中介FileWriter,创建一个向给定的文件写出的新的PrintWriter。
·void print(Object obj)
通过打印从toString产生的字符串来打印一个对象。
参数:obj 要打印的对象·void 
·boolean checkError()如果产生格式化或输出错误,则返回true。一旦这个流碰到了错误,它就受到了污染,并且所有对checkError的调用都将返回true。

2.3 文本如何输入

  • 在Java SE 5.0之前,处理文本输入的惟一方式就是通过BufferedReader类,它拥有一个readLine方法,使得我们可以读入一行文本。你需要将带缓冲区的读入器与输入源组合起来
  • BufferedReader没有任何用于读入数字的方法,我们建议你使用Scanner来读入文本输入

3.读写二进制数据

3.1 写二进制数据--DataOutputStream

  • Tips:根据你所使用的处理器类型,在内存存储整数和浮点数有两种不同的方法
    • 在Java中,所有的值都按照高位在前的模式写出,不管使用何种处理器,这使得Java数据文件可以独立于平台。
    • 假设你使用的是4字节的int,如果有一个十进制数1234,也就是十六进制的4D2(1234=4×256+13×16+2),那么它可以按照内存中4字节的第一个字节存储最高位字节的方式来存储为:000004D2,这就是所谓的高位在前顺序(MSB)
    • 我们也可以从最低位字节开始:D2040000,这种方式自然就是所谓的低位在前顺序(LSB)
    • C、C++会根据底层处理器来选择使用MSB还是LSB,但是java不会。java总是按照高位在前的模式

3.2 读取二进制数据--DataInputStream

4.ZIP文档

4.1 ZIP文档头

  • 包含了每个压缩的每个文件的名字和压缩方法等信息

4.2如何读取ZIP文档--ZipInputStream

  • 由多个ZipEntry对象组成,实际是getNextEntry方法获取所有的ZipEntry对象遍历。
  • read方法被修改为在碰到当前项的结尾时返回-1(而不是碰到ZIP文件的末尾),然后你必须调用closeEntry来读入下一项
java.util.zip.ZipInputStream 1.1
·ZipInputStream(InputStream in)
创建一个ZipInputStream,使得我们可以从给定的InputStream向其中填充数据。
·ZipEntry getNextEntry()
为下一项返回ZipEntry对象,或者在没有更多的项时返回null。
·void closeEntry()关闭这个ZIP文件中当前打开的项。之后可以通过使用getNextEntry()读入下一项。

4.3如何写入--ZipOutputStream

  • 每一项你想写进去的文件构造一个包含文件名、解压缩方法、文件日期等属性的ZipEntry对象
  • 需要调用ZipOutputStreamputNextEntry方法来开始写出新文件,并将文件数据发送到ZIP流中
  • 当完成时,需要调用closeEntry
java.util.zip.ZipOutputStream 1.1
·ZipOutputStream(OutputStream out)
创建一个将压缩数据写出到指定的OutputStream的ZipOutputStream。
·void putNextEntry(ZipEntry ze)
将给定的ZipEntry中的信息写出到流中,并定位用于写出数据的流,然后这些数据可以通过write()写出到这个流中。·void closeEntry()
关闭这个ZIP文件中当前打开的项。使用putNextEntry方法可以开始下一项。
·void setLevel(int level)
设置后续的各个DEFLATED项的默认压缩级别。这里默认值是Deflater.DEFAULT_COMPRESSION。如果级别无效,则抛出IllegalArgumentException。参数:level 压缩级别,从0(NO_COMPRESSION)到9(BEST_COMPRESSION)
·void setMethod(int method)
设置用于这个ZipOutputStream的默认压缩方法,这个压缩方法会作用于所有没有指定压缩方法的项上。参数:method 压缩方法,DEFLATED或STORED

5.对象流与序列化

  • 如何保存对象的信息呢?--对象流

5.1对象的保存和读取

  • ObjectOutputStreamObjectInputStream
  • 希望在对象流中存储或恢复的所有类都应进行一下修改,这些类必须实现Serializable接口

5.2序列号

  • 每个对象都是用一个序列号(serial number)保存的,这就是这种机制之所以称为对象序列化的原因
  • 序列号解决一个对象被多个对象引用的问题
  • 根据序列号写入时
    • 当第一次保存一个对象A时,生成序列号,保存其相应信息
    • 再次遇到序列号相同的对象时,标记与之前写过的对象相同
  • 根据序列号读出时
    • 第一次读取对象A时,构建它,并记录序列号与该对象的关系
    • 再次遇到序列号相同的对象,直接获取与该序列号相同的对象引用

5.3ObjectOutputStream

java.io.ObjectOutputStream 1.1
·ObjectOutputStream(OutputStream out)
创建一个ObjectOutputStream使得你可以将对象写出到指定的OutputStream。
·void writeObject(Object obj)
写出指定的对象到ObjectOutputStream,这个方法将存储指定对象的类、类的签名以及这个类及其超类中所有非静态和非瞬时的域的值。

5.4ObjectInputStream

java.io.ObjectInputStream 1.1
·ObjectInputStream(InputStream in)
创建一个ObjectInputStream用于从指定的InputStream中读回对象信息。
·Object readObject()
从ObjectInputStream中读入一个对象。特别是,这个方法会读回对象的类、类的签名以及这个类及其超类中所有非静态和非瞬时的域的值。它执行的反序列化允许恢复多个对象引用。

6.操作文件

7.内存映射文件

8.正则表达式

9.参考

1:Unicode字符集的编码方式以及码点、码元

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 本文内容非原创,你可以点击此处查看内容来源声明 输入/输出流 在Java API中,可以从其中读出一个字节序列的对...
    _gitignore阅读 2,658评论 0 0
  • 官网 中文版本 好的网站 Content-type: text/htmlBASH Section: User ...
    不排版阅读 4,537评论 0 5
  • 五、IO流 1、IO流概述 (1)用来处理设备(硬盘,控制台,内存)间的数据。(2)java中对数据的操作都是通过...
    佘大将军阅读 545评论 0 0
  • Java中是通过流的方式对数据进行操作,用于操作流的类都在IO包中,IO流用来处理设备之间的数据传输。IO流按照流...
    阿Q说代码阅读 1,603评论 0 1
  • C/C++输入输出流总结 前两天写C++实习作业,突然发现I/O是那么的陌生,打了好长时间的文件都没有打开,今天终...
    LuckTime阅读 1,764评论 0 6