黑马程序员16.IO流

来源:互联网 发布:淘宝大码女装裤子店铺 编辑:程序博客网 时间:2024/06/03 05:08

-------android培训java培训java学习型技术博客、期待与您交流! ---------- 

今天学习了毕老师java基础第19天的内容,在这里总结一下。

IO流

BufferedWriter


/*缓冲区的出现是为了提高流的操作效率而出现的。所以在创建缓冲区之前,必须要先有流对象。该缓冲区中提供了一个跨平台的换行符。newLine();*/import java.io.*;class  BufferedWriterDemo{public static void main(String[] args) throws IOException{//创建一个字符写入流对象。FileWriter fw = new FileWriter("buf.txt");//为了提高字符写入流效率。加入了缓冲技术。//只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可。BufferedWriter bufw = new BufferedWriter(fw);for(int x=1; x<5; x++){bufw.write("abcd"+x);bufw.newLine();bufw.flush();}//记住,只要用到缓冲区,就要记得刷新。//bufw.flush();//其实关闭缓冲区,就是在关闭缓冲区中的流对象。bufw.close();}}


BufferedReader

/*字符读取流缓冲区:该缓冲区提供了一个一次读一行的方法 readLine,方便于对文本数据的获取。当返回null时,表示读到文件末尾。readLine方法返回的时候只返回回车符之前的数据内容。并不返回回车符。*/import java.io.*;class  BufferedReaderDemo{public static void main(String[] args) throws IOException{//创建一个读取流对象和文件相关联。FileReader fr = new FileReader("buf.txt");//为了提高效率。加入缓冲技术。将字符读取流对象作为参数传递给缓冲对象的构造函数。BufferedReader bufr = new BufferedReader(fr);String line = null;while((line=bufr.readLine())!=null){System.out.print(line);}bufr.close();}}

缓冲区练习

/*通过缓冲区复制一个.java文件。*/import java.io.*;class  CopyTextByBuf{public static void main(String[] args) {BufferedReader bufr = null;BufferedWriter bufw = null;try{bufr = new BufferedReader(new FileReader("BufferedWriterDemo.java"));bufw = new BufferedWriter(new FileWriter("bufWriter_Copy.txt"));String line = null;while((line=bufr.readLine())!=null){bufw.write(line);bufw.newLine();bufw.flush();}}catch (IOException e){throw new RuntimeException("读写失败");}finally{try{if(bufr!=null)bufr.close();}catch (IOException e){throw new RuntimeException("读取关闭失败");}try{if(bufw!=null)bufw.close();}catch (IOException e){throw new RuntimeException("写入关闭失败");}}}}

ReadLine()原理

 

 代码:

import java.io.*;class MyBufferedReader {private FileReader r;MyBufferedReader(FileReader r){this.r = r;}//可以一次读一行数据的方法。public String myReadLine() throws IOException{//定义一个临时容器。原BufferReader封装的是字符数组。//为了演示方便。定义一个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 myClose() throws IOException{r.close(); }}class MyBufferedReaderDemo{public static void main(String[] args) throws IOException{FileReader fr = new FileReader("buf.txt");MyBufferedReader myBuf = new MyBufferedReader(fr);String line = null;while (line= muBuf.myReadLine()!=null){System.out.println(line);}myBuf.myClose();}}

装饰设计模式

/*装饰设计模式:当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。那么自定义的该类称为装饰类。装饰类通常会通过构造方法接收被装饰的对象。并基于被装饰的对象的功能,提供更强的功能。*/class Person{public void chifan(){System.out.println("吃饭");}}class SuperPerson //通常Person和SuperPerson会属于同一个体系{private Person p ;SuperPerson(Person p)//为了增强别人而存在,所以得现有别人,它才能存在{this.p = p;}public void superChifan(){System.out.println("开胃酒");p.chifan();System.out.println("甜点");System.out.println("来一根");}}class  PersonDemo{public static void main(String[] args) {Person p = new Person();//p.chifan();SuperPerson sp = new SuperPerson(p);sp.superChifan();} }
/*MyReader//专门用于读取数据的类。|--MyTextReader|--MyBufferTextReader|--MyMediaReader|--MyBufferMediaReader|--MyDataReader|--MyBufferDataReaderclass MyBufferReader{MyBufferReader(MyTextReader text){}MyBufferReader(MyMediaReader media){}}上面这个类扩展性很差。找到其参数的共同类型。通过多态的形式。可以提高扩展性。class MyBufferReader extends MyReader{private MyReader r;MyBufferReader(MyReader r){}}MyReader//专门用于读取数据的类。|--MyTextReader|--MyMediaReader|--MyDataReader|--MyBufferReader以前是通过继承将每一个子类都具备缓冲功能。那么继承体系会复杂,并不利于扩展。现在优化思想。单独描述一下缓冲内容。将需要被缓冲的对象。传递进来。也就是,谁需要被缓冲,谁就作为参数传递给缓冲区。这样继承体系就变得很简单。优化了体系结构。装饰模式比继承要灵活。避免了继承体系臃肿。而且降低了类于类之间的关系。装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强功能。所以装饰类和被装饰类通常是都属于一个体系中的。*/

 LineNumberReader

import java.io.*;class LineNumberReaderDemo {public static void main(String[] args)throws IOException {FileReader fr = new FileReader("PersonDemo.java");LineNumberReader lnr = new LineNumberReader(fr);String line = null;lnr.setLineNumber(100);while((line=lnr.readLine())!=null){System.out.println(lnr.getLineNumber()+":"+line);}lnr.close();}}

自定义lineNumberReader:
import java.io.*;class MyLineNumberReader{private Reader r;private int lineNumber;MyLineNumberReader(Reader r){this.r = r;}public String myReadLine() thorws IOException{lineNumber++;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 setLineNumber(int lineNumber){this.lineNumber = lineNumber;}public int getLineNumber(){return lineNumber;}public void myClose() throws IOException{r.close();}}class MyLineNumberReaderDemo{public static void main(String[] args) throws IOException{FileReader fr = new FileReader("copyTextByBuf.java");MyLineNumberReader mylnr = new MyLineNumberReader(fr);String line = null;while ((line=mylnr.myReadLine())!=null){sop(mylnr.getLineNumber()+line);}mylnr.myClose();}}
简化版:(因为父类有了)
import java.io.*;class MyLineNumberReader extends MyBufferedReader{private int lineNumber;MyLineNumberReader(Reader r){super(r);}public String myReadLine()throws IOException{lineNumber++;return super.myReadLine();}public void setLineNumber(int lineNumber){this.lineNumber = lineNumber;}public int getLineNumber(){return lineNumber;}}


字节流File读写操作

/*字符流:FileReaderFileWriter。BufferedReaderBufferedWriter字节流:InputStream  OutputStream需求,想要操作图片数据。这时就要用到字节流。复制一个图片.*/import java.io.*;class  FileStream{public static void main(String[] args) throws IOException{readFile_3();}public static void readFile_3()throws IOException{FileInputStream fis = new FileInputStream("fos.txt");//int num = fis.available();byte[] buf = new byte[fis.available()];//定义一个刚刚好的缓冲区。不用在循环了。fis.read(buf);System.out.println(new String(buf));fis.close();}public static void readFile_2()throws IOException{FileInputStream fis = new FileInputStream("fos.txt");byte[] buf = new byte[1024];int len = 0;while((len=fis.read(buf))!=-1){System.out.println(new String(buf,0,len));}fis.close();}public static void readFile_1()throws IOException{FileInputStream fis = new FileInputStream("fos.txt");int ch = 0;while((ch=fis.read())!=-1){System.out.println((char)ch);}fis.close();}public static void writeFile()throws IOException{FileOutputStream fos = new FileOutputStream("fos.txt");fos.write("abcde".getBytes());fos.close();}}

拷贝图片:
 
/*复制一个图片思路:1,用字节读取流对象和图片关联。2,用字节写入流对象创建一个图片文件。用于存储获取到的图片数据。3,通过循环读写,完成数据的存储。4,关闭资源。 */import java.io.*;class  CopyPic{public static void main(String[] args) {FileOutputStream fos = null;FileInputStream fis = null;try{fos = new FileOutputStream("c:\\2.bmp");fis = new FileInputStream("c:\\1.bmp");byte[] buf = new byte[1024];int len = 0;while((len=fis.read(buf))!=-1){fos.write(buf,0,len);}}catch (IOException e){throw new RuntimeException("复制文件失败");}finally{try{if(fis!=null)fis.close();}catch (IOException e){throw new RuntimeException("读取关闭失败");}try{if(fos!=null)fos.close();}catch (IOException e){throw new RuntimeException("写入关闭失败");}}}}
字节流的缓冲区:
/*演示mp3的复制。通过缓冲区。BufferedOutputStreamBufferedInputStream*/import java.io.*;class  CopyMp3{public static void main(String[] args) throws IOException{long start = System.currentTimeMillis();copy_2();long end = System.currentTimeMillis();System.out.println((end-start)+"毫秒");}public static void copy_2()throws IOException{MyBufferedInputStream bufis = new MyBufferedInputStream(new FileInputStream("c:\\9.mp3"));BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("c:\\3.mp3"));int by = 0;//System.out.println("第一个字节:"+bufis.myRead());while((by=bufis.myRead())!=-1){bufos.write(by);}bufos.close();bufis.myClose();}//通过字节流的缓冲区完成复制。public static void copy_1()throws IOException{BufferedInputStream bufis = new BufferedInputStream(new FileInputStream("c:\\0.mp3"));BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("c:\\1.mp3"));int by = 0;while((by=bufis.read())!=-1){bufos.write(by);}bufos.close();bufis.close();}}
import java.io.*;class MyBufferedInputStream{private InputStream in;private byte[] buf = new byte[1024*4];private int pos = 0,count = 0;MyBufferedInputStream(InputStream in){this.in = in;}//一次读一个字节,从缓冲区(字节数组)获取。public int myRead()throws IOException{//通过in对象读取硬盘上数据,并存储buf中。if(count==0){count = in.read(buf);if(count<0)return -1; pos = 0;byte b = buf[pos];count--;pos++;return b&255;}else if(count>0){byte b = buf[pos];count--;pos++;return b&0xff;}return -1;}public void myClose()throws IOException{in.close();}}/*11111111-111111110000000000101001001010100101010010101001010byte: -1  --->  int : -1;00000000 00000000 00000000 11111111  25511111111 11111111 11111111 1111111111111111  -->提升了一个int类型 那不还是-1吗?是-1的原因是因为在8个1前面补的是1导致的。那么我只要在前面补0,即可以保留原字节数据不变,又可以避免-1的出现。怎么补0呢? 11111111 11111111 11111111 11111111                        &00000000 00000000 00000000 11111111 ------------------------------------ 00000000 00000000 00000000 11111111 0000-00011111-11100000000011111-1111  -1结论:字节流的读一个字节的read方法为什么返回值类型不是byte,而是int。因为有可能会读到连续8个二进制1的情况,8个二进制1对应的十进制是-1.那么就会数据还没有读完,就结束的情况。因为我们判断读取结束是通过结尾标记-1来确定的。所以,为了避免这种情况将读到的字节进行int类型的提升。并在保留原字节数据的情况前面了补了24个0,变成了int类型的数值。而在写入数据时,只写该int类型数据的最低8位。*/


读取键盘录入

import java.io.*;class  ReadIn{public static void main(String[] args) throws IOException{InputStream in = System.in;StringBuilder sb = new StringBuilder();while (true){int ch = in.read();if (ch=='\r'){continue;}if (ch=='\n'){String s = sb.toString();if ("over".equals(s)){break;}System.out.println(s.toUpperCase());sb.delete(0,sb.length());}elsesb.append((char)ch);}  }}

读取转换流

字符流:
FileReader
FileWriter。

BufferedReader
BufferedWriter

字节流:
FileInputStream
FileOutputStream

BufferedInputStream
BufferedOutputStream

通过刚才的键盘录入一行数据并打印其大写,发现其实就是读一行数据的原理。
也就是readLine方法。
能不能直接使用readLine方法来完成键盘录入的一行数据的读取呢?
readLine方法是字符流BufferedReader类中的方法。
而键盘录入的read方法是字节流InputStream的方法。
那么能不能将字节流转成字符流再使用字符流缓冲区的readLine方法呢?
import java.io.*;class TransStreamDemo {public static void main(String[] args) throws IOException{//获取键盘录入对象。InputStream in = System.in;//将字节流对象转成字符流对象,使用转换流。InputStreamReaderInputStreamReader isr = new InputStreamReader(in);//为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReaderBufferedReader bufr = new BufferedReader(isr);String line = null;while ((line = bufr.readLine())!=null){if ("over".equals(line)){break;}System.out.println(line.toUpperCase());}bufr.close();}} 

写入转换流

import java.io.*;class TransStreamDemo {public static void main(String[] args) throws IOException{////获取键盘录入对象。//InputStream in = System.in;////将字节流对象转成字符流对象,使用转换流。InputStreamReader//InputStreamReader isr = new InputStreamReader(in);////为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReader//BufferedReader bufr = new BufferedReader(isr);BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));//OutputStream out = System.out;//OutputStreamWriter osw = new OutputStreamWriter(out);BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));String line = null;while ((line = bufr.readLine())!=null){if ("over".equals(line)){break;}bufw.write(line.toUpperCase()+"\r\n");bufw.newLine();bufw.flush();}    bufr.close();}} 

流操作规律

现在需求变了:
2,需求:想把键盘录入的数据存储到一个文件中。
源:键盘。
目的:文件。
import java.io.*;class TransStreamDemo {public static void main(String[] args) throws IOException{////获取键盘录入对象。//InputStream in = System.in;////将字节流对象转成字符流对象,使用转换流。InputStreamReader//InputStreamReader isr = new InputStreamReader(in);////为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReader//BufferedReader bufr = new BufferedReader(isr);BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));//OutputStream out = System.out;//OutputStreamWriter osw = new OutputStreamWriter(out);BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("out.txt")));String line = null;while ((line = bufr.readLine())!=null){if ("over".equals(line)){break;}bufw.write(line.toUpperCase()+"\r\n");bufw.newLine();bufw.flush();}    bufr.close();}} 
3,需求:想要将一个文件的数据打印在控制台上。
源:文件。
目的:控制台。
import java.io.*;class TransStreamDemo2 {public static void main(String[] args) throws IOException{BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileInputStream("FileStream.java")));BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));String line = null;while ((line = bufr.readLine())!=null){if ("over".equals(line)){break;}bufw.write(line.toUpperCase()+"\r\n");bufw.newLine();bufw.flush();}    bufr.close();}} 
流操作的基本规律:
最痛苦的就是流对象有很多,不知道该用哪一个。

通过三个明确来完成。

1,明确源和目的。
源:输入流。InputStream  Reader
目的:输出流。OutputStream  Writer。
2,操作的数据是否是纯文本。
是:字符流。
不是:字节流。

3,当体系明确后,在明确要使用哪个具体的对象。
通过设备来进行区分:
源设备:内存,硬盘。键盘
目的设备:内存,硬盘,控制台。

1,将一个文本文件中数据存储到另一个文件中。复制文件。
源:因为是源,所以使用读取流。InputStream Reader 
是不是操作文本文件。
是!这时就可以选择Reader
这样体系就明确了。

接下来明确要使用该体系中的哪个对象。
明确设备:硬盘。上一个文件。
Reader体系中可以操作文件的对象是 FileReader

是否需要提高效率:是!。加入Reader体系中缓冲区 BufferedReader.

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

目的:OutputStream Writer
是否是纯文本。
是!Writer。
设备:硬盘,一个文件。
Writer体系中可以操作文件的对象FileWriter。
是否需要提高效率:是!。加入Writer体系中缓冲区 BufferedWriter

FileWriter fw = new FileWriter("b.txt");
BufferedWriter bufw = new BufferedWriter(fw);

练习:将一个图片文件中数据存储到另一个文件中。复制文件。要按照以上格式自己完成三个明确。

---------------------------------------
2,需求:将键盘录入的数据保存到一个文件中。
这个需求中有源和目的都存在。
那么分别分析
源:InputStream Reader
是不是纯文本?是!Reader

设备:键盘。对应的对象是System.in.
不是选择Reader吗?System.in对应的不是字节流吗?
为了操作键盘的文本数据方便。转成字符流按照字符串操作是最方便的。
所以既然明确了Reader,那么就将System.in转换成Reader。
用了Reader体系中转换流,InputStreamReader

InputStreamReader isr = new InputStreamReader(System.in);

需要提高效率吗?需要!BufferedReader
BufferedReader bufr = new BufferedReader(isr);

目的:OutputStream  Writer
是否是存文本?是!Writer。
设备:硬盘。一个文件。使用 FileWriter。
FileWriter fw = new FileWriter("c.txt");
需要提高效率吗?需要。
BufferedWriter bufw = new BufferedWriter(fw);

**************
扩展一下,想要把录入的数据按照指定的编码表(utf-8),将数据存到文件中。

目的:OutputStream  Writer
是否是纯文本?是!Writer。
设备:硬盘。一个文件。使用 FileWriter。
但是FileWriter是使用的默认编码表。GBK.

但是存储时,需要加入指定编码表utf-8。而指定的编码表只有转换流可以指定。
所以要使用的对象是OutputStreamWriter。
而该转换流对象要接收一个字节输出流。而且还可以操作文件的字节输出流。FileOutputStream

OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d.txt"),"UTF-8"); 

需要高效吗?需要。
BufferedWriter bufw = new BufferedWriter(osw);

所以,记住。转换流什么使用。字符和字节之间的桥梁,通常,涉及到字符编码转换时,
需要用到转换流。

练习:将一个文本数据打印在控制台上。要按照以上格式自己完成三个明确。



异常的日志信息

import java.io.*;import java.util.*;import java.text.*;class  ExceptionInfo{public static void main(String[] args)throws IOException {try{int[] arr = new int[2];System.out.println(arr[3]);}catch (Exception e){try{Date d = new Date();SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");String s = sdf.format(d);PrintStream ps = new PrintStream("exeception.log");ps.println(s);System.setOut(ps);}catch (IOException ex){throw new RuntimeException("日志文件创建失败");}e.printStackTrace(System.out);}}}//log4j 生成异常日志的软件包,网上有下

-------android培训java培训java学习型技术博客、期待与您交流! ---------- 



0 0
原创粉丝点击