博客首页 注册 建议与交流 排行榜 加入友情链接         宝宝相册的专门空间
推荐 投诉 搜索: 帮助

流水孟春

以前使用的博客 webvista.cublog.cn
lib.cublog.cn
JAVA I/O
 
第1节   JAVA的I/O
一、什么是流(Stream)?
       能产生数据的数据源或能接收数据的接收端,叫流。
       常见的数据源有:
A、字节数组:byte  array。
B、字串对象:String对象。
C、文件:File对象
D、管道:pipe
E、流序列:即多股流,可把它们汇合成一股新流。
F、其他数据源:如网络通信等。
二、什么要用流?
       使用流后,可以把实际的I/O数据处理细节隐藏起来,为编程提供更方便、更好用的编程接口。
       例如:希望从键盘读到是直接就是“双精度数”,而不是字符串时,就不能直接访问键盘,而是对原始的键盘操作进行多次封装后得到一个新的类,用这类中的函数实现新的读写操作。用流更方便功能扩充。
三、JAVA标准I/O
      标准I/O的概念来自UNIX。它是指能被一个程序使用的单一的数据流。
标准I/O主要有:
A、标准输入:Standard Input
       程序可从标准输入中读取数据,而不必关心这个输出是:键盘、文件、网络等。
B、标准输出:Standard Output
       程序的结果可以直接输出到标准输出,而不必关心输出对象是:命令窗口、文件、网络。
C、标准错误:Standard Error
       数据流读写过程中发生的错误,会集中送到标准错误中进行处理。
      有了流的概念后,程序A(可以是文件)的输出(print)信息可以直接作为程序B(可能是网络)的输入,B的输出可以直接作为程序C的输出等,很将多个不同的程序串接起来,各自独立工作,又能协同。
第2节    流的分类
一、字节流:
     比较适合7位ASCII码的操作。
二、字符流:
     以字符为单位进行处理,用2字节的Unicode作编码。
三、文件流
四、对象流:
       序列化后的对象。内存中的对象是以二进制的“字节”为单位进行读写,把它们“双字节”化(Unicode编码)的过程,叫序列化,以方便网络传输。
第3节   字节流
一、标准I/O
1、System.in
    称之为标准输入流。
    默认时,它是指键盘。通过System.setIn(另一个流对象)可将它定义成另一个流(如文件、程序的缓冲区等)。
2、System.out
     称之为标准输出流。
     默认时,它是命令行窗口。可以
通过System.setOut(另一个输出流)将其定义成另一个输出流(如文件等)。
3、System.err
    把错误的信息输出到命令行上。
System.err和System.out都能输出信息,两者的区别是:前者一般用来输出错误信息、日志、跟踪信息等。
      通过System.setErr()可以把输出定向到另一个输出流中(如文件)。
4、注意:
(1)
       System.in不能直接使用,要使用其它类对它进行包装后间接使用。因为它是逐个读取字符,会造系统资源严重浪费(在Unix/Linux多用户终端环境下特别明显)。
       System.out/err可以直接使用。
(2)以上重定向流的输入/输出方向后,新的方向只对相应的程序有效,对其它运行着的无关JAVA程序无效。
二、输入/输出的方法
1、InputStream类
      它负责从合法的数据源中取得输入。
      每一种数据源都有相应的InputStream子类,这些子类是对InputStream进行包装后得到,功能、应用场合不同。详见以下各种的过滤类FilterInputStream。
        这个也不直接使用,而是用各种具体的过滤类。
2、OutputStream类
      将信息送至输出目标中。
      这个类也不直接使用,而是对它进行包装后,使用各种过滤类。
三、过滤流
1、设计模式:Design   Pattern
      它是指:针对某个普遍问题的一种通用的解决方案。一种思路,与编程语言无关。
      可参考“四人帮”写的《设计模式(可复用面向对象软件的基础)》一书。
2、Decorator设计模式
       也叫“装饰模式”、“外覆(Wrapper)模式”。
       基本思想:要给某对象增加一些功能时,如果使用继承的方法会造成子类大量的增加,程序设计时可改用“装饰模式”。它是把一个对象A“包装”在另一个对象B中,使得新对象B是“多个对象叠加组合”的结果,B有A的功能,并可在B中直接使用这个功能、或扩充这个功能。
例如:有一个文本框,没有滚动条,不能滚动文本:
   给这个文本框添加一个滚动条对象即可。这种方法叫“装饰”。
       “装饰模式”规定,被修饰过的类热拥有内置对象的接口,所以能侦听、接收发给内置对象的消息、数据,最后将这些消息转发给内置的对象。
        过滤器实际上就是一个外覆类。

四、常用的字节输入流类
    程序中要首先导入:java.io.*;
   详见P179页图8.1和P182页表8.1。
