Java IO详解(转)

IO是Java及众多编程语言很重要的一块,同时很多程序的瓶颈和耗时操作也都在IO这块。

一、简介

IO操作面临很多问题,信息量的巨大,网络的环境等等,因为IO不仅仅是对本地文件、目录的操作,有时对二进制流、还有一部分是网络方面的资源,所以多种原因直接造成IO操作无疑是耗时且复杂多变的。Java对IO的支持是个不断的演变过程,经过了很多的优化,直到JDK1.4以后,才趋于稳定,在JDK1.4中,加入了nio类,解决了很多性能问题,虽然我们有足够的理由不去了解关于Java IO以前的情况,但是为了学好现在的类,我们还是打算去研究下,通过掌握类的优化情况来彻底理解IO的机制!Java IO主要主要在java.io包下,分为四大块近80个类:

1、基于字节操作的I/O接口:InputStream和OutputStream

2、基于字符操作的I/O接口:Writer和Reader

3、基于磁盘操作的I/O接口:File

4、基于网络操作的I/O接口:Socket(不在java.io包下)

影响IO性能的无非就是两大因素:数据的格式及存储的方式,前两类主要是数据格式方面的,后两个类是存储方式方面的:本地和网络。所以策划好这两个方面的活动,有助于我们合理使用IO。

二、基于字节的I/O操作(InputStream和OutputStream)

我们先来看看类图:

图1

图2

二者类似,我只详细讲解InputStream类,OutputStream留给大家自己去学习。InputStream类是个抽象类,里面核心的方法就是read()、read(byte b[])、read(byte b[], int off, int len),这三个方法是用于读取数据的底层的方法,他们可以用来读取一下这些类型的数据:

A. 字节数组

B. String对象

C. 文件

D. 管道,从一端进入,从另一端输出

E. 流

F. internet资源

每一种数据源都有相应的InputStream子类,因为InputStream是个处于顶层的类,用来处理各种数据源的类都继承了InputStream类,我们来看看这些类:

ByteArrayInputStream:处理字节数组的类,允许将内存的缓冲区当做InputStream使用。

StringBufferInputStream:将String转换成InputStream,内部实现用的是StringBuffer。

FileInputStream:从文件中读取数据。

PipedInputStream:用于从管道中读取数据。

SequenceInputStream:将多个流对象转化成一个InputStream。

FilterInputStream:装饰器类,为其它InputStream类提供功能。

