第七章 IO/输入与输出

 

第七章 IO/输入与输出

     File

     RandomAccessFile

     各种节点流类

     字符编码

     各种过滤流与包装类

     IO类的相关应用

 

File

                                                                                                                                   

     File类是IO包中唯一代表磁盘文件本身信息的类,而不是文件中的内容。

     File类定义了一些与平台无关的方法来操作文件,创建、删除文件和重命名文件。

     Java中的目录被当作一种特殊的文件使用,list方法可以返回目录中的所有子目录和文件名。

     Unix下的路径分隔符为(/),在Dos下的路径分隔符为(\)Java可以正确处理UnixDos的路径分隔符。

RandomAccessFile

                                                                                                                                    

     此类的实例支持对随机访问文件的读取和写入。

     RandomAccessFile类提供了众多的文件访问方法。

     RandomAccessFile类支持“随机访问”方式。

     RandomAccessFile类在随机(相对顺序而言)读写等长记录格式的文件时有很大的优势。

     RandomAccessFile类公限于操作文件,不能访问其他的IO设备,如网络、内存映像等。

     两种构造方法:

         nNew RandomAccessFile(f,”rw”);//读写方式

         nNew RandomAccessFile(f,”r”);//只读方式

编程实例:往文件中写入三名员工的信息,每个员工含有姓名和年龄两个字段,然后按照第二名、等一名、第三名的先后顺序读出员工信息。

 

public class Employee

{

       public String name = "";

       public int age = 0;

       public static final int LEN = 8;     

       public Employee(String name, int age)

       {

              // TODO: Add your code here

              if(name.length()>LEN)

              {

                     name=name.substring(0,LEN);

              }

              else

              {

                     while(name.length()<LEN)

                     {

                            name+="\u0000";

                     }

              }

              this.name=name;

              this.age=age;

       }    

}

 

import java.io.*;

public class TestRandomAccessFile

{

       public static void main(String[] args) throws Exception

       {

              // TODO: Add your code here

              Employee em1=new Employee("zhangsan",18);

              Employee em2=new Employee("李四",26);

              Employee em3=new Employee("wangwu",22);

             

              RandomAccessFile raf=new RandomAccessFile("employee.txt","rw");

              raf.writeChars(em1.name);

              raf.writeInt(em1.age);

              raf.writeChars(em2.name);

              raf.writeInt(em2.age);

              raf.writeChars(em3.name);

              raf.writeInt(em3.age);

             

              RandomAccessFile raf1=new RandomAccessFile("employee.txt","r");

              String strName="";

              raf1.skipBytes(Employee.LEN*2+4);

              for(int i=0;i<Employee.LEN;i++)

              {

                     strName+=raf1.readChar();

              }

              System.out.println(strName.trim()+":"+raf1.readInt());

             

              raf1.seek(0);

              strName="";

              for(int i=0;i<Employee.LEN;i++)

              {

                     strName+=raf1.readChar();

              }

              System.out.println(strName.trim()+":"+raf1.readInt());

             

              raf1.skipBytes(Employee.LEN*2+4);

              strName="";

              for(int i=0;i<Employee.LEN;i++)

              {

                     strName+=raf1.readChar();

              }

              System.out.println(strName.trim()+":"+raf1.readInt());

       }    

}

 

节点流

                                                                                                                                    

     理解流的概念

     InputStreamOutputStream

     FileInputStreamFileOutputStream

     ReaderWriter

     PipedInputStreamPipedOutputStream

     ByteArrayInputStreamByteArrayOutputStream

     重视程序代码的复用性

理解流的概念

                                                                            

     流是字节序列的抽象概念。

流机制是JAVAC++中的一个重要的机制,通过流能使我们能自由地控制包括文件,内存,IO设备等等中的数据的流向。如:可以从文件输入流中获取数据,经处理后再通过网络输出流把数据输出到网络设备上;或利用对像输出流把一个程序中的对象输出到一个格式流文件中,并通过网络流对象将其输出到远程机器上,然后在远程机器上利用对象输入流将对象还原。像这些机制是别的高级语言所不能比拟的。但要掌握好这些流对象,流的概念是很重要的。是一串连续不继的数据的集合,就像水管一里的水流,在水管的一端一点一点地供水,而在水管的另一端看到的是一股连续不断的水流。数据写入程序可以是一段一段地向数据流管道中写入数据,这些数据段会按先向顺序形成一个长的数据流。对数据的读取程序来说,看不到数据流在写入时的分段情况,每次可以读取其中的任意长度的数据,但只能先读取前面的数据后,再读取后面的数据。不管写入时是将数据分多次写入,还是作为一个整体一次写入,读取时的效果都是完全一样的。在JAVA中的流按流动方向可以分为输入流输出流两种,按流的处理位置可分为节点流包装流输入流、输出流是以程序为参考点来说的,所谓的输入流就是程序从中获取数据的流,输出流就是程序要其写数据的流。在输入流的一边是程序,而另一边就是流的数据源。而输出流的一边则目标,一边就是程序。(如下图)

     文件是数据的静态存储形式,而流是指数据传输时的形态。

     流类分为两个大类:节点流类和过滤流类(也叫处理流类)。

 

InputStream

                                                                                                                                    

       程序可以从中连续读取字节的对象叫输入流,Java中,用InputStream类来描述所有输入流的抽象概念。

InputStream类的方法:

方法摘要

 int

available()
          
返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。

 void

close()
          
关闭此输入流并释放与该流关联的所有系统资源。

 void

mark(int readlimit)
          
在此输入流中标记当前的位置。readlimit 参数告知此输入流在标记位置失效之前允许读取的字节数

 boolean

markSupported()
          
测试此输入流是否支持 mark reset 方法。

abstract  int

read()
          
从输入流中读取数据的下一个字节。

 int

read(byte[] b)
          
从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。

 int

read(byte[] b, int off, int len)
          
将输入流中最多 len 个数据字节读入 byte 数组。

 void

reset()
          
将此流重新定位到最后一次对此输入流调用 mark 方法时的位置。

 long

skip(long n)
          
跳过和丢弃此输入流中数据的 n 个字节。

 

OutputStream

                                                                                                                                       

       程序可以从向其中连续写入字节的对象叫输出流,在Java中,用OutputStream类来描述所有输出流的抽象概念。此抽象类是表示输出字节流的所有类的超类。输出流接受输出字节并将这些字节发送到某个接收器。

OutputStream类的方法:

方法摘要

 void

close()
          
关闭此输出流并释放与此流有关的所有系统资源。

 void

flush()
          
刷新此输出流并强制写出所有缓冲的输出字节。

 void

write(byte[] b)
          
b.length 个字节从指定的 byte 数组写入此输出流。

 void

write(byte[] b, int off, int len)
          
将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。

abstract  void

write(int b)
     将指定的字节写入此输出流。将指定的字节写入此输出流。
write 的常规协定是:向输出流写入一个字节。要写入的字节是参数 b 的八个低位。b 的 24 个高位将被忽略。 OutputStream 的子类必须提供此方法的实现

 

FileInputStreamFileOutputStream

                                                                                                                                        

     FileInputStreamFileOutputStream类分别用来创建磁盘文件的输入流和输出流对象,通过它们的构造函数来指定文件路径和文件名。

     创建FileInputStream实例对象时,指定的文件应当是存在和可读的。创建FileOutputStream实例对象时,如果指定的文件已经存在,这个文件中的原来内容将被覆盖清除。

     对同一个磁盘文件创建FileInputStream对象的两种方式:

u       FileInputStream inOne=new FileInputStream(“hello.test”);

u       File f=new File(“hello.test”);

FileInputStream inTwo=new FileInputStream(f);

     创建FileOutputStream实例对象时,可以指定还不存在的文件名,不能指定一个已被其他程序打开了的文件。

编程举例:用FileOutputStream类向文件中写入一个串字符,然后用FileInputStream读出写入的内容。

import java.io.*;

public class TestInputStream

{

public static void main(String[] args)

{

        // TODO: Add your code here

        try

        {

               FileOutputStream outOne=new FileOutputStream("test.txt");

               outOne.write("Hello World".getBytes());

               outOne.close();

              

               FileInputStream inOne=new FileInputStream("test.txt");

               byte[]buf=new byte[1024];

               int len=inOne.read(buf);

               System.out.println(new String(buf,0,len));

               inOne.close();

        }

        catch(Exception e)

        {

               e.printStackTrace();

        }

}    

}

 

ReaderWriter

                                                                                                                                 

     ReaderWriter是所有字符流类的抽象基类,用于简化对字符串的输入输出编程,即用于读写文本数据。

     二进制文件和文本文件的区别。

如果一个文件专用于存储文本字符,而没有包含字符以外的其它数据,就称为文本文件;除此之外的文件就称为二进制文件。