1、DataInputStream
      它是按基本数据类型进行读写,调用相应的readInt()、readDouble()、readLine()等函数。主的用法是:
   DataInputStream  a=new  DataInputStream();
      int b=a.readInt();//试输入整数再打印
      String c=a.readLine();//返回一个串
      这个类的一次读操作会引发一次真实的直接设备读操作,在Unix/Linux多用户终端环境会造成操作系统的停机等待的现象,现在已经不建议使用。
2、BufferedInputStream     
         它是从缓冲区中读取数据,是间接操作数据流。比较建议使用。常用的函数有:
        read() 返回一个字符的ASCII码。
五、字节输出流
1、DataOutputStream
        可以直接把基本数据类型、这串直接送至输出流中。有相关的write()。
2、BufferedOutputStream
        每次的write()不会直接输出,而是写入缓冲区中,缓冲区满后才一次性将数据输出到流中。
3、PrintStream
   可以对基本数据类型进行格式化后打印,这个类容易出错。
        注意:使用流操作时,可能会产生异常,所以要用异常处理机制处理。

第5节    字符流
一、字符流与字节流的区别
      前者是从缓冲区读取数据,后者是直接操作。所以,一般使用字符流。只有要对字节对象操作时,才会用到字节流。
二、字符流类
     特点:类名尾部有“Reader”、”Writer”字样。参见P187页的图8.2。
三、常用的字符流类
1、InputStreamReader类
      它实际上是对字节流对象包装成一个字符流对象。起到一个“适配器”的作用。
       适配器:Adapter ,一些起到数据转换作用的类。如本例中:把字节流转换成字符流。
      一般不直接使用本类。
2、BufferedReader类
      字符流缓冲区。关键函数:
   readLine():读取一行,返回字串。

第4节   文件I/O
一、File类
       这个类的主要作用是:判断文件是否存在、文件的读写权限、创建文件夹等。这个文件夹有同样的作用。常用的函数有:
1、构造函数
      用来表示一个(一组)文件/文件夹。
