黑马程序员 IO流 缓冲区、装饰模式
1 .IO流,创建一个对象,该对象一被初始化就必须明确要操作的文件。文件被传见到指定目录下,如果有同名文件就会被覆盖。fw.flush()刷新流对象中的缓冲数据,将数据刷到目的地,flush刷新后流可以继续使用,close刷新后流会关闭。
2.字符流的缓冲区
缓冲区的出现是,为了提高流的操作效率而出现的。所以在创建缓冲区前,必须先有流对象。字符读取流缓冲区提供了一个一次毒一行的方法readline,方便于文本数据的获取,当返回null时,表示读到文本末尾,readline方法返回的时候只返回回车符之前的数据,并不返回回车符。
字符流的缓冲区
对应类:
BufferedWriter
BufferedReader
缓冲区的出现是为了提高流的操作效率,所以在创建缓冲区之前必须要先有流对象。将需要被提高效率的流对象作为参数传递给缓冲区的构造函数。
关闭缓冲区,就是在关才缓冲区中的流对象。
newline():换行
FileWriter fw = FileWriter(“D:\\aa.txt”);
BufferedWriter bw = BufferedWriter(fw);
bw.write(“adfdsafdsa”);
bw.newline();
bw.write(“fdsafsda”);
bw.close();
BufferedReader
readLine():读一行
FileReader fr = new FileReader(“d:\\txt.txt”);
BufferedReader br = new BufferedReader(fr);
String str=null;
while((str=br.readLine())!=null){
out.print(str);
}
br.close();
缓冲区的复制文件
BufferedWriter bw = null;
BufferedReader br = null;
try{
bw = newBufferedWriter(new FileWriter(“D:\\aaa_copy.txt”));
br = newBufferedReader(new FileReader(“D:\\aaa.txt”));
String line = null;
while((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
}
装饰设计模式:
当要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有对象的功能,并提供加强功能。那么自定义的该类就称为装饰类。
装饰类通常会通过构造方法接收被装饰的对象,并基于被装饰的对象的功能,提供更强的功能。
装饰和继承的区别:
例:
MyReader
|--MyTextReader
|--MyTextReader
变为:
MyReader
|--MyTextReader
|--MyTextReader
|--MyBuffereReader
装饰模式比继承要灵活,避免了继承体系臃肿,而且降低了类与类之间的关系。装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强的功能。所有装饰类和被装饰类通常是都属于一个体系中的。
import java.io.*;
class MyLineNumberReader{
private FileReader fr;
private int LineNumber=11;
MyLineNumberReader(FileReader fr ){
this.fr = fr;
}
public String myReadLine()throws Exception{
StringBuffer sb = new StringBuffer();
int ch;
while((ch=fr.read())!=-1){
if(ch=='\r'){
continue;
}
if(ch=='\n'){
LineNumber++;
return sb.toString();
}
else{
sb.append((char)ch);
}
}
if(sb.length()!=0){
System.out.println("+++++++++++++++++++++++++");
return sb.toString();
}
return null;
}
public void setLineNumber(int LineNumber){
this.LineNumber=LineNumber;
}
public int getLineNumber(){
return LineNumber;
}
public void close()throws Exception{
fr.close();
}
}
class MyLineNumberDemo{
public static void main(String[] args)throws Exception{
FileReader fr = new FileReader("D:\\tmp\\aa_copy.txt");
MyLineNumberReader lnr = new MyLineNumberReader(fr);
lnr.setLineNumber(11);
String str;
while((str=lnr.myReadLine())!=null){
System.out.println(lnr.getLineNumber()+":"+str);
}
lnr.close();
}
}
LineNumberReader带行号的装饰类
getLineNumber();
setLineNumber();
自定义LineNumberReader类
FileReader fr = new FileReader("D:\\tmp\\aa_copy.txt");
LineNumberReader lnr = new LineNumberReader(fr);
lnr.setLineNumber(0);
String str;
while((str=lnr.readLine())!=null){
System.out.println(lnr.getLineNumber()+":"+str);
}
lnr.close();
字节流:
InputStream
OutputStream
FileInputStream
FileOutputStream
write(“abcd”.getBytes());//以单个字符存入
不需要用flush()方法刷新
FileInputStream fis = new FileInputStream(“aa.txt”);
byte[] buf = new byte[fis.available()];
fis.read(buf);
System.out.println(new String(buf));
fis.close();
不建议使用此方式,因为考虑到文件比较大时,会发生内存溢出。
所以一般使用下面方式
FileInputStream fis = new FileInputStream(“aa.txt”);
byte[] buf = new byte[1024];
int num=0;
while((num=fis.read(buf))!=-1){
System.out.println(newString(buf,0,num));
}
复制一张图片
用字节读取流对象和图片关联。
用字节写入流对象创建一个图片文件。用于存储获取到的图片数据。
通过循环读写,完成数据的存储。
关才资源。
字节流的缓冲区
BufferedOutputStream
BufferedInputStream
BufferedInputStream bufis = new BufferedInputStream(newFileInputStream(“c:\\1.mp3”));
BufferedOntputStream bufos = new BufferedOntputStream(new FileOntputStream(“c:\\1_copy.mp3”));
int by=0;
while((by=bufis.read())!=-1){
bufos.write(by);
}
自定义字节流缓冲区
import java.io.*;
classMyBufferedInputStream{
privateInputStream in;
privatebyte[] buf = new byte[1024];
private intpos=0,count=0;
MyBufferedInputStream(InputStreamin){
this.in=in;
}
//一次读一个字节,从缓冲区(字节数组)获取。
publicint myRead(){
//通过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;
}elseif(count>0){
byte b = buf[pos];
count--;
pos++;
return b&255;
}
return-1;
}
publicvoid myClose(){
in.close();
}
}
读取键盘录入
System.out:对应的是标准输出设备,控制台
System.in:对应的是键盘
InputStreamin = System.in;
int by =in.read();
System.out.println(by);
InputStreamin = System.in;
int ch=0;
while((ch=in.read())!=-1){
System.out.println(by);
}
InputStreamin = System.in;
StringBuildersb = new StringBuilder();
while(true){
int ch=in.read();
if(ch==’\r’)
contine;
if(ch==’\n’){
String s = sb.String();
if(“over”.equals(s))
break;
System.out.println(s.toUpperCase());
sb.delete(0,sb.length());
}else{
sb.appen((char)ch);
}
}
通过刚才的键盘录入一行数据并打印其大写,发现其实就是读一行数据的原理,也就是readLine方法。
能不能直接使用readLine方法来完成键盘录入的一行数据的读取呢?
readLine方法是BufferedReader类中的方法。
而键盘录入的read方法是字节流InputStream的方法。
那么将字节流转换成字符流再使用字符流缓冲区的readLine的方法。
InputStreamReader:将字节流转换成字符流,在构造方法中传入字节流。
OutputStreamWriter
code:
//获取键盘录入对象。
//InputStream in = System.in;
//将字节流对象转成字符流对象,使用转换流:InputStreamReader;
//InputStreamReader isr = newInputStreamReader(in);
//为了提高效率,将字符串进行缓冲区的高效操作,使用装饰类:BufferedReader;
//BufferedReader byfr = newBufferedReader(isr);
BufferedReader byfr = newBufferedReader(new InputStreamReader(System.in));
//OutputStream out = System.out;
//OutputStreamWriter osw = newOutputStreamWriter(out);
//BufferedWriter bufw = newBufferedWriter(osw);
BufferedWriter bufw = newBufferedWriter(new OutputStreamWriter(System.out));
String line=null;
while((line=bufr.read())!=null){
if(“over”.equals(line))
break;
osw.write (line.toUpperCase());
bufw.newLine();
osw.flush();
}
byfr.close();
1. 将键盘输入的数据写入到一个文件中,只需改上述代码中的目的由控制台改为文件。
BufferedWriter bufw= new BufferedWriter(new OutputStreamWriter(new FileOutputStream(“out.txt”)));
2. 将一个文件的数据打印在控制台上。
BufferedReader bufr= new BufferedReader(new InputStreamReader(new FileInputStream(“copyPic.java”)));
流操作的基本规律:
流对象有很多,不知识该用哪一个。
通过两个明确来完成。
明确源和目的。
源:输入流:InputStream Reader
目的:输出流:OutputStream Writer
操作的数据是否是纯文本。
是:字符流:Reader Writer
不是:字节流:InputStream OutputStream
当体系明确后,在明确要使用哪个具体的对象。通过设备来进行区分:
源设备:内存,硬盘,键盘
目的设备:内存,硬盘,控制台
需求:
将一个文本文件中的数据存储到另一个文件中,复制文件。
源:InputStreamReader //因为是源,所以使用读取流,判断是不是操作文本文件,是!则选择Reader。这样体系就明确了。
接下来明确要使用该体系中的哪个对象。明确设备:硬盘上的一个文件。
Reader体系中可以操作文件的对象是:FileReader
是否需要提高效率,是!则加入Reader体系中的缓冲区:BufferedReader;
目的:OutputStreamWriter //目的是否是纯文本,是!则Writer。设备:硬盘上的一个文件。Writer体系中可以操作文件的对象是:FileWriter
是否需要提高效率,是!则加入Writer体系中的缓冲区:BufferedWriter;
将键盘录入的数据保存到一个文件中。
源:InputStream Reader //判断是不是纯文件?是!则用Reader。
设备:键盘,对应的对象是System.in ??? 不是选择Reader吗?System.in对应的不是字节流吗?为了操作键盘 的文本数据方便。转成字符流按照字符串操作是最方便的。所以既然明确了Reader,那么就将System.in转换成Reader。
用到了Reader体系中的转换流,InputStreamReader
code:
InputStreamReader isr = new InputStreamReader(System.in);
//需要提高效率吗?需要!BufferedReader
BufferedReader bufr = new BufferedReader(isr);
目的:OutputStream Writer //是否是纯文本,是!则用Writer、
设备:硬盘,一个文件,使用FileWriter
code:
FileWriter fw = new FileWriter(“a.txt”);
//提高效率?
BufferedWriter bufw = new BufferedWriter(fw);
扩展,想要把录入的数据按照指定的编码表存入,将数据存到文件中。
目的:OutputStream Writer //是否是纯文本,是!则用Writer、
设备:硬盘,一个文件,使用FileWriter
但是FileWriter是使用的默认编码表:GBK
但是存储时,需要加入指定编码表,而指定的编码表只有转换流可以指定。所以要使用的对象是OutputStreamWriter.而该转换对象要接收一个字节输出流,而且还可操作的文件的字节输出流。FileOutputStream
code:
OutputStreamWriterosw = new OutputStreamWriter(new FileOutputStream(“d.txt”),”UTF-8”);
需要高效吗?需要!
BufferedWriterbufw = new BuffereWriter(osw);
所以,记住!转换流什么使用,字符和字节之间的桥梁,通常,涉及到字符编码转换时,需要用到转换流。
读取指定编码表的文件
InputStreamReader
改变标准输入输出设备. -不常用
System.setIn(new FileInputStream(“a.txt”);
System.setOut(newFileOutputStream(“b.txt”));
系统日志文件
catch(Exception e){
Date d = newDate();
SimpleDateFormatsdf = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);
String s =sdf.format(d);
PrintStreamps = new PrintStream(“exeception.log”)
ps.println(s);
System.setOut(ps);
e.printStackTreace(System.out);
}
打印系统信息
Properties p =System.getProperties();
//p.list(System.out);
p.liset(newPrintStream(“systeminfo.txt”));