浅谈Java的输入输出流(转)

Java语言的输入输出功能是十分强大而灵活的,美中不足的是看上去输入输出的代码并不是很简洁,因为你往往需要包装许多不同的对象。在Java类库中,IO部分的内容是很庞大的,因为它涉及的领域很广泛:标准输入输出,文件的操作,网络上的数据流,字符串流,对象流,zip文件流....本文的目的是为大家做一个简要的介绍。  

流是一个很形象的概念,当程序需要读取数据的时候,就会开启一个通向数据源的流,这个数据源可以是文件,内存,或是网络连接。类似的,当程序需要写入数据的时候,就会开启一个通向目的地的流。这时候你就可以想象数据好像在这其中“流”动一样,如下图:

Java中的流分为两种,一种是字节流,另一种是字符流,分别由四个抽象类来表示(每种流包括输入和输出两种所以一共四个):InputStream,OutputStream,Reader,Writer。Java中其他多种多样变化的流均是由它们派生出来的:

 在这其中InputStream和OutputStream在早期的Java版本中就已经存在了,它们是基于字节流的,而基于字符流的Reader和Writer是后来加入作为补充的。以上的层次图是Java类库中的一个基本的层次体系。

这四个抽象类中,InputStream和Reader定义了完全相同的接口:

int read()
  int read(char cbuf[])
  int read(char cbuf[], int offset, int length)  

而OutputStream和Writer也是如此:

int write(int c) 
 int write(char cbuf[])
 int write(char cbuf[], int offset, int length)

这六个方法都是最基本的,read()和write()通过方法的重载来读写一个字节,或者一个字节数组。

  更多灵活多变的功能是由它们的子类来扩充完成的。知道了Java输入输出的基本层次结构以后,本文在这里想给大家一些以后可以反复应用例子,对于所有子类的细节及其功能并不详细讨论。

import java.io.*;

public class IOStreamDemo {

public void samples() throws IOException {

//1. 这是从键盘读入一行数据,返回的是一个字符串
           BufferedReader stdin =new BufferedReader(new InputStreamReader(System.in)); 
           System.out.print("Enter a line:");
           System.out.println(stdin.readLine());

//2. 这是从文件中逐行读入数据

BufferedReader in = new BufferedReader(new FileReader("IOStreamDemo.java"));
           String s, s2 = new String();
           while((s = in.readLine())!= null)
                      s2 += s + "\n";
           in.close();

//3. 这是从一个字符串中逐个读入字节 
           StringReader in1 = new StringReader(s2);
           int c;
           while((c = in1.read()) != -1)
                      System.out.print((char)c);

//4. 这是将一个字符串写入文件 
           try {
                      BufferedReader in2 = new BufferedReader(new StringReader(s2));
                      PrintWriter out1 = new PrintWriter(new BufferedWriter(new FileWriter("IODemo.out")));
                      int lineCount = 1;
                      while((s = in2.readLine()) != null )
                                 out1.println(lineCount++ + ": " + s);
                      out1.close();
           } catch(EOFException e) {
                      System.err.println("End of stream");
           }
      }

}

对于上面的例子,需要说明的有以下几点:

  1. BufferedReader是Reader的一个子类,它具有缓冲的作用,避免了频繁的从物理设备中读取信息。它有以下两个构造函数:

BufferedReader(Reader in) 
BufferedReader(Reader in, int sz)

这里的sz是指定缓冲区的大小。

  它的基本方法:

void close() //关闭流

void mark(int readAheadLimit) //标记当前位置

boolean markSupported() //是否支持标记

int read() //继承自Reader的基本方法

int read(char[] cbuf, int off, int len) //继承自Reader的基本方法

String readLine() //读取一行内容并以字符串形式返回

boolean ready() //判断流是否已经做好读入的准备

void reset() //重设到最近的一个标记

long skip(long n) //跳过指定个数的字符读取

2. InputStreamReader是InputStream和Reader之间的桥梁,由于System.in是字节流,需要用它来包装之后变为字符流供给             BufferedReader使用。

3. PrintWriter out1 = new PrintWriter(new BufferedWriter(newFileWriter("IODemo.out")));

这句话体现了Java输入输出系统的一个特点,为了达到某个目的,需要包装好几层。首先,输出目的地是文件IODemo.out,所以最内层包装的是FileWriter,建立一个输出文件流,接下来,我们希望这个流是缓冲的,所以用BufferedWriter来包装它以达到目的,最后,我们需要格式化输出结果,于是将PrintWriter包在最外层。

  Java提供了这样一个功能,将标准的输入输出流转向,也就是说,我们可以将某个其他的流设为标准输入或输出流,看下面这个例子:


