进入旧版 | 服务项目 | 成功案例 | 联系方式 | 过客留言 | 友情链接
   
设为首页
加入收藏
联系我们
网站首页 | 新闻资讯 | 操作系统 | 办公软件 | 网络软件 | 工具软件 | 媒体动画 | 网页制作 | 网站开发 | 程序开发 | 平面设计
Photoshop视频教程 | Word入门 | Flash入门 | JScript | VBScript | ASP | PHP | ADO | 网页特效 | 3DS MAX6.0命令 | 系统进程
您当前的位置:GOODSGY电脑学习网 -> 网站开发 -> JSP -> 文章内容  
调整JavaTM 的I/O性能(一)(zt)

调整JavaTM 的I/O性能
这篇文章讨论并举例阐述了提高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);

              }

          }

      }

本程序使用了UTF8编码,它将ASCII编码为其本身,其他字符编码为两个或者三个字节。

在百度中搜索:调整JavaTM 的I/O性能(一)(zt)
在Google中搜索:调整JavaTM 的I/O性能(一)(zt)
在Yahoo中搜索:调整JavaTM 的I/O性能(一)(zt)

收藏到网摘:新浪VIVI 365key 我摘 POCO网摘 博采中心 YouNote 和讯网摘 天天收藏
[] [返回上一页] [打 印] [收 藏]

 相关文章    最新文章
· [组图] 巧用PS调整工具打造梦幻世界
· Photoshop视频教程:5.2.1 色彩调整
· [图文] 教你如何调整vista系统雅黑字体DPI..
· [图文] 调整Vista系统安全策略 让UAC更友善..
· [组图] 轻松调整DVDRip压缩电影的字幕大小..
· [组图] Photoshop图层面板调整图层图标怪问..
· [组图] Photoshop十秒钟调整曝光不足照片
· [组图] 巧用Photoshop色阶调整得到书法效果..
· [组图] Photoshop通道互换法调整照片色调
· [组图] Photoshop调整色彩饱和度欠佳的图片..
 
· 提升JSP页面响应速度的七大秘籍绝招
· 开发一个调试JSP的Eclipse插件
· JSP报表打印的一种简单解决方案
· JSP/Servlet的重定向技术综述
· java的md5加密类(zt)
· 一个用来访问http服务器的东西。功能类似..
· 菜鸟调试手记一(sql server 中文问题)
· Java性能优化技巧集锦(2)
· 用java压缩文件示例(没有中文问题)
· 使用XML/HTC/DHTML模拟标准Windows菜单

∷相关文章评论∷    (评论内容只代表网友观点,与本站立场无关!) [更多评论…]
站内搜索

精彩图文
  网站导航  
操作系统 办公软件 网络软件
Vista Windows2003 WindowsXP Windows2000/NT Windows9X/ME Linux 其他 Word Excel Powerpoint Outlook 金山系列 其他 网页浏览 上传下载 联络聊天 邮件工具 服务器软件 网络辅助
工具软件 媒体动画 网页制作
系统工具 媒体工具 压缩工具 图文处理 文件管理 其他 3DMAX Authorware Director Maya 视频处理 其他 Flash Dreamweaver FireWorks FrontPage LiveMotion Golive HTML/CSS 其它
网站开发 平面设计 程序设计
ASP JSP PHP CGI JavaScript VBScript XML/SOAP Web服务器 Photoshop PhotoImpact CorelDraw Illustrator Freehand 设计欣赏 其他 VB VC .NET C/C++ DELPHI JAVA

冀ICP备05019428号
Copyright © 2004-2008 电脑学习网 Inc.All rights reserved.
TEL:13832340607
QQ:39873155
E_Mail:goodsgy(#)hotmail.com   (把(#)替换成@)
MSN:goodsgy(#)hotmail.com   (把(#)替换成@)