ReaderWriter类主要用于读取文本格式的内容,而InputStreamOutputStream及它们的子类主要用于读取二进制文件。

       编程举例:用FileWriter类向文件中写入一个字符串,然后用FileReader读出写入的内容。

import java.io.*;

public class TestFileRead

{

       public static void main(String[] args)

       {

              // TODO: Add your code here

              try

              {

                     FileWriter fw=new FileWriter("file.txt");

                     fw.write("Hello World!");

                     fw.close();

                                         

                     FileReader fr=new FileReader("file.txt");

                     char []buf=new char[1024];

                     int len=fr.read(buf);

                     System.out.println(new String(buf,0,len));

                     fr.close();

              }

              catch(Exception e)

              {

                     e.printStackTrace();

              }

       }    

}

 

从输入方法中获取字符串到文件:

import java.io.*;

import java.util.*;

public class TestFileWriter

{

       public static void main(String[] args)

       {

              // TODO: Add your code here

              int ch=0;

              String str=null;

              StringBuffer sb=new StringBuffer();

              System.out.println("请输入一串字符:");

              try

              {

                     while(true)

                     {

                            ch=System.in.read();

                            if(ch=='\r'||ch=='\n')

                            {

                                   break;

                            }

                            else

                            {

                                   sb.append((char)ch);

                            }

                            str=sb.toString();

                     }

                    

                     File f=new File("test.txt");

                     FileWriter fw=new FileWriter(f);

                     fw.write(str);

                     fw.close();

                    

                     FileReader fr=new FileReader(f);

                     char []buf=new char[1024];

                     int len=fr.read(buf);

                     System.out.println(new String(buf,0,len));

                     fr.close();

                    

              }

              catch(Exception e)

              {

                     e.printStackTrace();

              }

       }    

}

 

PipedInputStreamPipedOutputStream

                                                                                                                                    

     PipedInputStream类与PipedOutputStream类用于在应用程序中的创建管道通信。

这两个类主要用来完成线程之间的通信,一个线程中的PipedInputStream对象可以从另外一个线程中的PipedOutputStream对象中读取数据。

     PipedInputStream类与PipedOutputStream类编程实例:

import java.io.*;

public class Sender implements Runnable

{

       private PipedOutputStream out=new PipedOutputStream();

       public PipedOutputStream getOutPutStream()

       {

              return out;

       }

       public void run()

       {

              try

              {

                     out.write("Hello World!".getBytes());

                     out.close();

              }

              catch(Exception e)

              {

                     e.printStackTrace();

              }

       }

}

 

import java.io.*;

public class Receiver implements Runnable

{

       private PipedInputStream in=new PipedInputStream();

       public PipedInputStream getInputStream()

       {

              return in;

       }

       public void run()

       {

              try

              {

                     byte []buf=new byte[1024];

                     int len=in.read(buf);

                     System.out.println("The Follow message comes from Sender:\n"+

                            new String(buf,0,len));

                            in.close();

              }

              catch(Exception e)

              {

                     e.printStackTrace();

              }

       }

}

 

import java.io.*;

public class PipedStreamTest

{

       public static void main(String[] args)

       {

              // TODO: Add your code here

              Sender ts=new Sender();

              Receiver tr=new Receiver();

              PipedOutputStream out=ts.getOutPutStream();

              PipedInputStream in=tr.getInputStream();

              try

              {

                     out.connect(in);

              }

              catch(Exception e)

              {

                     e.printStackTrace();

              }

              new Thread(ts).start();

              new Thread(tr).start();

       }    

}

     PipedWriterPipedReader类。

     使用管道流类,可以实现各个程序模块之间的松耦合通信。

 

ByteArrayInputStream与ByteArrayOutputStream类

     ByteArrayInputStreamByteArrayOutputStream类,用于以IO流的方式来完成对字节数组内容的读写,来支持类似内存虚拟文件或者内存映像文件的功能。ByteArrayInputStream是把字节数组当成源的输入流。该类有两个构造函数,每个构造函数需要一个字节数组提供数据源。(包含一个内部缓冲区,该缓冲区存储从流中读取的字节。内部计数器跟踪 read 方法要提供的下一个字节。)ByteArrayOutputStream此类实现了一个输出流,其中的数据被写入一个字节数组。缓冲区会随着数据的不断写入而自动增长。可使用 toByteArray() toString() 检索数据。

     ByteArrayInputStream类的两个构造函数:

ByteArrayInputStream(byte[] buf)
          
创建一个 ByteArrayInputStream,使用 buf 作为其缓冲区数组。

ByteArrayInputStream(byte[] buf, int offset, int length)
          
创建 ByteArrayInputStream,使用 buf 作为其缓冲区数组。

     ByteArrayOutputStream类的两个构造函数:

ByteArrayOutputStream()
          
创建一个新的字节数组输出流。缓冲区的容量最初是 32 字节,如有必要可增加其大小

ByteArrayOutputStream(int size)
          
创建一个新的字节数组输出流,它具有指定大小的缓冲区容量(以字节为单位)。

 






方法摘要

 void

close()
          
关闭 ByteArrayOutputStream 无效。

 byte[]

toByteArray()
          
创建一个新分配的字节数组。

 String

toString()
          
将缓冲区的内容转换为字符串,根据平台的默认字符编码将字节转换成字符。

 String

toString(String enc)
          
将缓冲区的内容转换为字符串,根据指定的字符编码将字节转换成字符。

 void

write(byte[] b, int off, int len)
          
将指定字节数组中从偏移量 off 开始的 len 个字节写入此字节数组输出流。

 void

write(int b)
          
将指定的字节写入此字节数组输出流。

 void

writeTo(OutputStream out)
          
将此字节数组输出流的全部内容写入到指定的输出流参数中,这与使用 out.write(buf, 0, count) 调用该输出流的 write 方法效果一样。

 

     编程举例:编写一个函数,把输入流中的所有英文字母变成大写字母,然后将结果写入到一个输出流对象中。用这个函数来将一个字符串的所有字符转换成大写。

方法一:

import java.io.*;

public class ByteArrayStream

{

       public static void main(String[] args)

       {

              // TODO: Add your code here

              String str="abcdefg";

              byte []source=str.getBytes();

              ByteArrayInputStream in=new ByteArrayInputStream(source);

              ByteArrayOutputStream out=new ByteArrayOutputStream();

              getUpperChar(in,out);

              byte []result=new byte[1024];

              result=out.toByteArray();

              System.out.println(new String(result));

              System.out.println(out.toString());

              try

              {

                     out.writeTo(new FileOutputStream("test.txt"));

              }

              catch(Exception ex)

              {

                     ex.printStackTrace();

              }    

       }

      

       public static void getUpperChar(InputStream in,OutputStream out)

       {

              int ch=0;

              try

              {

                     while((ch=in.read())!= -1)

                     {

                            int upperCh=Character.toUpperCase(ch);

                            out.write(upperCh);

                     }

              }

              catch(Exception e)

              {

                     e.printStackTrace();

              }    

       }    

}

方法二:

import java.io.*;

public class ByteArrayStream

{

       public static void main(String[] args)

       {

              // TODO: Add your code here

              byte []buf="hello".getBytes();

              ByteArrayInputStream bis=new ByteArrayInputStream(buf);

              ByteArrayOutputStream bos=new ByteArrayOutputStream();

              changeChar(bis,bos);

              changeChar(System.in,System.out);

             

       }    

      

       public static void changeChar(InputStream in,OutputStream out)

       {

              try

              {

                     int ch=0;

                     int pos=0;

                     byte []buf=new byte [1024];

                     while((ch=in.read())!=-1)

                     {

                            int charUPP=Character.toUpperCase(ch);

                            out.write(buf[pos++]=(byte)charUPP);

                     }

                     System.out.println(new String(buf,0,pos));

              }

              catch(Exception e)

              {

                     e.printStackTrace();

              }

       }

}

     StringReader类和StringWriter类以字符IO流的方式处理字符串

StringReader类的构造函数:

构造方法摘要

StringReader(String s)
          
创建一个新字符串 reader其源为一个字符串的字符流。

 

StringWriter类的构造函数:

构造方法摘要

StringWriter()
          
创建具有默认初始字符串缓冲区大小的新字符串 writer

 

StringWriter(int initialSize)
          
创建具有指定初始字符串缓冲区大小的新字符串 writer

 

StringWriter类的方法:

方法摘要

 StringWriter

append(char c)
          
将指定字符追加到此 writer

 StringWriter

append(CharSequence csq)
          
将指定的字符序列追加到此 writer

 StringWriter

append(CharSequence csq, int start, int end)
          
将指定字符序列的子序列追加到此 writer

 void

close()
          
关闭 StringWriter 无效。

 void

flush()
          
刷新该流的缓冲。

 StringBuffer

