首页 如何调整javaTM 的IO性能(1)

如何调整javaTM 的IO性能(1)

举报
开通vip

如何调整javaTM 的IO性能(1)如何调整javaTM 的IO性能(1) 如何调整javaTM 的性能 这篇文章讨论并举例阐述了提高JavaTM I/O性能的多种技术。绝大多数技术是围绕着磁盘文件I/O的调整来谈 的,但是,有些技术对网络I/O和视窗输出也同样适用。首先介绍的技术包含底层I/O问题,然后对诸如压 缩、格式化和序列化这样的高层I/O进行讨论。但是,请注意,本讨论不涉及应用设计问题, 搜索算法和数 据结构的选择,也不讨论类似文件高速缓存(file caching)这样的系统级问题。 当讨论Java I/O时,Java编程语言所假定...

如何调整javaTM 的IO性能(1)
如何调整javaTM 的IO性能(1) 如何调整javaTM 的性能 这篇文章讨论并举例阐述了提高JavaTM I/O性能的多种技术。绝大多数技术是围绕着磁盘文件I/O的调整来谈 的,但是,有些技术对网络I/O和视窗输出也同样适用。首先介绍的技术包含底层I/O问题,然后对诸如压 缩、格式化和序列化这样的高层I/O进行讨论。但是,请注意,本讨论不涉及应用设计问题, 搜索算法和数 据结构的选择,也不讨论类似文件高速缓存(file caching)这样的系统级问题。 当讨论Java I/O时,Java编程语言所假定的两种不同的磁盘文件组织是没有任何意义的。这两种磁盘文件组 织,一种基于字节流,另一种基于字符序列。在 Java语言中,一个字符使用两个字节表示,而不是象C语言 那样使用一个字节表示一个字符。正因为如此,从文件中读取字符时需要一些转换。在某些情况下,这样的 区别非常重要,我们将用几个例子对此进行说明。 底层I/O问题 简介 加速I/O的基本规则 缓冲 读/写文本文件 格式化的开销 随机存储 高层I/O问题 压缩 高速缓存 标志化(Tokenization) 序列化(Serialization) 获取文件信息 更多的信息 加速I/O的基本规则 作为开始讨论的一种方法,下面列出了加速I/O的一些基本规则: 1.避免访问磁盘 2.避免访问下面的操作系统 3.避免方法调用 4.避免对字节和字符的单独处理 显然,这些规则不能被全面而严格地应用,因为如果那样的话,I/O就不可能工作了。 但是,为了查看规则是 如何被应用的,就考虑下面的三个例子,这些例子计算一个文 件中换行符('\n')的数目。 方法一:读取的方法 第一个方法简单地利用一个文件输入流(FileInputStream)上的读方法: import java.io.*; public class intro1 { public static void main(String args[]) { if (args.length != 1) { System.err.println("missing filename"); System.exit(1); } try { FileInputStream fis = new FileInputStream(args[0]); int cnt = 0; int b; while ((b = fis.read()) != -1) { if (b == '\n') cnt++; } fis.close(); System.out.println(cnt); } catch (IOException e) { System.err.println(e); } } } 然而,这个方法触发了大量对底层运行系统的调用,这就是FileInputStream.read, 返回文件下一个字节的本 机方法。 方法二:采用一个大缓冲区 第二种方法通过采用一个大缓冲区,避免了上述问题: import java.io.*; public class intro2 { public static void main(String args[]) { if (args.length != 1) { System.err.println("missing filename"); System.exit(1); } try { FileInputStream fis = new FileInputStream(args[0]); BufferedInputStream bis = new BufferedInputStream(fis); int cnt = 0; int b; while ((b = bis.read()) != -1) { if (b == '\n') cnt++; } bis.close(); System.out.println(cnt); } catch (IOException e) { System.err.println(e); } } } BufferedInputStream.read从输入缓冲区中获取下一个字节,极少访问底层系统。 方法三:直接缓冲(Direct Buffering) 第三种方法避免使用缓冲的输入流(BufferedInputStream),而直接进行缓冲,因此避免 了读取方法的调用: import java.io.*; public class intro3 { public static void main(String args[]) { if (args.length != 1) { System.err.println("missing filename"); System.exit(1); } try { FileInputStream fis = new FileInputStream(args[0]); byte buf[] = new byte[2048]; int cnt = 0; int n; while ((n = fis.read(buf)) != -1) { for (int i = 0; i < n; i++) { if (buf[i] == '\n') cnt++; } } fis.close(); System.out.println(cnt); } catch (IOException e) { System.err.println(e); } } } 对于1MB的输入文件,以秒为单位,各个程序的执行时间为: intro1 6.9 intro2 0.9 intro3 0.4 或者,在最快和最慢之间存在一个17比1的差距。 这巨大的加速性能并没有必然地 证明 住所证明下载场所使用证明下载诊断证明下载住所证明下载爱问住所证明下载爱问 ,应该总是效仿第三种方法,因为此方法中需要自己进行缓冲。如果事 先没有进行仔细的实现,这样的方法可能容易造成错误,特别是在处理文件结束 (end-of-file)事件时。它 也可能在可读性上比其他的方法差。但是,记住时间都花费到什么地方去了,记住在需要时如何纠正是很有 用的。 对绝大多数应用程序而言,方法二可能是正确的选择。 缓冲 方法二和方法三使用了缓冲技术,其中,文件中的一整块从磁盘中读取出来,然后再一 次一个字节或者字符 地进行访问。缓冲是加速I/O的一种基本和重要的技术,而且许 多Java类都支持缓冲(BufferedInputStream用于 字节,BufferedReader用于字符)。 一个明显的问题是:是否缓冲区越大就能够使I/O越快呢,Java缓冲区典型的缺省值是 1024或者2048个字节。 大于此值的缓冲区可能能够帮助加速I/O,但通常只有几个 百分点,即5%到10%。 方法四:整个文件 这个极端的例子需要确定文件的长度,然后将整个文件读取到缓冲区中。 import java.io.*; public class readfile { public static void main(String args[]) { if (args.length != 1) { System.err.println("missing filename"); System.exit(1); } try { int len = (int)(new File(args[0]).length()); FileInputStream fis = new FileInputStream(args[0]); byte buf[] = new byte[len]; fis.read(buf); fis.close(); int cnt = 0; for (int i = 0; i < len; i++) { if (buf[i] == '\n') cnt++; } System.out.println(cnt); } catch (IOException e) { System.err.println(e); } } } 这种方法很方便,因为文件可以被当作字节数组来对待。但是,一个明显的问题是可能没有足够的内存来读 取一个非常大的文件。 缓冲的另一方面涉及到终端窗口的文本输出。缺省情况下,System.out(一 个打印流——PrintStream)是行缓 冲的,也就是说,当遇到一个换行符时输出队列被清空。对于交互式应用来说,这是很重要的,阅 赡芟不 对谑导适输入前,有一个输入提示符。 方法五:禁止行缓冲 但是行缓冲可以被禁止,正如下面例子中所示的: import java.io.*; public class bufout { public static void main(String args[]) { FileOutputStream fdout = new FileOutputStream(FileDescriptor.out); BufferedOutputStream bos = new BufferedOutputStream(fdout, 1024); PrintStream ps = new PrintStream(bos, false); System.setOut(ps); final int N = 100000; for (int i = 1; i <= N; i++) System.out.println(i); ps.close(); } } 该程序输出整数1至100000,并且比使用行缓冲的程序快三倍。 缓冲也是下面几个例 子之一的一个重要部分,其中缓冲区被用来加速对随机文件的访问。 读/写文本文件 先前提及的一个想法是,在从文件中读取字符时,方法调用的系统开销非常可观。这种 情况的另一个例子可 以在这样一个程序中找到,该程序计算一个文本文件的行数。 import java.io.*; public class line1 { public static void main(String args[]) { if (args.length != 1) { System.err.println("missing filename"); System.exit(1); } try { FileInputStream fis = new FileInputStream(args[0]); BufferedInputStream bis = new BufferedInputStream(fis); DataInputStream dis = new DataInputStream(bis); int cnt = 0; while (dis.readLine() != null) cnt++; dis.close(); System.out.println(cnt); } catch (IOException e) { System.err.println(e); } } } 这个程序使用老版本的DataInputStream.readLine方法,该方法的实现是通过使用读取 方法调用来获得每个字 符。一个更新的方法是: import java.io.*; public class line2 { public static void main(String args[]) { if (args.length != 1) { System.err.println("missing filename"); System.exit(1); } try { FileReader fr = new FileReader(args[0]); BufferedReader br = new BufferedReader(fr); int cnt = 0; while (br.readLine() != null) cnt++; br.close(); System.out.println(cnt); } catch (IOException e) { System.err.println(e); } } } 这种方法能够快一些。例如,对于6MB字节200,000行的文本文件,第二个程序比第一个大约快20%。 但是,即使是第二个程序,也并不够快,这里有一个重要问题值得注意。第一个程序在Javatm 2编译器上会 导致一个严厉的警告,这是因为DataInputStream.readLine太陈旧了,不能正确地将字节转换为字符,并且也不 是操作某些包含有非ASCII字节文本文件的恰当选 择,(请注意,Java语言使用Unicode字符集,而不是 ASCII字符集)。 前面提到的字节流和字符流的不同,在下列程序中产生了效果: import java.io.*; public class conv1 { public static void main(String args[]) { try { FileOutputStream fos = new FileOutputStream("out1"); PrintStream ps = new PrintStream(fos); ps.println("\uffff\u4321\u1234"); ps.close(); } catch (IOException e) { System.err.println(e); } } } 写入一个输出文件,但没有保留实际输出的Unicode字符。读/写I/O类是基于字符的,并且是设计用来解决这 个问题的。在OutputStreamWriter中,薪 辛舜幼址 蜃纸诘谋嗦胱 弧? 使用PrintWriter输出Unicode字符的程序看上去象这样: import java.io.*; public class conv2 { public static void main(String args[]) { try { FileOutputStream fos = new FileOutputStream("out2"); OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF8"); PrintWriter pw = new PrintWriter(osw); pw.println("\uffff\u4321\u1234"); pw.close(); } catch (IOException e) { System.err.println(e); } } }
本文档为【如何调整javaTM 的IO性能&#40;1&#41;】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_998870
暂无简介~
格式:doc
大小:30KB
软件:Word
页数:13
分类:其他高等教育
上传时间:2017-09-27
浏览量:8