Java——IO流读写对象及流操作规律

来源:互联网 发布:labp是网络管理协议 编辑:程序博客网 时间:2024/05/22 00:24


IO流

概述:IO流就是用来进行数据的输入输出操作的一个缓冲区。
按操作的对象不同可分为:
   1、对字符操作
             Reader和Writer
   2、对字节操作
             InputStream和OutputStream

字符流:
   
FileWriter:是Writer的一个子类,用于进行文件的数据写入,以字符为操作单位。
首先要创建一个FileWriter对象,构造方法的参数要指定一个文件名,用来明确数据写入的位置。如:FileWriter fw = new FileWriter("demo.txt");
常用方法:
write() //将数据存储到字符流中,可以以字符串,字符,字符数组等为参数。
flush() //刷新字符流,将数据写入到目的地。
close() //刷新字符流,同时关闭字符流,调用后Writer对象不能使用。
示例:
import java.io.*;class FileWriterDemo{public static void main(String[] args) throws IOException{//创建一个FileWriter对象,该对象一被初始化,就必须要明确被操作的文件。//没有此文件 将创建文件,如有同名文件,将被覆盖。FileWriter fw = new FileWriter("demo.txt");//write方法将字符串写入到流中。fw.write("hello");//刷新缓冲区中数据,写入目的地中。//fw.flush();//关闭流,并刷新一次缓冲中的数据。 fw.close();}}


字符流读取方法
以FileReader为例:
常用方法:
    read() //读取一个字符,返回字符对应的ACSII码
    close() //关闭读取流
读取文件示例:
 

import java.io.*;class FileReaderDemo{public static void main(String[] args) throws IOException{//第一种读取方式:单个字符读取FileReader fr = new FileReader("demo.txt");while(true){ int c = fr.read(); if(c == -1)break; System.out.print((char)c);}fr.close(); //第二种方式:通过字符数组进行读取。//read(char[])返回的是读到的字符个数 FileReader fr2 = new FileReader("demo.txt");char[] buf = new char[1024];int num = 0;while((num = fr2.read(buf)) != -1) System.out.print(new String(buf, 0, num));fr2.close();}}


带缓冲区的字符读取和写入流:
BufferedReader和BufferedWriter:
这两个类封装了定义缓冲区的操作,在读取和写入时定义了字符数组作为缓冲区,避免了单个字符操作的低效率。建立对象时,需要传入对应的Reader和Writer对象作为参数。
    BufferedWriter:
    建立对象时格式应如:
          FileWriter fw = new FileWriter("test.txt");
          BufferedWriter bufw = new BufferedWriter(fw);
    特有方法:
          newLine() //添加一个换行符,自动通过系统获取,可以跨平台。
          BufferedReader:
    建立对象和上面方法类似。
    特有方法:
          readLine() //返回一个字符串,内容是读取一行字符的内容,到文本末尾返回null。
示例:
import java.io.*;class BufferedReaderDemo{public static void main(String[] args) throws IOException{FileReader fr = new FileReader("test.java");BufferedReader bufr = new BufferedReader(fr);String s = null;while((s = bufr.readLine()) != null){System.out.println(s);}}}
class BufferedWriterDemo{public static void main(String[] args) throws IOException{FileWriter fw = new FileWriter("buf.txt");BufferedWriter bufw = new BufferedWriter(fw);bufw.write("abcde");bufw.flush();bufw.close();//关闭缓冲区也直接关闭了FileWriter对象;}} 



装饰模式:
这种对原有Reader和Writer功能进行增强的设计模式成为装饰设计模式。
方法是在遇到一个定义好的类,并需要对其进行改进时,定义一个新类,将其作为新类的成员,并定义新方法,内部使用原有需要改进的方法,并加入新的代码。

这种设计模式的好处在于:
装饰模式比继承要灵活。避免了继承体系的臃肿,且降低了类与类之间的关系。
装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强的功能,所以装饰类和被装饰的类通常都是属于一个体系。
自定义BufferedReader:
下面用这种设计模式 自定义一个BufferedReader,主要以自定义的readLine()方法为例:
import java.io.*;//自定义BufferedReader类class MyBufferedReader extends Reader{private Reader r;MyBufferedReader(Reader r){this.r = r;}//一次读一行数据的方法public String myReadLine()throws IOException{//定义一个临时容器,原BufferedReader使用的是字符数组,//这里为了方便使用StringBuilder,StringBuilder sb = new StringBuilder();int ch = 0;while((ch = r.read()) != -1){//判断是否为行终止符if(ch == '\r')continue;if(ch == '\n')return sb.toString();elsesb.append((char)ch);}if(sb.length() != 0){return sb.toString();}return null;}public void close()throws IOException{r.close();}public int read(char[] cbuf, int off, int len)throws IOException{return r.read(cbuf, off, len);}}class MyBufferedReaderDemo{public static void main(String[] args)throws IOException{FileReader fr = new FileReader("test.java");MyBufferedReader mbufr = new MyBufferedReader(fr);FileWriter fw = new FileWriter("buf.txt");BufferedWriter bufw = new BufferedWriter(fw);String buf = null;while((buf = mbufr.myReadLine()) != null){fw.write(buf);bufw.newLine();bufw.flush();}mbufr.close();fw.close();}}



字节流:
字节流是直接针对字节进行操作的,所以字节流可以直接对非文本文件进行读写。

读写方法与字符流类似,只是自定义的缓冲区缓存byte数组就可以了。
以拷贝图片为例:
import java.io.*;class CopyPic{public static void picCopy(){FileInputStream fis = null;FileOutputStream fos = null;try{fos = new FileOutputStream("buf.jpg");fis = new FileInputStream("logo.jpg");byte[] buf = new byte[1024];int len = 0;while((len = fis.read(buf)) != -1){fos.write(buf, 0, len);}}catch(IOException e){System.out.println("pic copy failed");}finally{try{if(fos != null)fos.close();}catch(IOException e){System.out.println("output close failed");}try{if(fos != null)fos.close();}catch(IOException e){System.out.println("input close failed");}}}public static void main(String[] args){picCopy();}}



字节流也有对应的带有缓冲区的加强类:BufferedInputStream和BufferedOutputStream
调用read()方法时应注意,它会把读到的byte类型数据提升为int类型并返回,数据前自动补齐-1,这样在遇到连续8位是1的数据时,再补齐-1就会被当做结束标记,
自定义read()方法时,应注意在提升byte为int时,要在前面补0,也就是将数据和255做与运算。
自定义BufferedInputStream如下:
import java.io.*;class MyBufferedInputStream{private InputStream in;private byte[] buf = new byte[1024];//缓冲区private int pos = 0, count = 0;//定义指针,计数器MyBufferedInputStream(InputStream in){this.in = in;}//一次读一个字节,从缓冲区——字节数组中读public int myRead()throws IOException{if(count == 0)//数组是否取空{count = in.read(buf);//通过in对象读取硬盘上的数据 并存储到缓冲区buf中,if(count < 0){return -1;}pos = 0;byte b = buf[pos];//第一次从缓冲区中取一个字节count --;pos ++;return b & 0xff;//补0}else if(count > 0){byte b = buf[pos];//一次从缓冲区中取一个字节count --;pos ++;return b & 255;//补0}return -1;}public void close()throws IOException{in.close();}}/* byte型提升为int型后,8位数据提升为32位,前面系统自动补1,如果独到8个1,补位后 * 还是-1,就会中断读数据循环,所以要手动补0。就和255与运算。 *  */



字符流与字节流转换流:
最简单的应用例子就是,在获取键盘录入时,希望提高效率,避免输入一个读取一个,改为输入一行,然后整行读取到缓冲区,而readLine()方法又是字符流的方法,
这时就可以使用转换流,将InputStream对象传入InputStreamReader构造函数中,再通过BufferedReader对象来使用readLine()方法。

代码如下:
import java.io.*;class TransStreamDemo{public static void main(String[] args)throws IOException{//获取键盘录入对象//InputStream in = System.in;////将字节流转换成字符流,使用转换流//InputStreamReader isr = new InputStreamReader(in);//BufferedReader br = new BufferedReader(isr);BufferedReader br = new BufferedReader(new InputStreamReader(System.in));//OutputStream out = System.out;//OutputStreamWriter osw = new OutputStreamWriter(out);//BufferedWriter bw = new BufferedWriter(osw);BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));String buf = null;while((buf = br.readLine()) != null){if("over".equals(buf))break;bw.write(buf.toUpperCase());bw.newLine();bw.flush();}br.close();br.close();bw.close();}}




流操作规律:
下面总结一下流操作规律,以便明确数据操作时用哪个流对象。
通过明确以下几点就可以确定:
1、   源:输入流:InputStream Reader
         目的:输出流:OutputStream Writer
2、操作的是否为纯文本:
          是:字符流对象
          否:字节流对象
3、通过设备来确定具体对象:
          硬盘上文件:Filexxxx
          标准输入输出设备(键盘,控制台):System.xx 这里可以通过System.setxx()来设置默认设备。

再通过是否需要提高效率决定是否用Bufferedxxx。
示例:
需求:想要将一个文件的数据打印在控制台上。
源:文件
目的:控制台
代码如下:
import java.io.*;class TransStreamDemo{public static void main(String[] args)throws IOException{//获取键盘录入对象//InputStream in = System.in;////将字节流转换成字符流,使用转换流//InputStreamReader isr = new InputStreamReader(in);//BufferedReader br = new BufferedReader(isr);BufferedReader br = new BufferedReader(new InputStreamReader(System.in));//OutputStream out = System.out;//OutputStreamWriter osw = new OutputStreamWriter(out);//BufferedWriter bw = new BufferedWriter(osw);BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));String buf = null;while((buf = br.readLine()) != null){if("over".equals(buf))break;bw.write(buf.toUpperCase());bw.newLine();bw.flush();}br.close();br.close();bw.close();}}

2 0