import java.io.*;

public class Redirecting {

public static void main(String[] args) throws IOException {
              PrintStream console = System.out;
              BufferedInputStream in = new BufferedInputStream( new FileInputStream("Redirecting.java"));
              PrintStream out = new PrintStream( new BufferedOutputStream( new FileOutputStream("test.out")));
              System.setIn(in);
              System.setOut(out);

BufferedReader br = new BufferedReader( new InputStreamReader(System.in));
              String s;
              while((s = br.readLine()) != null)
                     System.out.println(s);
              out.close(); 
              System.setOut(console);
      } 
}

在这里java.lang.System的静态方法

static void setIn(InputStream in) 
static void setOut(PrintStream out)

提供了重新定义标准输入输出流的方法,这样做是很方便的,比如一个程序的结果有很多,有时候甚至要翻页显示,这样不便于观看结果,这是你就可以将标准输出流定义为一个文件流,程序运行完之后打开相应的文件观看结果,就直观了许多。

  Java流有着另一个重要的用途,那就是利用对象流对对象进行序列化。下面将开始介绍这方面的问题。

  在一个程序运行的时候,其中的变量数据是保存在内存中的,一旦程序结束这些数据将不会被保存,一种解决的办法是将数据写入文件,而Java中提供了一种机制,它可以将程序中的对象写入文件,之后再从文件中把对象读出来重新建立。这就是所谓的对象序列化Java中引入它主要是为了RMI(Remote Method Invocation)和Java Bean所用,不过在平时应用中,它也是很有用的一种技术。

  所有需要实现对象序列化的对象必须首先实现Serializable接口。下面看一个例子:


import java.io.*;
import java.util.*;

public class Logon implements Serializable {

private Date date = new Date();
       private String username;
       private transient String password;

Logon(String name, String pwd) {
              username = name;
              password = pwd;
       }

public String toString() {
              String pwd = (password == null) ? "(n/a)" : password;
              return "logon info: \n " + "username: " + username + "\n date: " + date + "\n password: " + pwd;
       }

public static void main(String[] args) throws IOException, ClassNotFoundException {
              Logon a = new Logon("Morgan", "morgan83");
              System.out.println( "logon a = " + a);
              ObjectOutputStream o = new ObjectOutputStream( newFileOutputStream("Logon.out"));
              o.writeObject(a);
              o.close();

int seconds = 5;
              long t = System.currentTimeMillis() + seconds * 1000;
              while(System.currentTimeMillis() < t) ;

ObjectInputStream in = new ObjectInputStream( new FileInputStream("Logon.out"));
              System.out.println( "Recovering object at " + new Date());
              a = (Logon)in.readObject();
              System.out.println("logon a = " + a); 
       }
}

类Logon是一个记录登录信息的类,包括用户名和密码。首先它实现了接口Serializable,这就标志着它可以被序列化。之后再main方法里ObjectOutputStream o = new ObjectOutputStream( newFileOutputStream("Logon.out"));新建一个对象输出流包装一个文件流,表示对象序列化的目的地是文件Logon.out。然后用方法writeObject开始写入。想要还原的时候也很简单ObjectInputStream in =new ObjectInputStream( new FileInputStream("Logon.out"));新建一个对象输入流以文件流Logon.out为参数,之后调用readObject方法就可以了。

  需要说明一点,对象序列化有一个神奇之处就是,它建立了一张对象网,将当前要序列化的对象中所持有的引用指向的对象都包含起来一起写入到文件,更为奇妙的是,如果你一次序列化了好几个对象,它们中相同的内容将会被共享写入。这的确是一个非常好的机制。它可以用来实现深层拷贝。

  关键字transient在这里表示当前内容将不被序列化,比如例子中的密码,需要保密,所以没有被写入文件。

  对Java的输入输出功能,就浅浅的介绍到这里,本文的目的只是开一个好头,希望能让大家对Java输入输出流有个基本的认识。

个人觉得挺有道理,转载于:http://www.yesky.com/88/1700588.shtml

时间: 2024-11-08 10:12:53

浅谈Java的输入输出流(转)的相关文章

浅谈Java的输入输出流