getBuffer()
          
返回该字符串缓冲区本身。

 String

toString()
          
以字符串的形式返回该缓冲区的当前值。

 void

write(char[] cbuf, int off, int len)
          
写入字符数组的某一部分。

 void

write(int c)
          
写入单个字符。

 void

write(String str)
          
写入一个字符串。

 void

write(String str, int off, int len)
          
写入字符串的某一部分。

例:用StringReaderStringWriter改写上面的例子程序

import java.io.*;

public class TestStringReader

{

       public static void main(String[] args)

       {

              // TODO: Add your code here

              String strTemp=new String("hello world.");

              StringReader sr=new StringReader(strTemp);

              StringWriter sw=new StringWriter();

              changUpper(sr,sw);

              System.out.println(sw.toString());

       }

      

       public static void changUpper(Reader re,Writer wr)

       {

              int ch=0;

              try

              {

                     while((ch=re.read())!=-1)

                     {

                            int upperCh=Character.toUpperCase(ch);

                            wr.write(upperCh);

                     }    

              }

              catch(Exception e)

              {

                     e.printStackTrace();

              }    

       }    

}

 

重视IO程序代码的复用

                                                                                                                                    

     System.in连接到键盘,是InputStream类的实例对象。System.out连接到显示器,是PrintStream类的实例对象。

     不管各种底层物理设备用什么方式实现数据的终止点,InputStreamread方法总是返回-1来表示输入流的结束。

     Windows下按下Ctrl+Z组合键可以产生键盘输入流的结束标记,在Linux下,则是按下Ctrl+D组合键来产生键盘输入流的结束标记。

编程举例:借助上一页编写的函数,将键盘国输入的内容转变成大写字母后打印在屏幕上。

import java.io.*;

public class TestSystem

{

       public static void main(String[] args)

       {

              // TODO: Add your code here

              System.out.println("输入将变成大写字母的小写字母:");

              changUpper(System.in,System.out);

       }

      

       public static void changUpper(InputStream in,OutputStream out)

       {

              int ch=0;

              try

              {

                     while((ch=in.read())!=-1)

                     {

                            int upperCh=Character.toUpperCase(ch);

                            out.write(upperCh);

                     }    

              }

              catch(Exception e)

              {

                     e.printStackTrace();

              }

       }    

}

建议要编写从键盘上连续读取一大段数据时,应尽量将读取数据的过程放在函数中完成,使用-1来作为键盘输入的结束点。在该函数中编写的程序代码不应直接使用System.in读取数据,而是用一个InputStream类型形式参数对象来读取数据,然后将System.in作为实参传递给InputStream类型的形式参数来调用函数。

 

字符编码

                                                                                                                                   

     计算机里只有数字,计算机软件里的一切都是用数字来表示的,屏幕上显示的一个个字符也不例外。

     字符a对应数字97,字符b对应数字为98等,这种字符与数字对应的编码规则被称为ASCII(美国标准信息交换码)码。ASCII的最高bit位都是0,也就是说这些数字都在0127之间。

     .中国大陆将每一个中文字符才用两个字节的数字来表示,中文字符的每个字节的最高bit都是1,中国大陆为每个中文字符制定的编码规则称为GB2312(国标码)。

     GB2312的基础上,对更多的中文字符(包括繁体)进行了编码,新的编码规则称为GBK

     在中国大陆使用的计算机系统上,GBKGB2312就被称为系统的本地字符集。

     “中国”的“中”字,在中国大陆的编码是十六进制的D6D0,而在中国台湾的编码中十六进制的A4A4,台湾地区对中文字符集的编码规则称为BIG5(大五码)。

     在一个国家的本地系统中出现的一个字符,通过电子邮件传送到另外一个国家的本地化系统中,看到的就不是那个原始字符了,而是另外那个国家的一个字符或乱码。

 

Unicode编码

                                                                                                                                    

     ISO(国际标准化组织)将全世界所有的符号进行了统一编码,称之为Unicode编码。

     “中”这个符号,在全世界的任何角落始终对应的都是一个十六进制的数字4e2d

     如果所有的计算机系统都使用Unicode编码,在中国大陆的本地化系统中显示的“中”这个符号,发送到伊拉克的本地化系统中,显示的仍然是“中”这个符号。

     Unicode编码的字符都占用两个字节的大小,对于ASCII码所表示的字符,只是简单地在ASCII码原来占用的一个字节前面,增加一个所有bits0的字节。

     Unicode只占用两个字节,在全世界范围内所表示的字符个数不会超过216次方(65536),实际上Unicode编码中还保留了两千多个数值没有用于字符编码。

     在相当长的一段时期内,本地化字符编码将与Unicode编码共存。

     Java中的字符使用的都是Unicode编码,Java在通过Unicode保证跨平台特性的前提下,也支持本地平台字符集。

 

UTF-8编码

                                                                                                                                    

     ASCII码字符保持原样,仍然只占用一个字节,对于其它国家的字符,UTF-8使用两个或三个字节表示。使用UTF-8编码的文件,通常都要用EF BB BF作为文件开关的三个字节数据。

 

字符编码的操作体验

                                                                                                                                    

     查看中文字符的GB2312

     查看中文字符的UTF-8

     查看中文字符的Unicode

     Windows记事本程序中用不同的编码格式存储文本文件

UTF-8的优点:

     不出现内容为0x00字节

     便于应用程序检测数据在传输过程中是否发生了错误。

     直接处理使用ASCII码的英文文档。

UTF-8的缺点:

     有的字符要占用3个字节。

 

UTF-16编码

                                                                                                                                    

     UTF-16编码在Unicode基础上进行了一些细节上的扩充,增加了对Unicode编码没有包括的那些字符的表示方式。

     UTF-16Unicode的扩充并没有影响Unicode编码所包括的那些字符,只是增加了对Unicode编码没有包括的那些字符的表示方式,一个使用Unicode编码的字符就是UTF-16格式的。

     Unicode编码将0xD800-0xDFFF区间的数值保留出来,UTF-16扩充的字符,占用四个字节,前面两个字节的数值为0xD800-0xD8FF之间,后面两个字节的数值为0xDC00-0xDFFF之间。

     在不同体系结构的计算机系统中,UTF-16编码的Unicode字符在内存中的字节存储顺序是不同的。

     对于0x1234这样一个双字节数据,使用Little-EndianBig-Endian两种方式在内存中存储的格式如图所示:

 

     如果文件以0xFE 0xFF这两个字节开头,则表明文本的其余部分是Big-EndianUTF-16编码;如果文件以0xFF 0xFE两个字节开头,则表明文本的其余部分是Little-EndianUTF-16编码。

 

字符编码的编程体验

                                                                                                                                    

     打印中文字符的Unicode

     打印中文字符的GB2312

     验证写入到屏幕输出流的中文字符所采用的编码

     查看系统的缺省编码

     修改系统的缺省编码

     验证从键盘输入流中读取的中文字符所采用的编码

     研究GB2312码到Unicode码的解码过程

     GB2312码的中文字符被按照ISO8859-1字符集解码生成了Unicode字符串后,如何将这个字符串转换成正确Unicode编码字符串

 

public class TestCode

{

       public static void main(String[] args) throws Exception

       {

              // TODO: Add your code here

              String str="中国";

              System.out.println("打印"+"\""+str+"\""+"每个字符Unicode:");

              for(int i=0;i<str.length();i++)

              {

                     System.out.println(Integer.toHexString((int)str.charAt(i)));

              }

             

              byte []buf=str.getBytes(/*"GB2312"*/);

              System.out.println("打印"+"\""+str+"\""+"每个字符GB2312:");

              for(int i=0;i<buf.length;i++)

              {

                     System.out.println(Integer.toHexString(buf[i]));

              }

             

              System.out.println("验证写入到屏幕输出流的字符"+"\""+str+"\""+"所采用的编码:");

              for(int i=0;i<buf.length;i++)

              {

                     System.out.write(buf[i]);

              }

              System.out.println();

              /*System.out.write(buf);

              System.out.println();*/

             

              System.out.println("查看系统的缺省编码:");

              System.getProperties().list(System.out);

             

              System.out.println("修改系统的缺省编码");

              //System.setProperty("file.encoding","ISO8859-1");

              System.getProperties().put("file.encoding","ISO8859-1");

              System.getProperties().list(System.out);

       }    

}

 

public class TestDecode

{

 

       public static void main(String[] args) throws Exception

