java流与文件——流

来源:互联网 发布:天界法宝升阶数据 编辑:程序博客网 时间:2024/04/30 20:03

【0】README

0.1) 本文描述转自 core java volume 2, 旨在理解 java流与文件——流 的相关知识;
0.2) 输入流和输出流(InputStream 和 OutputStream传输单位是基于单字节):

  • 0.2.1)输入流:可以从其中读入一个字节序列的对象,这个其中就叫做输入流,即我们可以从输入流中读入一个字节序列的对象;
  • 0.2.2)输出流:可以从其中写出一个字节序列的对象,这个其中就叫做输出流,即我们可以从输出流中写出一个字节序列的对象;
  • 0.2.3)抽象类 InputStream 和 OutputStream 构成了 输入输出类层次结构的基础;

0.3)引入 抽象类Reader 和 Writer(传输单位是基于两字节的Unicode码元,每次只传递一个字符,见read和write方法)

  • 0.3.1)problem: 因为面向字节的流不便于处理以 Unicode 形式存储的信息;
  • 0.3.2)solution:所以从抽象类 Reader 和 Writer 中继承出来了一个专门用于处理 Unicode字符的单独的类层次结构。这些类拥有的读入和写出操作都是基于两字节的 Unicode码元的, 而不是基于单字节的字符;(干货——Unicode码元==Unicode字符==两字节)

【1】读写字节

1.1)InputStream 类有一个抽象方法: abstract int read()
1.2)OutputStream类有抽象方法: abstract void write(int b)
1.3) read 和 write 方法 在执行时都将阻塞,直到字节确实被读入或写出;这意味着如果流不能被立即访问,则当前线程被阻塞;

  • 1.3.1)available 方法: 可以检查当前可读入的字节数量;
  • 1.3.2)close方法: 完成对流的读写后,用close 方法关闭它;且关闭一个输出流的同时还会冲刷(flush)缓冲区;
    缓冲区:所有被临时置于缓冲区中, 以便用更大的包的形式传递的字符在关闭输出流时被送出, 同时减少了访问硬盘的次数)(干货——缓冲区的定义和作用)
    • 1.3.2.1)如果不关闭文件, 那么写出字节的最后一个包可能将永远也不会传递出去;
  • 1.3.3)flush方法: 冲洗缓冲区的数据到流中,最后到达文件;

【2】完整的流家族

(图片来源: http://blog.csdn.net/hguisu/article/details/7418161)
这里写图片描述
2.1)InputStream 和 OutputStream

  • 2.1.1)DataInputStream 和 DataOutputStream: 可以以二进制格式读写所有的基本java类型;
  • 2.1.2)ZipInputStream 和 ZipOutputStream : 以常见的ZIP 压缩格式读写文件;
