摘要: 本文大多技术围绕调整磁盘文件 I/O,但是有些内容也同样适合网络 I/O 和窗口输出。 第一部分技术讨论底层的I/O问题,然后讨论诸如压缩,格式化和串行化等高级I/O问题。然而这个讨论没有包含应用设计问题,例如搜索算法和数据结构,也没有讨论系统级的问题,例如文件高速缓冲。 Java语言采取两种截然不同的磁盘文件结构。一个是基于字节流,另一个是字符序列。在Java语言中一个字符有两个字节表示,而不是像通常的语言如c语言那样是一个字节。因此,从一个文件读取字符时需要进行转换。这个不同在某些情况下是很重要的,就像下面的几个例子将要展示的那样。 低级I/O相关的问题:
高级I/O问题
加速I/O的基本规则
很明显这些规则不能在所有的问题上避免,因为如果能够的话就没有实际的I/O被执行。 使用缓存减少读写次数开销 使用缓冲加速文件读取的示例: 这个巨大的加速并不能证明你应该总是使用第三种方法,即自己做缓冲。这可能是一个错误的倾向特别是在处理文件结束事件时没有仔细的实现。在可读性上它也没有其它方法好。但是记住时间花费在哪儿了以及在必要的时候如何矫正是很有用。方法2 或许是对于大多应用的 "正确" 方法. 方法 2 和 3 使用了缓冲技术, 大块文件被从磁盘读取,然后每次访问一个字节或字符。缓冲是一个基本而重要的加速I/O 的技术,而且有几个类支持缓冲(BufferedInputStream 用于字节, BufferedReader 用于字符)。 缓冲区越大I/O越快吗?典型的Java缓冲区长1024 或者 2048 字节,一个更大的缓冲区有可能加速 I/O但比重很小,大约5 到10%。 方法1: 读方法 第一个方法简单的使用FileInputStream的read方法: 方法 2: 使用大缓冲区 第二种方法使用大缓冲区避免了上面的问题: 方法 3: 直接缓冲 方法4: 缓冲整个文件 对于一个1 MB的输入文件,以秒为单位的执行时间是:FileInputStream的read方法,每次读取一个字节,不用缓冲 6.9秒 BufferedInputStream的read方法使用BufferedInputStream 0.9秒 FileInputStream的read方法读取数据到直接缓冲 0.4秒或者说在最慢的方法和最快的方法间是17比1的不同。 这个方法很方便,在这里文件被当作一个字节数组。但是有一个明显得问题是有可能没有读取一个巨大的文件的足够的内存。 缓冲的另一个方面是向窗口终端的文本输出。缺省情况下, System.out ( 一个PrintStream) 是行缓冲的,这意味着在遇到一个新行符后输出缓冲区被提交。 |