       {

              int ch=0;

              byte []buf=new byte [1024];

              int pos=0;

              String strInfo=null;

              System.setProperty("file.encoding","iso8859-1");

              System.out.println("请输入一串中文字符:");

              while(true)

              {

                     ch=System.in.read();

                     System.out.println(Integer.toHexString(ch));

                     switch(ch)

                     {

                            case '\r':

                                   break;

                            case '\n':

                                   strInfo=new String(buf,0,pos/*,"Gb2312"*/);

                                   for(int i=0;i<strInfo.length();i++)

                                   {

                                          System.out.println(Integer.toHexString(strInfo.charAt(i)));

                                   }

                                   System.out.println("中国");

                                   System.out.println(new String(strInfo.getBytes("ISO8859-1"),"GBK"));

                                   pos=0;

                                   break;

                            default:

                                   buf[pos++]=(byte)ch;   

                     }

              }

       }    

}

过滤流与包装类

                                                                                                                                  

     包装类的概念与作用

     BufferedInputStreamBufferedOutputStream

     DataInputStreamDataOutputStream

     PrintStream

     ObjectInputStreamObjectOutputStream

     字节流与字符流的转换

 

包装类的概念与作用

DataInputStreamDataOutputStream

                                                                                                                                                                                

     DataOutputStream类的提供了往各种输出流对象中写入各种类型的数据的方法。传递一个FileOutputStream输出流对象给DataOutputStream实例对象和调用DataOutputStream实例对象的方法。

     DataOutputStream并没有对应到任何具体的流设备,一定要给它传递一个对应具体流设备的输出流对象。完成类似DataOutputStream功能的类就是一个包装类,也叫过滤类或处理流类

 

构造方法摘要

DataInputStream(InputStream in)
          
使用指定的底层 InputStream 创建一个 DataInputStream

 

 方法摘要

 int

read(byte[] b)
          
从包含的输入流中读取一定数量的字节,并将它们存储到缓冲区数组 b 中。

 int

read(byte[] b, int off, int len)
          
从包含的输入流中将最多 len 个字节读入一个 byte 数组中。

 boolean

readBoolean()
          
参见 DataInput readBoolean 方法的常规协定。

 byte

readByte()
          
参见 DataInput readByte 方法的常规协定。

 char

readChar()
          
参见 DataInput readChar 方法的常规协定。

 double

readDouble()
          
参见 DataInput readDouble 方法的常规协定。

 float

readFloat()
          
参见 DataInput readFloat 方法的常规协定。

 void

readFully(byte[] b)
          
参见 DataInput readFully 方法的常规协定。

 void

readFully(byte[] b, int off, int len)
          
参见 DataInput readFully 方法的常规协定。

 int

readInt()
          
参见 DataInput readInt 方法的常规协定。

 String

readLine()
          
已过时。 该方法无法将字节正确转换为字符。从 JDK 1.1 开始,读取文本行的首选方法是使用 BufferedReader.readLine() 方法。使用 DataInputStream 类读取文本行的程序可以改为使用 BufferedReader 类,只要将以下形式的代码:

     DataInputStream d = new DataInputStream(in);
 

替换为:

     BufferedReader d
          = new BufferedReader(new InputStreamReader(in));
 

 long

readLong()
          
参见 DataInput readLong 方法的常规协定。

 short

readShort()
          
参见 DataInput readShort 方法的常规协定。

 int

readUnsignedByte()
          
参见 DataInput readUnsignedByte 方法的常规协定。

 int

readUnsignedShort()
          
参见 DataInput readUnsignedShort 方法的常规协定。

 String

readUTF()
          
参见 DataInput readUTF 方法的常规协定。

static String

readUTF(DataInput in)
          
从流 in 中读取用 UTF-8 修改版格式编码的 Unicode 字符格式的字符串;然后以 String 形式返回此字符串。

 int

skipBytes(int n)
          
参见 DataInput skipBytes 方法的常规协定。

 

构造方法

DataOutputStream(OutputStream out)
          
创建一个新的数据输出流,将数据写入指定基础输出流。

 

方法摘要

 void

flush()
          
清空此数据输出流。

 int

size()
          
返回计数器 written 的当前值,即到目前为止写入此数据输出流的字节数。

 void

write(byte[] b, int off, int len)
          
将指定 byte 数组中从偏移量 off 开始的 len 个字节写入基础输出流。

 void

write(int b)
          
将指定字节(参数 b 的八个低位)写入基础输出流。

 void

writeBoolean(boolean v)
          
将一个 boolean 值以 1-byte 值形式写入基础输出流。

 void

writeByte(int v)
          
将一个 byte 值以 1-byte 值形式写出到基础输出流中。

 void

writeBytes(String s)
          
将字符串按字节顺序写出到基础输出流中。

 void

writeChar(int v)
          
将一个 char 值以 2-byte 值形式写入基础输出流中,先写入高字节。

 void

writeChars(String s)
          
将字符串按字符顺序写入基础输出流。

 void

writeDouble(double v)
          
使用 Double 类中的 doubleToLongBits 方法将 double 参数转换为一个 long 值,然后将该 long 值以 8-byte 值形式写入基础输出流中,先写入高字节。

 void

writeFloat(float v)
          
使用 Float 类中的 floatToIntBits 方法将 float 参数转换为一个 int 值,然后将该 int 值以 4-byte 值形式写入基础输出流中,先写入高字节。

 void

writeInt(int v)
          
将一个 int 值以 4-byte 值形式写入基础输出流中,先写入高字节。

 void

writeLong(long v)
          
将一个 long 值以 8-byte 值形式写入基础输出流中,先写入高字节。

 void

writeShort(int v)
          
将一个 short 值以 2-byte 值形式写入基础输出流中,先写入高字节。

 void

writeUTF(String str)
          
以与机器无关方式使用 UTF-8 修改版编码将一个字符串写入基础输出流。

 

 

 

BufferedInputStreamBufferedOutputStream

                                                                                                                                   

     缓冲流为I/O流增加了内存缓冲区,增加缓冲区有两个基本目的:

            n允许Java程序一次不只操作一个字节,这样提高了程序的性能。

            n由于有了缓冲区,使得在流上执行skipmartreset方法都成为可能。、

     BufferedInputStreamBufferedOutputStreamjava提供的两个缓冲区包装类,不管底层系统是否使用了缓冲区,这两个类在自己的实例对象中创建缓冲区。这种缓冲区与底层系统提供的缓冲区的区别:底层系统提供的系统缓冲区直接与目标设备交换数据,而包装类提供的缓冲区需要调用包装类所包装的输出流对象将缓冲区的数据写入到目标或底层缓冲区中,或者调用包装类所包装的输入流对象从目标设备或底层缓冲区中读取数据到包装类的缓冲区中。底层缓冲区可以一次从硬盘读取大量数据或者一次向硬盘写入大量数据,而BufferedInputStream一次只能从底层缓冲区中读取一个数据,将读取到数据缓存到BufferedOutputStream缓冲区中,然后一次读取多个数据。

 

 

构造方法摘要

BufferedInputStream(InputStream in)
          
创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。

 

BufferedInputStream(InputStream in, int size)
          
创建具有指定缓冲区大小的 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。

 

方法摘要

 int

available()
          
返回可以从此输入流读取(或跳过)、且不受此输入流接下来的方法调用阻塞的估计字节数。

 void

close()
          
关闭此输入流并释放与该流关联的所有系统资源。

 void

mark(int readlimit)
          
参见 InputStream mark 方法的常规协定。

 boolean

markSupported()
          
测试此输入流是否支持 mark reset 方法。

 int

read()
          
参见 InputStream read 方法的常规协定。

 int

read(byte[] b, int off, int len)
          
从此字节输入流中给定偏移量处开始将各字节读取到指定的 byte 数组中。

 void

reset()
          
参见 InputStream reset 方法的常规协定。

 long

skip(long n)
          
参见 InputStream skip 方法的常规协定。

 

构造方法摘要

BufferedOutputStream(OutputStream out)
          
创建一个新的缓冲输出流,以将数据写入指定的底层输出流。

 

BufferedOutputStream(OutputStream out, int size)
          
创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流。

 

 

方法摘要

 void

flush()
          
刷新此缓冲的输出流。

 void

write(byte[] b, int off, int len)
          
将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此缓冲的输出流。

 void

write(int b)
          
将指定的字节写入此缓冲的输出流

 

编程实例:分别使用DataOutputStream类的writerUTFwriterByteswriterChars方法,比较这几个方法的差异。程序中所使用的流栈如下:

     关闭流栈中的最上层的流对象,将会自动关闭流栈中的所有底层流对象

 

import java.io.*;

public class DataStreamTest

{

       public static void main(String[] args) throws Exception

       {

              // TODO: Add your code here

              FileOutputStream fos=new FileOutputStream("test.txt");

              BufferedOutputStream bos=new BufferedOutputStream(fos);

              DataOutputStream dos=new DataOutputStream(bos);

              dos.writeUTF("ab中国");

              dos.writeChars("ab中国");

              dos.writeBytes("ab中国");

              dos.close();

             

              FileInputStream fis=new FileInputStream("test.txt");

              BufferedInputStream bis=new BufferedInputStream(fis);

              DataInputStream dis=new DataInputStream(bis);

              System.out.println(dis.readUTF());

              byte []buf=new byte [1024];

              int len=dis.read(buf);

              System.out.println(len);

              System.out.println(new String(buf,0,len));

              System.out.println();

              dis.close();

       }    

}

 