Java语言的输入输出功能是十分强大而灵活的,美中不足的是看上去输入输出的代码并不是很简洁,因为你往往需要包装许多不同的对象.在Java类库中,IO部分的内容是很庞大的,因为它涉及的领域很广泛:标准输入输出,文件的操作,网络上的数据流,字符串流,对象流,zip文件流....本文的目的是为大家做一个简要的介绍. 流是一个很形象的概念,当程序需要读取数据的时候,就会开启一个通向数据源的流,这个数据源可以是文件,内存,或是网络连接.类似的,当程序需要写入数据的时候,就会开启一个通向目的地的流.这时候你

浅谈java类集框架和数据结构(2)

继续上一篇浅谈java类集框架和数据结构(1)的内容 上一篇博文简介了java类集框架几大常见集合框架,这一篇博文主要分析一些接口特性以及性能优化. 一:List接口 List是最常见的数据结构了,主要有最重要的三种实现:ArrayList,Vector,LinkedList,三种List均来自AbstracList的实现,而AbstracList直接实现了List接口,并拓展自AbstractCollection. 在三种实现中,ArrayList和Vector使用了数组实现,可以认为这两个是

浅谈 Java Printing

浅谈 Java  Printing 其实怎么说呢?在写这篇博文之前,我对java printing 可以说是一无所知的.以至于我在敲文字时, 基本上是看着api文档翻译过来的.这虽然看起来非常的吃力,但是我相信,有道大哥不会辜负我的.嘻 嘻! Java Printing 技术,也就是我们平时所接触的打印,只不过是说可以用Java实现而已. 一.Java Printing 打印简介 Java Printing API能够使java应用程序实现相关的打印功能,如: 1.打印所有 Java 2D 和

【转】浅谈Java中的equals和==

浅谈Java中的equals和== 在初学Java时,可能会经常碰到下面的代码: 1 String str1 = new String("hello"); 2 String str2 = new String("hello"); 3 4 System.out.println(str1==str2); 5 System.out.println(str1.equals(str2)); 为什么第4行和第5行的输出结果不一样?==和equals方法之间的区别是什么?如果在初

浅谈java异常[Exception]

本文转自:focusJ 一. 异常的定义 在<java编程思想>中这样定义 异常:阻止当前方法或作用域继续执行的问题.虽然java中有异常处理机制,但是要明确一点,决不应该用"正常"的态度来看待异常.绝对一点说异常就是某种意义上的错误,就是问题,它可能会导致程序失败.之所以java要提出异常处理机制,就是要告诉开发人员,你的程序出现了不正常的情况,请注意. 记得当初学习java的时候,异常总是搞不太清楚,不知道这个异常是什么意思,为什么会有这个机制?但是随着知识的积累逐渐也

浅谈Java虚拟机

最近发现MDT推出去的系统的有不同问题,其问题就不说了,主要是策略权限被域继承了.比如我们手动安装的很多东东都是未配置壮态,推的就默认为安全壮态了,今天细找了一下,原来把这个关了就可以了. 浅谈Java虚拟机,布布扣,bubuko.com

浅谈Java中的对象和引用

浅谈Java中的对象和对象引用 在Java中,有一组名词经常一起出现,它们就是"对象和对象引用",很多朋友在初学Java的时候可能经常会混淆这2个概念,觉得它们是一回事,事实上则不然.今天我们就来一起了解一下对象和对象引用之间的区别和联系. 1.何谓对象? 在Java中有一句比较流行的话,叫做"万物皆对象",这是Java语言设计之初的理念之一.要理解什么是对象,需要跟类一起结合起来理解.下面这段话引自<Java编程思想>中的一段原话: "按照通

浅谈Java中的equals和==

浅谈Java中的equals和== 在初学Java时,可能会经常碰到下面的代码: 1 String str1 = new String("hello"); 2 String str2 = new String("hello"); 3 4 System.out.println(str1==str2); 5 System.out.println(str1.equals(str2)); 为什么第4行和第5行的输出结果不一样?==和equals方法之间的区别是什么?如果在初

浅谈Java throw, throws, try catch异常处理

1.throws关键字通常被应用在声明方法时,用来指定可能抛出的异常.多个异常可以使用逗号隔开.当在主函数中调用该方法时,如果发生异常,就会将异常抛给指定异常对象.如下面例子所示: public class Shoot {   创建类 static void pop() throws NegativeArraySizeException { //定义方法并抛出NegativeArraySizeException异常 int [] arr = new int[-3];//创建数组 } public