黑马程序员————IO流------(2)

来源:互联网 发布:钢铁侠分析软件 编辑:程序博客网 时间:2024/06/10 02:08

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------


BufferedWriter:

缓冲区的出现是为了提高流的操作效率而出现的。所以在创建缓冲区之前,必须要先有流对象。该缓冲区中提供了一个跨平台的换行符newLine();

练习:

package IO;import java.io.*;public class BufferedWriterDemo {public static void main(String[] args)throws Exception {//实例化一个字符写入流Writer w=new FileWriter("e:/a.txt");//给字符写入流包装一下,提高效率BufferedWriter bw=new BufferedWriter(w);bw.write("abc");bw.newLine();//换行符bw.write("efg");bw.flush();bw.close();//关闭资源}}
BufferedReader:
字符读取流缓冲区:该缓冲区可以进行读一行操作,方便对文件的读取。当返回Null时,就读到末尾了。

练习:

package IO;import java.io.BufferedReader;import java.io.FileReader;import java.io.Reader;public class BufferedReaderDemo {public static void main(String[] args)throws Exception {//创建一个读取流对象和文件关联Reader r=new FileReader("e:/a.txt");//加入缓冲技术,提高效率,与读取流对象关联起来BufferedReader bw=new BufferedReader(r);String line=null;while((line=bw.readLine())!=null){System.out.println(line);}
<span style="white-space:pre"></span>bw.colse();
}}


练习:

要求:通过缓冲区复制文本文件

package IO;/* * 思路: * 1.先有读取流和需要被复制的文件关联,然后加入缓冲区 * 2.有一个写入流和目的文件相关联,然后加入缓冲区 * 3.一边读取一行,一边写进一行,这样就能完成复制 */import java.io.*;public class CopyFile {public static void main(String[] args)throws Exception {//读取流BufferedReader br=new BufferedReader(new FileReader("e:/CopyFile.java"));//写入流BufferedWriter bw=new BufferedWriter(new FileWriter("e:/copy.txt"));//一边读,一边写String line=null;while((line=br.readLine())!=null){bw.write(line);bw.newLine();bw.flush();}bw.close();br.close();}}

readLine的原理

将读到的\r\n时,就将数组中的已有数据打印出来。然后继续读下一行的元素。

模拟readLine功能写一个自己的MyBufferedReader

代码:

package IO;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.FileNotFoundException;import java.io.FileReader;import java.io.FileWriter;import java.io.PrintWriter;import java.io.Reader;/* * 思路: * 1.readLine的原理就是读到\r\n时,才把所读到的所有存进缓冲区。 * 2.知道原理后,自己可以写一个BufferedReader */public class MyBufferedReader {private FileReader r;public MyBufferedReader(FileReader r){this.r=r;}//为了方便,这里定义StringBuilder容器,因为最终还是要将数组转换成字符串public String myReadLine()throws Exception{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);//这点很重要,记得要强制转换成char,不然复制出来全是数字。}if(sb.length()!=0){//如果最后一行没有换行符,它就导致最后一行存进缓冲区,没被返回。所有自己判断一下return sb.toString();}return null;}public void myClose()throws Exception{r.close();}public static void main(String[] args){MyBufferedReader mbr=null;BufferedWriter bw=null;try { mbr=new MyBufferedReader(new FileReader("e:/copy.txt")); bw=new BufferedWriter(new FileWriter("e:/copy_1.txt")); String line=null; while((line=mbr.myReadLine())!=null){//运用自己的读一行的方法bw.write(line);bw.newLine();bw.flush();}} catch (Exception e) {e.printStackTrace();}finally{try{if(mbr!=null){mbr.myClose();}}catch(Exception e){e.printStackTrace();}try{if(bw!=null){bw.close();}}catch(Exception e){e.printStackTrace();}}}}

注意:最后一行可能没有换行符,那么数据也只是存到缓冲区,并没有被返回,所有最好进行自己的判断,返回。

if(sb.length()!=null){

retren sb.toString();

}


装饰者设计模式

将被增强的对象,传给增强的对象,基于原本的读一个的功能,扩展为读一行的功能。

装饰类通常通过构造方法接收被装饰的对象,并基于被装饰的对象的功能,提供更强大的功能。

实例:

package IO;public class Decorator {Student s;public Decorator(Student s){this.s=s;}public void sleep(){System.out.println("看书");System.out.println("听歌");s.sleep();}}class Student{public void sleep(){System.out.println("睡觉");}}

装饰和继承的区别

如读这个体系,有读文本,读照片,读电影等,不可能每个类都继承Buffer,那么这样会造成这个体系太臃肿,且扩展性不强,这时可以直接定义一个装饰类(Buffer),把读文件等类作为参数传入,这样就具备了Buffer的增强功能。


装饰者模式就是为已有功能加强的,还是原来的体系中的类。


装饰者比继承要灵活,降低了类与类直接的关系。

自定义装饰类

package IO;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.FileNotFoundException;import java.io.FileReader;import java.io.FileWriter;import java.io.IOException;import java.io.PrintWriter;import java.io.Reader;/* * 这就是一个装饰类,还是属于Reader体系中 * 它继承了Reader,复写了Reader中的方法,也加强了read方法,使原来读一个变为读一行 */public class MyBufferedReader extends Reader {private FileReader r;public MyBufferedReader(FileReader r){this.r=r;}//为了方便,这里定义StringBuilder容器,因为最终还是要将数组转换成字符串public String myReadLine()throws Exception{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);//这点很重要,记得要强制转换成char,不然复制出来全是数字。}if(sb.length()!=0){//如果最后一行没有换行符,它就导致最后一行存进缓冲区,没被返回。所有自己判断一下return sb.toString();}return null;}@Overridepublic int read(char[] cbuf, int off, int len) throws IOException {return r.read(cbuf, off, len);}@Overridepublic void close() throws IOException {r.close();}}


拷贝图片

不要用字符流来拷贝媒体文件,字符流是用来处理文字数据的。

package IO;import java.io.*;public class CopyPic {public static void main(String[] args)throws Exception {FileInputStream fis=new FileInputStream("e:/2.png");FileOutputStream fos=new  FileOutputStream("e:/copy_pic.png");int len=0;while((len=fis.read())!=-1){fos.write(len);}fis.close();fos.close();}}


自定义字节流的缓冲区--read和write的特点

先从硬盘上抓上一把数据,再存到数组缓冲区去,然后通过指针,一个一个读出来。取完之后,再取硬盘中抓一把数据,再存到数组中去。再通过指针取。

package IO;/* * 定义数组:当做缓冲区,存放从硬盘中读取来的数据 * 定义指针:从数组中一个一个的读取出来 * 定义计数器:当数组中的数据读完,计数器显示为0 ,这时继续从硬盘中读取 */import java.io.*;public class MyBufferedInputStream {private InputStream ins;byte[] buf = new byte[1024];private int pos = 0;// 定义指针private int count = 0;// 用来判断缓冲区数据是否读完private MyBufferedInputStream(InputStream ins) {this.ins = ins;}// 一次读一个自己 从字符缓冲区(数组)中获取public int myRead() throws Exception {if (count == 0) {// 当数组中的数据读完时pos = 0;count = ins.read(buf);if (count == -1)return -1;byte b = buf[pos];count--;pos++; // 从数组读数据,自动从Byte提升intreturn b & 255;// 防止出现-1的情况,导致文件复制不成功}else if(count>0){byte b=buf[pos];count--;pos++;return b & 0xff;}       return -1;  }public void myClose()throws Exception{ins.close();}public static void main(String[] args)throws Exception{MyBufferedInputStream fis=new MyBufferedInputStream(new FileInputStream("e:/copy.txt"));FileOutputStream fos=new FileOutputStream("e:/copy_c.txt");int b=0;while((b=fis.myRead())!=-1){    fos.write(b);}fos.flush();fos.close();fis.myClose();}}


读取键盘的录入

System.in对应键盘的输出设备,控制台

System.out:对应标准输入设备:键盘

注意:Read是阻塞式方法。

需求:

通过录入一行数据,然后打印出来。直到录入为over,那就停止录入。

package IO;import java.io.*;public class SystemDemo {public static void main(String[] args) throws Exception {InputStream ins = System.in;StringBuffer sb = new StringBuffer();// 把数据先存入里面int b = 0;while (true) {b = ins.read();if (b == '\r')continue;if (b == '\n') {if ("over".equals(sb.toString())) {break;}System.out.println(sb.toString());sb.delete(0, sb.length());} else {sb.append((char) b);}}}}

运行结果:



读取转换流

操作字节流的字符流InputStreamReader.

怎么来的呢?实际是因为字节流没有读一行的方法,而字符流有这方法,我想要使用,那么我就必须变为字符流才可以。

package IO;import java.io.*;/* * 因为BufferedReader有读一行的方法,那么把字节流转换为字符流, * 再提高效率后,就能使用这个方法readLine(); */public class TransStreamDemo {public static void main(String[] args) throws Exception {//键盘录入对象InputStream ins=System.in;//字节流转换为字符流InputStreamReader irs=new InputStreamReader(ins);//提高效率BufferedReader br=new BufferedReader(irs);String line=null;while((line=br.readLine())!=null){if("over".equals(line)){break;}elseSystem.out.println(line);}}}


写入转换流

字符流通向字节的桥梁:OutputStreamWriter.

 文件以字节的形式存在,录入的是字符,存在硬盘的是字节。字符输出流内部是缓冲区,要flush 


package IO;import java.io.*;/* * 因为BufferedReader有读一行的方法,那么把字节流转换为字符流, * 再提高效率后,就能使用这个方法readLine(); */public class TransStreamDemo {public static void main(String[] args) throws Exception {//键盘录入对象InputStream ins=System.in;//字节流转换为字符流InputStreamReader irs=new InputStreamReader(ins);//提高效率BufferedReader br=new BufferedReader(irs);//写入转换流BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(System.out));String line=null;while((line=br.readLine())!=null){if("over".equals(line)){break;}elsebw.write(line);bw.newLine();bw.flush();}}}


流操作规律

通过三个明确来完成。

   1.明确源和目的

源:输入流。InputStream  Reader

目的:输出流。OutputStrema Writer

    2.操作的数据是否是纯文本

是:字符流

不是:字节流

    3.当体系明确后,在明确要使用哪个具体的对象。

通过设备来区分

源设备:内存,硬盘,键盘

目的设备:内存,硬盘,控制台。


当涉及到字符编码转换时,需要用到转换流。


改变标准流输入输出设备

System.setIn(new FileInputStream());

System.setOut(new FileOutputStream());



0 0
原创粉丝点击