BufferedReaderBufferedWriter

                                                                                                                                      

BufferedReader从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。通常,Reader 所作的每个读取请求都会导致对底层字符或字节流进行相应的读取请求。因此,建议用 BufferedReader 包装所有其 read() 操作可能开销很高的 Reader(如 FileReader 和 InputStreamReader)。例如:

 BufferedReader in = new BufferedReader(new FileReader("foo.in"));
将缓冲指定文件的输入。如果没有缓冲,则每次调用 read() 或 readLine() 都会导致从文件中读取字节,并将其转换为字符后返回,而这是极其低效的。

 

构造方法摘要

BufferedReader(Reader in)
          
创建一个使用默认大小输入缓冲区的缓冲字符输入流。

 

BufferedReader(Reader in, int sz)
          
创建一个使用指定大小输入缓冲区的缓冲字符输入流。

 

方法摘要

 void

close()
          
关闭该流并释放与之关联的所有资源。

 void

mark(int readAheadLimit)
          
标记流中的当前位置。

 boolean

markSupported()
          
判断此流是否支持 mark() 操作(它一定支持)。

 int

read()
          
读取单个字符。

 int

read(char[] cbuf, int off, int len)
          
将字符读入数组的某一部分。

 String

readLine()
          
读取一个文本行。

 boolean

ready()
          
判断此流是否已准备好被读取。

 void

reset()
          
将流重置到最新的标记。

 long

skip(long n)
          
跳过字符。

BufferedWriter将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入通常 Writer 将其输出立即发送到底层字符或字节流。除非要求提示输出,否则建议用 BufferedWriter 包装所有其 write() 操作可能开销很高的 Writer(如 FileWriters 和 OutputStreamWriters)。例如,

 PrintWriter out
   = new PrintWriter(new BufferedWriter(new FileWriter("foo.out")));

将缓冲 PrintWriter 对文件的输出。如果没有缓冲,则每次调用 print() 方法会导致将字符转换为字节,然后立即写入到文件,而这是极其低效的。

构造方法摘要

BufferedWriter(Writer out)
          
创建一个使用默认大小输出缓冲区的缓冲字符输出流。

 

BufferedWriter(Writer out, int sz)
          
创建一个使用给定大小输出缓冲区的新缓冲字符输出流。

 

方法摘要

 void

close()
          
关闭此流,但要先刷新它。

 void

flush()
          
刷新该流的缓冲。

 void

newLine()
          
写入一个行分隔符。

 void

write(char[] cbuf, int off, int len)
          
写入字符数组的某一部分。

 void

write(int c)
          
写入单个字符。

 void

write(String s, int off, int len)
          
写入字符串的某一部分。

 

BufferedReaderreadLine方法可以一次读取一行文本,BufferedWriternewLine方法可以向字符流中写入不同操作系统下的换行符。

 

PrintStream

                                                                                                                                      

PrintStream 为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。它还提供其他两项功能。与其他输出流不同,PrintStream 永远不会抛出 IOException;而是,异常情况仅设置可通过 checkError 方法测试的内部标志。另外,为了自动刷新,可以创建一个 PrintStream这意味着可在写入 byte 数组之后自动调用 flush 方法,可调用其中一个 println 方法,或写入一个换行符或字节 ('\n')

PrintStream 打印的所有字符都使用平台的默认字符编码转换为字节。在需要写入字符而不是写入字节的情况下,应该使用 PrintWriter 类。

     PrintStream类提供了一系列的printprintln方法,可以将基本数据类型的数据格式化成字符串输出。

     格式化输出是什么意思?例如:97被格式化输出的实际字节数据为0x390x37

构造方法摘要

PrintStream(File file)
          
创建具有指定文件且不带自动行刷新的新打印流。

 

PrintStream(File file, String csn)
          
创建具有指定文件名称和字符集且不带自动行刷新的新打印流。

 

PrintStream(OutputStream out)
          
创建新的打印流。

 

PrintStream(OutputStream out, boolean autoFlush)
          
创建新的打印流。

 

PrintStream(OutputStream out, boolean autoFlush, String encoding)
          
创建新的打印流。

 

PrintStream(String fileName)
          
创建具有指定文件名称且不带自动行刷新的新打印流。

 

PrintStream(String fileName, String csn)
          
创建具有指定文件名称和字符集且不带自动行刷新的新打印流。

 

 方法摘要

 PrintStream

append(char c)
          
将指定字符添加到此输出流。

 PrintStream

append(CharSequence csq)
          
将指定字符序列添加到此输出流。

 PrintStream

append(CharSequence csq, int start, int end)
          
将指定字符序列的子序列添加到此输出流。

 boolean

checkError()
          
刷新流并检查其错误状态。

protected  void

clearError()
          
清除此流的内部错误状态。

 void

close()
          
关闭流。

 void

flush()
          
刷新该流的缓冲。

 PrintStream

format(Locale l, String format, Object... args)
          
使用指定格式字符串和参数将格式化字符串写入此输出流中。

 PrintStream

format(String format, Object... args)
          
使用指定格式字符串和参数将格式化字符串写入此输出流中。

 void

print(boolean b)
          
打印 boolean 值。

 void

print(char c)
          
打印字符。

 void

print(char[] s)
          
打印字符数组。

 void

print(double d)
          
打印双精度浮点数。

 void

print(float f)
          
打印浮点数。

 void

print(int i)
          
打印整数。

 void

print(long l)
          
打印 long 整数。

 void

print(Object obj)
          
打印对象。

 void

print(String s)
          
打印字符串。

 PrintStream

printf(Locale l, String format, Object... args)
          
使用指定格式字符串和参数将格式化的字符串写入此输出流的便捷方法。

 PrintStream

printf(String format, Object... args)
          
使用指定格式字符串和参数将格式化的字符串写入此输出流的便捷方法。

 void

println()
          
通过写入行分隔符字符串终止当前行。

 void

println(boolean x)
          
打印 boolean 值,然后终止行。

 void

println(char x)
          
打印字符,然后终止该行。

 void

println(char[] x)
          
打印字符数组,然后终止该行。

 void

println(double x)
          
打印 double,然后终止该行。

 void

println(float x)
          
打印 float,然后终止该行。

 void

println(int x)
          
打印整数,然后终止该行。

 void

println(long x)
          
打印 long,然后终止该行。

 void

println(Object x)
          
打印 Object,然后终止该行。

 void

println(String x)
          
打印 String,然后终止该行。

protected  void

setError()
          
将该流的错误状态设置为 true

 void

write(byte[] buf, int off, int len)
          
len 字节从指定的初始偏移量为 off byte 数组写入此流。

 void

write(int b)
          
将指定的字节写入此流。

 

PrintWriter

                                                                                                                                      

向文本输出流打印对象的格式化表示形式。此类实现在 PrintStream 中的所有 print 方法。它不包含用于写入原始字节的方法,对于这些字节,程序应该使用未编码的字节流进行写入。与 PrintStream 类不同,如果启用了自动刷新,则只有在调用 printlnprintf format 的其中一个方法时才可能完成此操作,而不是每当正好输出换行符时才完成。这些方法使用平台自有的行分隔符概念,而不是换行符。此类中的方法不会抛出 I/O 异常,尽管其某些构造方法可能抛出异常。客户端可能会查询调用 checkError() 是否出现错误

     PrintStream对应的PrintWriter类,即使遇到了文本换行标识符(\n),PrintWriter类也不会自动清空缓冲区。

     PrintWriterprintln方法能根据操作系统的不同而生成相应的文本换行标识符。在Windows下的文本换行标识符是”\r\n”,而Linux下的文本换行标识符是”\n”

构造方法摘要

PrintWriter(File file)
          
使用指定文件创建不具有自动行刷新的新 PrintWriter

 

PrintWriter(File file, String csn)
          
创建具有指定文件和字符集且不带自动刷行新的新 PrintWriter

 

PrintWriter(OutputStream out)
          
根据现有的 OutputStream 创建不带自动行刷新的新 PrintWriter

 

PrintWriter(OutputStream out, boolean autoFlush)
          
通过现有的 OutputStream 创建新的 PrintWriter

 

PrintWriter(String fileName)
          
创建具有指定文件名称且不带自动行刷新的新 PrintWriter

 

PrintWriter(String fileName, String csn)
          
创建具有指定文件名称和字符集且不带自动行刷新的新 PrintWriter

 

PrintWriter(Writer out)
          