做过关于IO操作的读者知道,我们很少单独使用哪个类来实现IO操作,平时都是几个类合起来使用,这其实体现了一种装饰器模式(详见:http://blog.csdn.net/zhangerqing)的思想,在后面的分析中我们会详细的分析。从上面的图1中我们可以看出,FilterInputStream虽说是Inputstream的子类,但它依然是BufferedInputStream、DataInputStream、LineNumberInputStream、PushbackInputStream类的父类,这四个类分别提供了最贴近我们程序员使用的方法,如:readInt() 、readInt()、readInt()等等。对于IO操作,不管是磁盘还是网络,最终都是对字节的操作,而我们平时写的程序都是字符形式的,所以在传输的过程中需要进行转换。在字符到字节的转换过程中,我们需要用到一个类:InputStreamReader。

三、基于字符的I/O操作(Writer和Reader)

图3

图4

Writer和Reader操作的目的就是操作字符和不是字节,和InputStream和OutputStream配合增加IO效果。通过InputStreamReader和OutputStreamReader可以进行字节和字符的转换,设计Writer和Reader的目的是国际化,使IO操作支持16位的Unicode。我把它们单独的画出来,因为要是全画的话,太大了放不下,有兴趣的TX可以在rational rose中导入其带的JDK类图看看,很过瘾的!

四、基于磁盘的I/O操作(File)

五、基于网络的I/O操作(Socket)

六、NIO

四-六部分由于时间关系,还没有整理完,后续会补出来!

七、经典IO操作

1、缓冲输入文件。

[java] view plain copy

  1. import java.io.BufferedReader;
  2. import java.io.FileReader;
  3. public class InputStreamTest {
  4. public static String read(String filename) throws Exception {
  5. BufferedReader br = new BufferedReader(new FileReader(filename));
  6. String s;
  7. StringBuffer sb = new StringBuffer();
  8. while ((s = br.readLine()) != null) {
  9. sb.append(s + "\n");
  10. }
  11. br.close();
  12. return sb.toString();
  13. }
  14. public static void main(String[] args) throws Exception {
  15. System.out.println(read("src/InputStreamTest.java"));
  16. }
  17.  }

这段代码是从磁盘读入InputStreamTest.java文件,然后转换成字符串。输出就是将源文件原样输出。

2、从内存中读取。

[java] view plain copy

  1. import java.io.StringReader;
  2. public class MemoryInput {
  3. public static void main(String[] args) throws Exception {
  4. StringReader in = new StringReader(
  5. InputStreamTest.read("src/MemoryInput.java"));
  6. int c;
  7. while ((c = in.read()) != -1)
  8. System.out.println((char) c);
  9. }
  10. }

read返回的是int类型的数据,所以在输出语句中用char做了强类型转换。该程序将一个一个的输出字符。

3、基本的文件输出。

[java] view plain copy

  1. import java.io.BufferedReader;
  2. import java.io.BufferedWriter;
  3. import java.io.FileWriter;
  4. import java.io.PrintWriter;
  5. import java.io.StringReader;
  6. public class BasicFileOutput {
  7. static String file = "basie.out";
  8. public static void main(String[] args) throws Exception {
  9. BufferedReader in = new BufferedReader(new StringReader(
  10. InputStreamTest.read("src/BasicFileOutput.java")));
  11. PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(
  12. file)));
  13. int lineCount = 1;
  14. String s;
  15. while ((s = in.readLine()) != null) {
  16. out.println(lineCount++ + ": " + s);
  17. }
  18. out.close();
  19. System.out.println(InputStreamTest.read(file));
  20. }
  21. }

输出:

1: import java.io.BufferedReader;

2: import java.io.BufferedWriter;

3: import java.io.FileWriter;

4、RandomAccessFile

RandomAccessFile被我们称为”自我独立的类”,因为它独立于我们前面说的IO类,与InputStream和OutputStream没什么关系,除了实现了DataOutput, DataInput两个接口外。所有方法都是重新编写,而且很多都是native方法,我们来看个例子,了解下这个类:

5、管道流

八、标准I/O

就是我们最原始的使用的从控制台输入或者输出的那些类和方法,如System.in、System.out等。

[java] view plain copy

  1. public class StandardIO {
  2. public static void main(String[] args) throws IOException {
  3. BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
  4. String s;
  5. while ((s = in.readLine()) != null && s.length() != 0)
  6. System.out.println(s);
  7. }
  8. }

System.in返回的是未经包装的InputStream对象,所以需要进行装饰,经InputStreamReader转换为Reader对象,放入BufferedReader的构造方法中。除此之外,System.out和System.err都是直接的PriintStream对象,可直接使用。我们也可以使用java.util包下的Scanner类来代替上述程序:

[java] view plain copy

  1. public class StandardIO {
  2. public static void main(String[] args) throws IOException {
  3. Scanner in = new Scanner(System.in);
  4. String s;
  5. while((s = in.next()) != null && s.length() != 0){
  6. System.out.println(s);
  7. }
  8. }
  9. }

九、性能分析及总结

1、一个文件读写工具类。