![这里写图片描述](http://img.blog.csdn.net/20160112133712321)**2.2)Reader 和 Writer*** **2.2.1)read 方法:** 返回一个 Unicode 码元(一个在0 ~ 65535 间的整数), 或在碰到文件结尾时返回-1;* **2.2.2)write 方法:** 被调用时, 需要传递一个Unicode码元;![这里写图片描述](http://img.blog.csdn.net/20160112133811813)![这里写图片描述](http://img.blog.csdn.net/20160112133821368)**2.3)还有4个附加的接口: Closeable, Flushable, Readable, Appendable。** * **2.3.1)前两个接口非常简单, 它们分别拥有下面的方法:** close 和 flush 方法;* **2.3.2)InputStream, OutputStream , Read 和 Writer 都实现了 Closeable 接口;****Attention)*** **A1)** Closeable 接口 extends AutoCloseable 接口, 因此对任何Closeable 进行操作时,都可以使用带资源的try 语句;**(干货——使用带资源的try 语句的条件是该类或接口要继承AutoCloseable接口)*** **A2)为什么要有两个接口呢?** 因为 Closeable 接口的close方法只抛出IOException, 而 AutoCloseable.close 可以抛出任何异常;* **2.3.3)** OutputStream 和 Writer 还实现了 Flushable 接口* **2.3.4)Readable 接口只有一个方法:** int read(CharBuffer cb) * **2.3.4.1)CharBuffer 类:** 拥有按照顺序和随机地进行读写访问的方法, 它表示一个内存中的缓冲区或者一个内存映像的文件;* **2.3.5)Appendable 接口:有两个用于添加单个字符和字符序列的方法:** Appendable append(char c) Appendable append(CharSequence s)* **2.3.6)CharSequence 接口 :**描述了一个char 值序列的基本属性, String, CharBuffer, StringBuilder, 和 StringBuffer 都实现了它;* **2.3.7)**在流的家族中, 只有 Writer 实现了 Appendable 接口;
##**【3】组合流过滤器****3.1)FileInputStream 和 FileOutputStream:** 可以提供附着在 一个磁盘文件上的输入流和输出流, 我们只需要提供完整路径名;**Hint)** 所有在 java.io 中的类都将相对路径名解释为以用户工作目录开始, 你可以通过调用 System.getProperty(“user.dir”) 来获得这个信息;**Warning)*** **W1)**对于可移植的程序来说, 应该使用程序所运行平台的文件分隔符, 通过 常量字符串 java.io.File.separator 来获得它;* **W2)**不推荐使用 单斜杠“/” 作为文件分隔符, 而使用 “\\”;**3.2)problem 和 solution ****(干货——这是产生组合流过滤器的原因)*** **3.2.1)problem:** 如果我们只有 DataInputStream, 我们就只能读入数值类型:DataInputStream din = …double s = din.readDouble();正如 FileInputStream 没有任何读入数值类型的方法一样, DataInputStream 也没有任何从文件中读取数据的方法:* **3.2.2)solution:** java使用了一种机制来分离这两种职责。某些流(如 FileInputStream 和 由 URL 类的openStream 方法返回的输入流) 可以从文件和其它位置获取字节, 而其他的流(如 DataInputStream 和 PrintWriter) 可以将字节组装到更有用的数据类型中;* **3.2.3)我们需要对它们进行组合, 看个荔枝:**为了从文件中读取数组,需要创建一个FileInputStream , 然后将其传递给 DataInputStream 的构造器:
FileInputStream fin = new FileInputStream("a.dat");DataInputStream din = new DataInputStream(fin);double s = din.readDouble();
![这里写图片描述](http://img.blog.csdn.net/20160112134434511)**3.3)嵌套过滤器添加多重功能*** **3.3.1)请求一个数据块并将其置于缓冲区中会更加高效, 添加这种缓冲机制:**DataInputStream din = new DataInputStream(new BufferedInputStream(new FileInputStream(“a.dat”)));* **Attention)**我们把 DataInputStream 放置在 构造器链 的最后,因为我们希望 使用 DataInputStream 的方法, 并且希望它们能够带有缓冲机制的 read 方法;* **3.3.2)PushbackInputStream(可回推输入流)**PushbackInputStream pbin = new PushbackInputStream(new BufferedInputStream(new FileInputStream(“a.dat”))); * **3.3.2.1) 现在,预读下一个字节: ** int b = pbin.read(); * **3.3.2.2)如果不满足,将其推回流中: ** pbin.unread(b); * **3.3.2.3)**但是读入和推回是可应用于可回推(pushback) 输入流的仅有 的方法; * **3.3.2.4)如果你需要预先浏览并且还可以读入数字, 那么你就需要一个既是可回推输入流,又是一个数据输入流的引用;**
PushbackInputStream pbin = new PushbackInputStream(new BufferedInputStream(new FileInputStream("a.dat")));DataInputStream din = new DataInputStream(pbin);
![这里写图片描述](http://img.blog.csdn.net/20160112134500677) 注意: (转自, http://blog.csdn.net/u010700335/article/details/40155053) 如果文件串的最后一个字符是中文,使用mark()中的长度设为file.length()如果文件的最后一个字符串是英文或数字,则java.io.IOException: Mark invalid,使用mark()中的长度设为file.length()+1 mark用于标记当前位置;在读取一定数量的数据(小于readlimit的数据)后使用reset可以回到mark标记的位置;FileInputStream不支持mark/reset操作;BufferedInputStream支持此操作;mark(readlimit)的含义是在当前位置作一个标记,制定可以重新读取的最大字节数,也就是说你如果标记后读取的字节数大于readlimit,你就再也回不到回来的位置了;通常InputStream的read()返回-1后,说明到达文件尾,不能再读取。除非使用了mark/reset。。
  • 3.3.3)看个荔枝: 可以通过一个 ZIP 压缩文件中通过使用下面的流序列读入数字:
ZipInputStream zin = new ZipInputStream(new FileInputStream("a.zip"));DataInputStream din = new DataInputStream(zin);
0 0
原创粉丝点击