创建不带自动行刷新的新 PrintWriter

 

PrintWriter(Writer out, boolean autoFlush)
          
创建新 PrintWriter

 

 方法摘要

 PrintWriter

append(char c)
          
将指定字符添加到此 writer

 PrintWriter

append(CharSequence csq)
          
将指定的字符序列添加到此 writer

 PrintWriter

append(CharSequence csq, int start, int end)
          
将指定字符序列的子序列添加到此 writer

 boolean

checkError()
          
如果流没有关闭,则刷新流且检查其错误状态。

protected  void

clearError()
          
清除此流的错误状态。

 void

close()
          
关闭该流并释放与之关联的所有系统资源。

 void

flush()
          
刷新该流的缓冲。

 PrintWriter

format(Locale l, String format, Object... args)
          
使用指定格式字符串和参数将一个格式化字符串写入此 writer 中。

 PrintWriter

format(String format, Object... args)
          
使用指定格式字符串和参数将一个格式化字符串写入此 writer 中。

 void

print(boolean b)
          
打印 boolean 值。

 void

print(char c)
          
打印字符。

 void

print(char[] s)
          
打印字符数组。

 void

print(double d)
          
打印 double 精度浮点数。

 void

print(float f)
          
打印一个浮点数。

 void

print(int i)
          
打印整数。

 void

print(long l)
          
打印 long 整数。

 void

print(Object obj)
          
打印对象。

 void

print(String s)
          
打印字符串。

 PrintWriter

printf(Locale l, String format, Object... args)
          
使用指定格式字符串和参数将格式化的字符串写入此 writer 的便捷方法。

 PrintWriter

printf(String format, Object... args)
          
使用指定格式字符串和参数将格式化的字符串写入此 writer 的便捷方法。

 void

println()
          
通过写入行分隔符字符串终止当前行。

 void

println(boolean x)
          
打印 boolean 值,然后终止该行。

 void

println(char x)
          
打印字符,然后终止该行。

 void

println(char[] x)
          
打印字符数组,然后终止该行。

 void

println(double x)
          
打印双精度浮点数,然后终止该行。

 void

println(float x)
          
打印浮点数,然后终止该行。

 void

println(int x)
          
打印整数,然后终止该行。

 void

println(long x)
          
打印 long 整数,然后终止该行。

 void

println(Object x)
          
打印 Object,然后终止该行。

 void

println(String x)
          
打印 String,然后终止该行。

protected  void

setError()
          
指示已发生错误。

 void

write(char[] buf)
          
写入字符数组。

 void

write(char[] buf, int off, int len)
          
写入字符数组的某一部分。

 void

write(int c)
          
写入单个字符。

 void

write(String s)
          
写入字符串。

 void

write(String s, int off, int len)
          
写入字符串的某一部分。

 

ObjectInputStream

                                                                                                                                    

ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。ObjectOutputStreamObjectInputStream 分别与 FileOutputStream FileInputStream 一起使用时,可以为应用程序提供对对象图形的持久存储。ObjectInputStream 用于恢复那些以前序列化的对象。其他用途包括使用套接字流在主机之间传递对象,或者用于编组和解组远程通信系统中的实参和形参。只有支持 java.io.Serializable java.io.Externalizable 接口的对象才能从流读取。

readObject 方法用于从流读取对象。应该使用 Java 的安全强制转换来获取所需的类型。在Java中,字符串和数组都是对象,所以在序列化期间将其视为对象。读取时,需要将其强制转换为期望的类型。可以使用 DataInput上的适当方法从流读取基本数据类型。

默认情况下,对象的反序列化机制会将每个字段的内容恢复为写入时它所具有的值和类型。反序列化进程将忽略声明为瞬态或静态的字段。对其他对象的引用使得根据需要从流中读取这些对象。使用引用共享机制能够正确地恢复对象的图形。反序列化时始终分配新对象,这样可以避免现有对象被重写。

读取对象类似于运行新对象的构造方法。为对象分配内存并将其初始化为零 (NULL)。为不可序列化类调用无参数构造方法,然后从以最接近 java.lang.object 的可序列化类开始和以对象的最特定类结束的流恢复可序列化类的字段。

例如,要从由 ObjectOutputStream 中的示例写入的流读取:

        FileInputStream fis = new FileInputStream("t.tmp");
        ObjectInputStream ois = new ObjectInputStream(fis);
        int i = ois.readInt();
        String today = (String) ois.readObject();
        Date date = (Date) ois.readObject();
         ois.close();

 

类控制实现 java.io.Serializable java.io.Externalizable 接口时的序列化方式。

实现 Serializable 接口允许对象序列化,以保存和恢复对象的全部状态,并且允许类在写入流时的状态和从流读取时的状态之间变化。它自动遍历对象之间的引用,保存和恢复全部图形。

 

构造方法摘要

protected

ObjectInputStream()
          
为完全重新实现 ObjectInputStream 的子类提供一种方式,让它不必分配仅由 ObjectInputStream 的实现使用的私有数据。

 

ObjectInputStream(InputStream in)
          
创建从指定 InputStream 读取的 ObjectInputStream

 方法摘要

 int

available()
          
返回可以不受阻塞地读取的字节数。

 void

close()
          
关闭输入流。

 void

defaultReadObject()
          
从此流读取当前类的非静态和非瞬态字段。

protected  boolean

enableResolveObject(boolean enable)
          
使流允许从该流读取的对象被替代。

 int

read()
          
读取数据字节。

 int

read(byte[] buf, int off, int len)
          
读入 byte 数组。

 boolean

readBoolean()
          
读取一个 boolean 值。

 byte

readByte()
          
读取一个 8 位的字节。

 char

readChar()
          
读取一个 16 位的 char 值。

protected  ObjectStreamClass

readClassDescriptor()
          
从序列化流读取类描述符。

 double

readDouble()
          
读取一个 64 位的 double 值。

 ObjectInputStream.GetField

readFields()
          
按名称从流中读取持久字段并使其可用。

 float

readFloat()
          
读取一个 32 位的 float 值。

 void

readFully(byte[] buf)
          
读取字节,同时阻塞直至读取所有字节。

 void

readFully(byte[] buf, int off, int len)
          
读取字节,同时阻塞直至读取所有字节。

 int

readInt()
          
读取一个 32 位的 int 值。

 String

readLine()
          
已过时。 此方法不能正确地将字节转换为字符。请参见 DataInputStream 以获取详细信息和替代方法。

 long

readLong()
          
读取一个 64 位的 long 值。

 Object

readObject()
          
ObjectInputStream 读取对象。

protected  Object

readObjectOverride()
          
此方法由 ObjectOutputStream 的受信任子类调用,这些子类使用受保护的无参数构造方法构造 ObjectOutputStream

 short

readShort()
          
读取一个 16 位的 short 值。

protected  void

readStreamHeader()
          
提供的 readStreamHeader 方法允许子类读取并验证它们自己的流头部。

 Object

readUnshared()
          
ObjectInputStream 读取非共享对象。

 int

readUnsignedByte()
          
读取一个无符号的 8 位字节。

 int

readUnsignedShort()
          
读取一个无符号的 16 short 值。

 String

readUTF()
          
读取 UTF-8 修改版格式的 String

 void

registerValidation(ObjectInputValidation obj, int prio)
          
在返回图形前注册要验证的对象。

protected  Class<?>

resolveClass(ObjectStreamClass desc)
          
加载指定流类描述的本地等价类。

protected  Object

resolveObject(Object obj)
          
在反序列化期间,此方法允许 ObjectInputStream 的受信任子类使用一个对象替代另一个。

protected  Class<?>

resolveProxyClass(String[] interfaces)
          
返回一个代理类,该类实现在代理类描述符中命名的接口;子类可以实现此方法,以便从流及动态代理类的描述符中读取自定义数据,允许它们使用接口和代理类的替换加载机制。

 int

skipBytes(int len)
          
跳过字节。

 

     ObjectInputStreamObjectOutputStream这两个包装类,用于从底层输入流中读取对象类型的数据和将对象类型的数据写入到底层输出流。

     ObjectInputStreamObjectOutputStream类所读写的对象必须实现了Serializable接口。对象中的transient(临时的)static类型的成员变量不会被读取和写入。

     一个可以被序列化的MyClass类的定义:

public class MyClass implements Serilizable

{

       public transient Thread t;

       private String customerID;

       private int total;

}

 

ObjectOutputStream

                                                                                                                                       

ObjectOutputStream Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储。如果流是网络套接字流,则可以在另一台主机上或另一个进程中重构对象。

只能将支持 java.io.Serializable 接口的对象写入流中。每个 serializable 对象的类都被编码,编码内容包括类名和类签名、对象的字段值和数组值,以及从初始对象中引用的其他所有对象的闭包。