[java] view plain copy

  1. import java.io.BufferedReader;
  2. import java.io.File;
  3. import java.io.FileReader;
  4. import java.io.IOException;
  5. import java.io.PrintWriter;
  6. import java.util.ArrayList;
  7. import java.util.Arrays;
  8. /**
  9. * 一个非常实用的文件操作类 . 2012-12-19
  10. *
  11. * @author Bruce Eckel , edited by erqing
  12. *
  13. */
  14. public class TextFile extends ArrayList<String> {
  15. private static final long serialVersionUID = -1942855619975438512L;
  16. // Read a file as a String
  17. public static String read(String filename) {
  18. StringBuilder sb = new StringBuilder();
  19. try {
  20. BufferedReader in = new BufferedReader(new FileReader(new File(
  21. filename).getAbsoluteFile()));
  22. String s;
  23. try {
  24. while ((s = in.readLine()) != null) {
  25. sb.append(s);
  26. sb.append("\n");
  27. }
  28. } finally {
  29. in.close();
  30. }
  31. } catch (IOException e) {
  32. throw new RuntimeException(e);
  33. }
  34. return sb.toString();
  35. }
  36. // Write a single file in one method call
  37. public static void write(String fileName, String text) {
  38. try {
  39. PrintWriter out = new PrintWriter(
  40. new File(fileName).getAbsoluteFile());
  41. try {
  42. out.print(text);
  43. } finally {
  44. out.close();
  45. }
  46. } catch (IOException e) {
  47. throw new RuntimeException(e);
  48. }
  49. }
  50. // Read a file,spilt by any regular expression
  51. public TextFile(String fileName, String splitter) {
  52. super(Arrays.asList(read(fileName).split(splitter)));
  53. if (get(0).equals(""))
  54. remove(0);
  55. }
  56. // Normally read by lines
  57. public TextFile(String fileName) {
  58. this(fileName, "\n");
  59. }
  60. public void write(String fileName) {
  61. try {
  62. PrintWriter out = new PrintWriter(
  63. new File(fileName).getAbsoluteFile());
  64. try {
  65. for (String item : this)
  66. out.println(item);
  67. } finally {
  68. out.close();
  69. }
  70. } catch (IOException e) {
  71. throw new RuntimeException(e);
  72. }
  73. }
  74. // test,I have generated a file named data.d at the root
  75. public static void main(String[] args) {
  76. /* read() test */
  77. System.out.println(read("data.d")); // testing is OK!
  78. /* write() test */
  79. write("out.d", "helloworld\negg"); // testing is OK!
  80. /* constractor test */
  81. TextFile tf = new TextFile("data.d"); // testing is OK!
  82. }
  83. }

2、读取二进制文件。

[java] view plain copy

  1. import java.io.BufferedInputStream;
  2. import java.io.File;
  3. import java.io.FileInputStream;
  4. import java.io.IOException;
  5. /**
  6. * to read the binary file
  7. *
  8. * @author erqing
  9. *
  10. */
  11. public class BinaryFile {
  12. /* the parametre is a file */
  13. public static byte[] read(File file) throws IOException {
  14. BufferedInputStream bf = new BufferedInputStream(new FileInputStream(
  15. file));
  16. try {
  17. byte[] data = new byte[bf.available()];
  18. bf.read(data);
  19. return data;
  20. } finally {
  21. bf.close();
  22. }
  23. }
  24. /* the param is the path of a file */
  25. public static byte[] read(String file) throws IOException {
  26. return read(new File(file).getAbsoluteFile());
  27. }
  28. }
时间: 2024-11-09 03:01:41

Java IO详解(转)的相关文章

Java IO 详解

Java IO 详解 初学java,一直搞不懂java里面的io关系,在网上找了很多大多都是给个结构图草草描述也看的不是很懂.而且没有结合到java7 的最新技术,所以自己来整理一下,有错的话请指正,也希望大家提出宝贵意见. 首先看个图:(如果你也是初学者,我相信你看了真个人都不好了,想想java设计者真是煞费苦心啊!) 这是java io 比较基本的一些处理流,除此之外我们还会提到一些比较深入的基于io的处理类,比如console类,SteamTokenzier,Externalizable接

Java IO详解