如:File  a=new  File(“c:\\aa\\bb”);
        File  b=new  File(“c://my1.txt”);
注意:Windows环境下,根文件夹、分隔符要用“//”  或  “\\”  表示;不能用“/”、“\”表示。
2、makdirs()
   一般对文件夹对象有效,即创建文件夹的作用。如上例:
    a.makedirs();返回真假值。
3、createNewFile();
   创建一个新文件。如果文件已经存在,则不创建。返回真假值。如:
    a.createNewFile();
4、a.getAbsoluteFile()
  返回目录/文件的绝对路径。
如:在指定的文件夹下创建文件
  File b=new File(a.getAbsoluteFile()+"//my1.txt");
 
二、文件流类
      把文件当作一个输入流,可从流中读到文件中的内容。流创建好后,就可对它进行读、写操作。
1、FileInputStream类
      把文件当作输入流对象。
  如:
File a=new File(“c:\\r1.txt”);
FileInputStream  b=
    new FileInputStream(a);//文件流对象
[例]把一个文件中的行读出显示在屏幕上。
File a=new File("c://r1.txt");
FileInputStream b=new 
                    FileInputStream(a);
InputStreamReader c=new
                    InputStreamReader(b);
BufferedReader d=new
                    BufferedReader(c);
//读出文件显示
String temp=d.readLine();
     while( temp != null)
     {
      System.out.println(temp);
      temp=d.readLine();
      }
 b.close();//最后关闭文件
2、文件重定向
File a=new File("c://r1.txt");
FileInputStream b=new 
                    FileInputStream(a);
System.setIn(b);//重定向
InputStreamReader c=
       new  InputStreamReader(System.in);
BufferedReader d=new
                    BufferedReader(c);
3、FileOutputStream类
      把一个文件作输出流,实现写文件的操作。它会将文件先清空复位,从文件头开始。
[例]  把1、2、3写到一个文本文件中。
File a=new File(“c:\\r1.txt”);//文件对象
FileOutputStream b=//文件流
            new FileOutputStream(a);
  
OutputStreamWriter c=//输出流
              new OutputStreamWriter(b);
   //写缓冲区
  BufferedWriter d=new BufferedWriter(c); for(int i=0;i<100;i++)
     {
         d.write(i+"\n");//写文件
      }
  d.close();  //关闭文件
注意:
(1)关闭文件时,将缓冲区关闭即可。
(2)文件不一定包装成缓冲区。文件流直接就可以读写。包装成缓冲区是为了使用缓冲的一些函数,如:readLine()等。
三、RandomAccessFile
        随机读写文件。注意:这个类不是流,它是普通的类,比较类似于C语言中的文件操作。主要函数:
1、构造函数
   生成一个随机文件对象。
RandomAccessFile b=new
      RandomAccessFile("c://r1.txt","rw");
第1个参数是文件名。
第2个参数是文件的读写属性。
2、读
read():读
readLine():读一行
readInt():读一个整数,整数在文件中以二进制形式存在。
readFloat():
3、写
Write()
writeInt()
4、移动指针
   seek(int n):从文件头开始算,移动指针N个字节。
5、关闭:
 close();
[例] 
(1)产生10个随机小数,写入到文件中保存。
(2)修改程序,读出这个数据显示在屏幕上。
(3)修改程序,读出最后5个数显示。
(1)
RandomAccessFile b=new
       RandomAccessFile("c://r1.txt","rw");
double temp;
     for(int i=0;i<100;i++)
     {
           temp=Math.random();
           b.writeDouble(temp);//写文件
            }
 b.close();//关闭文件
(2)
RandomAccessFile b=new
       RandomAccessFile("c://r1.txt","rw");
double temp;
     for(int i=0;i<100;i++)
     {
           temp=b.readDouble();//读一个数
           System.out.println(temp);//显示
            }
 b.close();//关闭文件
(3)每个double数64位,8字节。
b.seek(5*8);//移动5个数
     RandomAccessFile b=new
       RandomAccessFile("c://r1.txt","rw");
double temp;
     for(int i=0;i<100;i++)
     {
           temp=b.readDouble();//读一个数
           System.out.println(temp);//显示
            }
 b.close();//关闭文件
第6节   对象序列化
一、JAVA的I/O操作不足
      在网络传输、文件读写中,能被传输、读写的一般是:基本数据类型、String字串;大部份的系统类、用户自定义的类所产生的对象不能被直接传输、读写。
      解决方法:先把内存中的对象转换为字节流对象,对这个流对象进行传输、读写即可。
1、对象序列化:Serializing
     把内存中的对象字节化形成一个对象流的过程,叫对象序列化。
2、反序列化:Deserializing
     把一个对象流解码,得到一个原始的对象并放入JVM的堆中,形成一个内存对象,并返回它的引用的过程,叫反序列化。
      它们是一对逆运算。
二、一个类,如何实现可序列化?
实现接口  Serializable即可。
       这是个“标记接口”,其中没有任何的函数定义。
如:
   class   My1  implements  Serializable
   {
          …………..
   }
三、如何将一个可序列化的对象写盘、读盘?
1、持久性:persistent
        内存中的对象会因关机、程序结束运行等原因而从内存消失。
        持久性是指:对象的生命期不取决于程序是否执行,即便程序结束了,对象仍然存在。
         实现持久性的方法是:将对象写盘、写数据库。这个过程叫持久化对象。
2、把一个对象写盘的方法
A、把一个磁盘文件包装成“文件输出流”对象。FileOutputStream类。
B、把文件输出流对象包装成“对象输出流”对象。ObjectOutputStream。
C、使用对象流中的writeObject(obj)即可将一个可序列化的对象写盘。
[例]   定义一个可序列化的类。生成一个对象并写盘。
import java.io.*;
class Test23  implements Serializable
{
 public double i=0;
 Test23()
 {
  i=Math.random()*10;
  System.out.println(“对象中有一个随机数:"+i);
  }
}
写盘:
FileOutputStream a=
       new FileOutputStream("c:\\w1.txt");
ObjectOutputStream b=
        new ObjectOutputStream(a);
  //生成一个可序列化的对象
Test23 c=new Test23();
  //把这个可序列化的对象写盘
b.writeObject(c);
b.close();//关闭文件
3、对象读盘
A、把一个存有序列化对象的文件包装成“文件输入流”。FileInputStream类。
B、把文件输入流对象包装成“对象输入流”。ObjectInputStream类。
C、使用  readObject()即可读到一个反序列化的通用对象Object。必要时作类型转换。
[例]   将上例中的对象从文件中读取显示。
  //从文件中读对象
FileInputStream d=
          new FileInputStream("c:\\w1.txt");  
ObjectInputStream e=
           new ObjectInputStream(d);
Test23 f=(Test23)e.readObject();
System.out.println("读到的对象的值为:"+f.i);
e.close();//关闭文件
    注意:反序列化一个对象时,要保证JVM能通过classpath或Internet定位到与对象相应的*.class文件,否则反序列会失败。
      如:上例的读盘反序列化操作的*.class文件,将它复制到  c:\kk1下,在命令下运行它:
    c:\kk1>   java    xxx.class
这时会出现找不到对象对应的类的错误。
4、防止某些属性被序列化
     如果某些属性因保密等原因,希望它不能被序列化存盘、传输,可用transient定义它即可。如:
 transient  int   j=100;
      另一种做法:使用private代替transient,即使属性序列化了,也无法访问。如:
  private  int  j=100;
四、序列化对象的版本号
       一个类被修改后,读取先前的它生成的序列化对象后,还原时可能问题。所以最好在对象中加入一个符号常量,标识这个对象是哪个版本的类产生。
如:
  static final  long  version=1234566L;
通过version这个符号常量识别类的版本号。修改类时,要修改这个版本号。
 
 

发表于: 2007-01-25,修改于: 2007-01-25 16:08,已浏览672次,有评论0条 推荐 投诉

给我留言
版权所有 ChinaUnix.net 页面生成时间:3.93372