writeObject 方法用于将对象写入流中。所有对象(包括 String 和数组)都可以通过 writeObject 写入。可将多个对象或基元写入流中。必须使用与写入对象时相同的类型和顺序从相应 ObjectInputstream 中读回对象。

还可以使用 DataOutput 中的适当方法将基本数据类型写入流中。还可以使用 writeUTF 方法写入字符串。

对象的默认序列化机制写入的内容是:对象的类,类签名,以及非瞬态和非静态字段的值。其他对象的引用(瞬态和静态字段除外)也会导致写入那些对象。可使用引用共享机制对单个对象的多个引用进行编码,这样即可将对象的图形恢复为最初写入它们时的形状。

例如,要写入可通过 ObjectInputStream 中的示例读取的对象,请执行以下操作:

        FileOutputStream fos = new FileOutputStream("t.tmp");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeInt(12345);
        oos.writeObject("Today");
        oos.writeObject(new Date());
        oos.close();

 

构造方法摘要

protected

ObjectOutputStream()
          
为完全重新实现 ObjectOutputStream 的子类提供一种方法,让它不必分配仅由 ObjectOutputStream 的实现使用的私有数据。

 

ObjectOutputStream(OutputStream out)
          
创建写入指定 OutputStream ObjectOutputStream

 方法摘要

protected  void

annotateClass(Class<?> cl)
          
子类可以实现此方法,从而允许在流中存储类数据。

protected  void

annotateProxyClass(Class<?> cl)
          
子类可以实现此方法,从而在流中存储定制数据和动态代理类的描述符。

 void

close()
          
关闭流。

 void

defaultWriteObject()
          
将当前类的非静态和非瞬态字段写入此流。

protected  void

drain()
          
排空 ObjectOutputStream 中的所有已缓冲数据。

protected  boolean

enableReplaceObject(boolean enable)
          
允许流对流中的对象进行替换。

 void

flush()
          
刷新该流的缓冲。

 ObjectOutputStream.PutField

putFields()
          
获取用于缓冲写入流中的持久存储字段的对象。

protected  Object

replaceObject(Object obj)
          
在序列化期间,此方法允许 ObjectOutputStream 的受信任子类使用一个对象替代另一个对象。

 void

reset()
          
重置将丢弃已写入流中的所有对象的状态。

 void

useProtocolVersion(int version)
          
指定要在写入流时使用的流协议版本。

 void

write(byte[] buf)
          
写入一个 byte 数组。

 void

write(byte[] buf, int off, int len)
          
写入字节的子数组。

 void

write(int val)
          
写入一个字节。

 void

writeBoolean(boolean val)
          
写入一个 boolean 值。

 void

writeByte(int val)
          
写入一个 8 位字节。

 void

writeBytes(String str)
          
以字节序列形式写入一个 String

 void

writeChar(int val)
          
写入一个 16 位的 char 值。

 void

writeChars(String str)
          
char 序列形式写入一个 String

protected  void

writeClassDescriptor(ObjectStreamClass desc)
          
将指定的类描述符写入 ObjectOutputStream

 void

writeDouble(double val)
          
写入一个 64 位的 double 值。

 void

writeFields()
          
将已缓冲的字段写入流中。

 void

writeFloat(float val)
          
写入一个 32 位的 float 值。

 void

writeInt(int val)
          
写入一个 32 位的 int 值。

 void

writeLong(long val)
          
写入一个 64 位的 long 值。

 void

writeObject(Object obj)
          
将指定的对象写入 ObjectOutputStream

protected  void

writeObjectOverride(Object obj)
          
子类用于重写默认 writeObject 方法的方法。

 void

writeShort(int val)
          
写入一个 16 位的 short 值。

protected  void

writeStreamHeader()
          
提供 writeStreamHeader 方法,这样子类可以将其自身的头部添加或预加到流中。

 void

writeUnshared(Object obj)
          
未共享对象写入 ObjectOutputStream

 void

writeUTF(String str)
          
UTF-8 修改版格式写入此 String 的基本数据。

 

编程举例:创建了一个可序列化的学生对象,并用ObjectOutputStream类把它存储到一个文件(student.txt)中,然后再用ObjectInputStream类把存储的数据读取到一个学生对象,即恢复保存的学生对象。

import java.io.Serializable;

 

public class Student implements Serializable

{

       String name="";

       int age;

       public Student(String name,int age)

       {

              this.name=name;

              this.age=age;

       }

}

 

import java.io.*;

public class ObjectStream

{

       public static void main(String[] args)

       {

              // TODO: Add your code here

              Student stu1=new Student("张三",18);

              Student stu2=new Student("李四",20);

              File f=new File("student.txt");

              try

              {

                     FileOutputStream fos=new FileOutputStream(f);

                     ObjectOutputStream oos=new ObjectOutputStream(fos);

                     oos.writeObject(stu1);

                     oos.writeObject(stu2);

                     oos.writeObject(new Date());

                     oos.close();

                    

                     FileInputStream fis=new FileInputStream(f);

                     ObjectInputStream ois=new ObjectInputStream(fis);

                     stu1=(Student)ois.readObject();

                     stu2=(Student)ois.readObject();

                     System.out.println("姓名="+stu1.name);

                     System.out.println("年龄="+stu1.age);

                     System.out.println("姓名="+stu2.name);

                     System.out.println("年龄="+stu2.age);

                     System.out.println((Date)ois.readObject());

                     ois.close();    

              }

              catch(Exception e)

              {

                     e.printStackTrace();

              }

       }    

}

 

InpuStreamReader

                                                                                                                                        

InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。

每次调用 InputStreamReader 中的一个 read() 方法都会导致从底层输入流读取一个或多个字节。要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节。

为了达到最高效率,可要考虑在 BufferedReader 内包装 InputStreamReader。例如:

 BufferedReader in
   = new BufferedReader(new InputStreamReader(System.in));

 

构造方法摘要

InputStreamReader(InputStream in)
          
创建一个使用默认字符集的 InputStreamReader

 

InputStreamReader(InputStream in, Charset cs)
          
创建使用给定字符集的 InputStreamReader

 

InputStreamReader(InputStream in, CharsetDecoder dec)
          
创建使用给定字符集解码器的 InputStreamReader

 

InputStreamReader(InputStream in, String charsetName)
          
创建使用指定字符集的 InputStreamReader

 

 方法摘要

 void

close()
          
关闭该流并释放与之关联的所有资源。

 String

getEncoding()
          
返回此流使用的字符编码的名称。

 int

read()
          
读取单个字符。

 int

read(char[] cbuf, int offset, int length)
          
将字符读入数组中的某一部分。

 boolean

ready()
          
判断此流是否已经准备好用于读取。

 

OutputStreamWriter

                                                                                                                                       

OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。

每次调用 write() 方法都会导致在给定字符(或字符集)上调用编码转换器。在写入底层输出流之前,得到的这些字节将在缓冲区中累积。可以指定此缓冲区的大小,不过,默认的缓冲区对多数用途来说已足够大。注意,传递给 write() 方法的字符没有缓冲。

为了获得最高效率,可考虑将 OutputStreamWriter 包装到 BufferedWriter 中,以避免频繁调用转换器。例如:

 BufferedWriter out
   = new BufferedWriter(new OutputStreamWriter(System.out));

 

字节流与字符流的转换

                                                                                                                      

     能不能找到一种简单的方式来读取键盘上输入的一行字符,如何找?

     InputStreamReaderOutputStreamWriter,是用于将字节流转换成字符流来读写的两个类,InputStreamReader可以将一个字节流中的字节解码成字符后读取,OutputStreamWriter将字符编码成字节后写入到一个字节流中。

      避免频繁地在字符与字节之间进行转换,最好不要直接使用InputStreamReaderOutputStreamWriter类来读写数据,应尽量使用BufferedWriter类包装OutputStreamWriter类,用BufferedReader类包装InputStreamReader

BufferedReader in

   = new BufferedReader(new InputStreamReader(System.in));

BufferedWriter out

   = new BufferedWriter(new OutputStreamWriter(System.out));

:

import java.io.*;

public class BufferedTest

{

       public static void main(String[] args) throws Exception

       {

              // TODO: Add your code here

              System.out.println("请输入文字:");

              BufferedReader br=new BufferedReader(new InputStreamReader(System.in));

              String str=br.readLine();

              br.close();

              //System.out.println(str);

             

              FileReader fr=new FileReader("b.txt");

              char[]buf=new char [1024];

              int len=fr.read(buf);

              String strInfo=new String(buf,0,len);

              BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(System.out));

              bw.write(strInfo);

              System.out.println(strInfo);

              bw.close();

             

             

              FileWriter fw=new FileWriter("buffered.txt");

              fw.write(str);

              fw.close();

             

              FileOutputStream fos=new FileOutputStream("fos.txt");