学习Java的同学注意了!!! 学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:618528494  我们一起学Java! 初学Java,一直搞不懂Java里面的io关系,在网上找了很多大多都是给个结构图草草描述也看的不是很懂.而且没有结合到java7 的最新技术,所以自己来整理一下,有错的话请指正,也希望大家提出宝贵意见. 首先看个图:(如果你也是初学者,我相信你看了真个人都不好了,想想java设计者真是煞费苦心啊!) 这是Java io 比较基本的一些处理流

Java IO详解(三)------字节输入输出流

File 类的介绍:http://www.cnblogs.com/ysocean/p/6851878.html Java IO 流的分类介绍:http://www.cnblogs.com/ysocean/p/6854098.html 那么这篇博客我们讲的是字节输入输出流:InputStream.OutputSteam(下图红色长方形框内),红色椭圆框内是其典型实现(FileInputSteam.FileOutStream)  1.字节输出流:OutputStream public abstrac

Java IO详解(六)------序列化与反序列化(对象流)

File 类的介绍:http://www.cnblogs.com/ysocean/p/6851878.html Java IO 流的分类介绍:http://www.cnblogs.com/ysocean/p/6854098.html Java IO 字节输入输出流:http://www.cnblogs.com/ysocean/p/6854541.html Java IO 字符输入输出流:https://i.cnblogs.com/EditPosts.aspx?postid=6859242 Jav

java io详解及各输入输出类介绍

首先要记住Java有一个非常强大的 文件及目录类 File, 这里面你想要的功能都有. 下面进入正题. 由于JavaIO根据装饰器设计模式设计, 设计思想是先给出基本IO类,其他功能如缓存,格式化,再嵌套其他类实现. 在我看来实际上是个失败的设计,不仅没有使类变得简单,由于各种IO类必须组合起来才能发挥作用,反而增大了类的复杂度,写起来也冗余不已. 所以JavaIO类看起来会有些(非常)臃肿. 对于IO根据面向字符还是面向字节可分为两大类. 1. 面向字节的IO都是从InputStream和Ou

Java IO详解(一)------File 类

File 类:文件和目录路径名的抽象表示. 注意:File 类只能操作文件的属性,文件的内容是不能操作的. 1.File 类的字段 我们知道,各个平台之间的路径分隔符是不一样的. ①.对于UNIX平台,绝对路径名的前缀始终为"/" . 相对路径名没有前缀. 表示根目录的抽象路径名具有前缀"/"和空名称序列. ②.对于Microsoft Windows平台,包含驱动器说明符的路径名的前缀由后面跟着":"的驱动器号组成,如果路径名是绝对的,则可能后跟

Java网络详解

Java网络详解 Java网络基本概念 网络基础知识 1.计算机网络形式多样,内容繁杂.网络上的计算机要互相通信,必须遵循一定的协议.目前使用最广泛的网络协议是Internet上所使用的TCP/IP协议 2.网络编程的目的就是指直接或间接地通过网络协议与其他计算机进行通讯.网络编程中有两个主要的问题,一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行数据传输.在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的路由,由IP地址可以唯一地确定Internet上

JAVA: httpclient 详解;

相对于httpurlconnection ,httpclient更加丰富,也更加强大,其中apache有两个项目都是httpclient,一个是commonts包下的,这个是通用的,更专业的是org.apache.http.包下的,所以我一般用后者: httpclient可以处理长连接,保存会话,重连接,以及请求过滤器,连接重用等等... 下面是测试代码(全部总结来自官方文档,以及翻译) 须要下载核心包:httpclient-4.3.4.jar ,也可在官网下载:http://hc.apache

java反射详解 (转至 http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html)

本篇文章依旧采用小例子来说明,因为我始终觉的,案例驱动是最好的,要不然只看理论的话,看了也不懂,不过建议大家在看完文章之后,在回过头去看看理论,会有更好的理解. 下面开始正文. [案例1]通过一个对象获得完整的包名和类名 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package Reflect; /**  * 通过一个对象获得完整的包名和类名  * */ class Demo{     //other codes... } class hello{     pu