              byte[]buf=str.getBytes();

              fos.write(buf);

              fos.close();

             

              FileReader fr=new FileReader("a.txt");

              char[]bufChar=new char[1024];

              int len=fr.read(bufChar);

              System.out.println(new String(bufChar,0,len));

              fr.close();

       }    

}

 

Java程序与其它进程的数据通信

                                                                                                                                       

     Java程序中可以用Process类的实例对象来表示子进程,子进程的标准输入和输出不再连接到键盘和显示器,而是以管道流的形式连接到父进程的一个输出流和输入流对象上。

     调用ProcessgetOutputStreamgetInputStream方法可以获得连接到子进程的输出流和输入流对象。

     管道缓冲区满后,与PipedInputStream相连的PipedOutputStream无法再写入新的数据,PipedOutputStream.writer方法将处于阻塞状态。

     Process类的destroy方法结束子进程的运行。

     编程实例:在TestInOut类中启动java.exe命令执行另外一个MyTest类,TestInOutMyTest通过进程间的管道相互传递数据。

分析:

父进程(TestInOut)启动子进程(MyTest类),主线程(main)不停向子进程发送数据(send方法),另一线程不停从子进程中读取数据(run方法),在构造函数中启动子进程和一线程。

import java.io.*;

public class TestInOut implements Runnable

{

       Process p=null;

       public TestInOut()

       {

              try

              {

                     p=Runtime.getRuntime().exec("java MyTest");

                     new Thread(this).start();

              }

              catch(Exception e)

              {

                     e.printStackTrace();

              }

             

       }

       public static void main(String[] args)

       {

              // TODO: Add your code here

              TestInOut ti=new TestInOut();

              ti.send();

       }

 

       public void send()

       {

              try

              {

                     OutputStream ops=p.getOutputStream();

                     while(true)

                     {

                            ops.write("Hello\r\n".getBytes());

                     }

              }

              catch(Exception e)

              {

                     e.printStackTrace();

              }

       }

       public void run()

       {

              try

              {

                     InputStream ips=p.getInputStream();

                     BufferedReader br=new BufferedReader(new InputStreamReader(ips));

                     while(true)

                     {

                            String str=br.readLine();

                            if(str!=null)

                            {

                                   System.out.println(str);

                            }

                            else

                            {

                                   return ;

                            }    

                     }

              }

              catch(Exception e)

              {

                     e.printStackTrace();

              }

                    

       }

}

 

import java.io.*;

public class MyTest

{

       public static void main(String[] args)

       {

              // TODO: Add your code here

              try

              {

                     BufferedReader br=new BufferedReader(new InputStreamReader(System.in));

                     while(true)

                     {

                            String str=br.readLine();

                            if(str!=null)

                            {

                                   System.out.println(str+"World");

                            }

                            else

                            {

                                   return ;

                            }

                     }

              }

              catch(Exception e)

              {

                     e.printStackTrace();

              }

       }    

}

 

字节输入流类

                                                                                                                                      

字节输出流类

                                                                                                                                      

字符输入流类

                                                                                                                                      

字符输出流类

                                                                                                                                      

Decorator设计模式

                                                                                                                                      

     在程序中用一个对象(the Decorators)包装另外一个对象,这是一种被称为Decorator的设计模式。

     如果要设计自己的IO包装类,这个类需要继承以FilterXXX命名的类,例如,设计一对输入输出包装类:RecordInputStreamRecorderOutputStream,来完成从数据库文件中读取记录和往数据库文件中写入记录。

     Excption类从Throwable类继承的三个printStackTrace方法的定义如下:

        n Public void printStackTrace();

        n Public void printStackTrace(PrintStream s);

        nPublic void printStackTrace(PrintWriter s);

该如何把printStackTrace方法打出的详细异常信息存储到一个字符串中?

编写下面的程序代码,分析和观察程序的运行结果:

import java.io.*;

public class TestPrintWriter

{

      

       public static void main(String[] args) throws Exception

       {

              // TODO: Add your code here

              try

              {

                     throw new Exception("test");

              }

              catch(Exception e)

              {

                     /*StringWriter sw=new StringWriter();

                     PrintWriter pw=new PrintWriter(sw);

                     e.printStackTrace(pw);

                     System.out.println(sw.toString());

                     File f=new File("a.txt");

                     PrintStream ps=new PrintStream(f);

                     e.printStackTrace(ps);

                     FileInputStream fis=new FileInputStream(f);

                     byte []buf=new byte [1024];

                     int len=fis.read(buf);

                     System.out.println(new String(buf,0,len));*/

                     FileOutputStream fos=new FileOutputStream("b.txt");

                     PrintStream ps=new PrintStream(fos);

                     e.printStackTrace(ps);

                     System.out.println(fos.toString());

              }

       }    

}

思考与实践

                                                                                                                                      

编写下面的程序代码,分析和观察程序的运行结果:

import java.io.*;

class InputReader

{

       public static void main(String[] args) throws Exception

       {

              // TODO: Add your code here

              InputStreamReader ips=new InputStreamReader(System.in,"iso8859-1");

              BufferedReader br=new BufferedReader(ips);

              System.out.println("请输入文字:");

              String str=br.readLine();

              int len=str.length();

              for(int i=0;i<len;i++)

              {

                     System.out.println(Integer.toHexString((int)str.charAt(i)));

              }

              System.out.println(str); 

              ips.close();

       }    

}

程序运行结果:

请输入文字:

中国

d6

d0

b9

fa

???ú

请按照下面的两种要求修改上面的程序代码,让程序能够正常打印出输入的中文字符:

(1)     修改程序中的语句:     
                    InputStreamReader ips=new InputStreamReader(System.in,"iso8859-1");                        
               修改如下:                                                                                                        
                    InputStreamReader ips=new InputStreamReader(System.in);    

(2)     修改下面的语句:                                                                                                    
                    
System.out.println(str);

               修改如下:

                    System.out.println(new String(str.getBytes("iso8859-1"),"GBK"));

 

posted on 2007-08-21 12:55 大头剑客 阅读(4739) 评论(5)  编辑  收藏 所属分类: 学习笔记

评论

# re: 第七章 IO/输入与输出 2008-02-15 16:30 怎么羡慕天空的飞鸟

呵呵,挺全面啊!  回复  更多评论   

# re: 第七章 IO/输入与输出 2008-03-29 00:08 mfan

真好,谢谢啦  回复  更多评论   

# 求助[未登录] 2008-05-29 00:24 JAVA初学者

引用:● Unicode编码将0xD800-0xDFFF区间的数值保留出来,UTF-16扩充的字符,占用四个字节,前面两个字节的数值为0xD800-0xD8FF之间,后面两个字节的数值为0xDC00-0xDFFF之间。

请问一下大头剑客,1:怎么0xD900-0xDBFF这一段数值没有了?
2:还有张孝祥老师上课时说:前面两个字节的数值为0xD800-0xD8FF之间可包含1024个字符,后面两个字节的数值为0xDC00-0xDFFF之间可包含1024个字符,所以UTF-16扩充了1024*1024个字符.可我没想通,0xD800-0xD8FF之间应只能包含256个字符吗?后面两个字节的数值为0xDC00-0xDFFF之间确实只包含1024个字符,合起来UTF-16能扩充的字符数应是256*1024个字符啊.
不知我哪里理解错了.还望大头剑客指教.谢谢!
  回复  更多评论   

# 找到原因了[未登录] 2008-05-29 00:35 JAVA初学者

"前面两个字节的数值为0xD800-0xD8FF之间",是不是张孝祥老师课件中将"0xDBFF"误写成"0xD800"?  回复  更多评论   

# 找到原因了[未登录] 2008-05-29 00:38 JAVA初学者

刚才"找到原因了"那个贴了字打错了,以这个贴子为准.
前面两个字节的数值为0xD800-0xD8FF之间",是不是张孝祥老师课件中将"0xDBFF"误写成"0xD8FF"?  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航:
 
<2008年2月>
272829303112
3456789
10111213141516
17181920212223
2425262728291
2345678

导航

统计

公告

写字楼里写字间,写字间里程序员;
程序人员写程序,又拿程序换酒钱;
酒醒只在网上坐,酒醉还来网下眠;
酒醉酒醒日复日,网上网下年复年;
但愿老死电脑间,不愿鞠躬老板前;
奔驰宝马贵者趣,公交自行程序员;
别人笑我忒疯癫,我笑自己命太贱;
不见满街漂亮妹,哪个归得程序员.
不管前面是地雷阵还是万丈深渊,
我都将勇往直前,义无反顾,
鞠躬尽瘁,死而后已。
—— 朱镕基总理

常用链接

留言簿(1)

随笔档案

文章分类

文章档案

学习园地

最新随笔

搜索

积分与排名

最新评论