处理流:
处理流可以隐藏底层设备上节点流的差异,并对外提供更加方便的输入输出方法,只要关心高级流的操作方法。
使用处理流的典型思路是,使用处理流来包装节点流,程序通过处理流来执行输入输出功能,让节点流与底层的I/O设备、文件交互。
识别处理流非常简单,只要流的构造器参数不是一个物理的节点,而是已经存在的流,那么这种流就一定是处理流。而所有的节点流都是直接以物理IO节点为构造器参数的。
下面使用BuffeReader复制一个文件。BufferReader中提供了一个readLine()的方法可一非常方便的回去文件。
<span style="font-size:14px;">public class CopyTextByBuf {
public static void main(String[] args) {
BufferedReader br = null ;
BufferedWriter bw = null ;
try {
//创建BufferedReader对象,将FileReader字符流当参数传递进去
br = new BufferedReader(new FileReader("g:\\test.txt"));
bw = new BufferedWriter(new FileWriter("g:\\testCopy.txt"));
String line ;
//使用BufferedReader的readLine()方法一次读一行
//readLine()返回的字符串是不包含换行符的。
//当读到文件结尾的时候返回null
while((line=br.readLine())!=null){
bw.write(line);
//通过newLine向输出流中写入一个换行符。
bw.newLine();
//BufferWriter中带有缓冲区,输出时要刷新。
bw.flush();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if(br!=null){
try {
br.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(bw!=null){
try {
bw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}</span>
自定义一个类实现BufferReader()中的readLine()方法
readLine () 原理:实际上是调用了传进来的字符流的read()方法,每次只读一个字符,然后将读的字符存在自己的缓冲区中。当读到换行的时候将缓冲区中的字符一起输出。
public class CopyTextByBuf {
public static void main(String[] args)throws IOException {
MyBufferedReader br = null ;
br = new MyBufferedReader(new FileReader("g:\\test.txt"));
String line ;
while((line=br.myReadLine())!=null){
System.out.println(line);
}
br.myClose();
}
}
/*
* 自定义的BufferReader
*/
class MyBufferedReader{
Reader r ;
//构造MyBufferReader是需要将一个Reader传递进去
public MyBufferedReader(Reader reader){
r = reader ;
}
//使用StirngBuilder当作缓冲区
//当没有读到换行符号的时候每读一个字符就往缓冲区中放
//当读到换行符时,将缓冲区中的字符一起输出
public String myReadLine() throws IOException{
int ch =0;
StringBuilder sb = new StringBuilder();
while((ch=r.read())!=-1){
//windows 中换行符是两个字符组成
//读第一个时,直接跳出循环,再往下读
if((char)ch=='\r')
continue;
//读到换行符的末尾时输出
if((char)ch =='\n')
return sb.toString();
else sb.append((char)ch);
}
if(sb.length()!=0){
return sb.toString();
}
return null ;
}
//关闭流操作,直接关闭reader流。
//在后面使用中就不用调用reader的close方法了
public void myClose()throws IOException{
r.close();
}
}
使用LineNumberReader现实每行的行号:
public class LineNumberReaderTest {
public static void main(String[] args) throws IOException{
//创建LineNumberReader对象
LineNumberReader lr = new LineNumberReader(new FileReader("g:\\test.txt"));
String str = null ;
//设置从11行开始读
lr.setLineNumber(10);
while((str=lr.readLine())!=null){
//通过getLineNumber拿到行号
System.out.println(lr.getLineNumber()+":"+str);
}
//关闭流
lr.close();
}
}<strong>
</strong>
自定义一个类实现LineNumberReader的getLineNumber()方法。
public class LineNumberReaderTest {
public static void main(String[] args) throws IOException{
//创建MyLineNumberReader对象
MyLineNumberReader lr = new MyLineNumberReader(new FileReader("g:\\test.txt"));
String str = null ;
while((str=lr.myReadeLine())!=null){
//通过myReadeLine拿到行号
System.out.println(lr.myGetlineNumber()+":"+str);
}
//关闭流
lr.myClose();
}
}
class MyLineNumberReader{
Reader r ;
int lineNumber ;
public MyLineNumberReader(Reader reader){
r = reader ;
}
public String myReadeLine()throws IOException{
StringBuilder buf = new StringBuilder() ;
int ch = 0 ;
while((ch = r.read())!=-1){
if(ch =='\r')
continue;
if(ch=='\n'){
//当读到一行的末尾时,行号加一。
lineNumber++;
return buf.toString();
}
else
buf.append((char)ch);
}
if(buf.length()!=0){
//当结尾不是以换行结束在返回字符串是行号加一。
lineNumber++;
return buf.toString();
}
return null ;
}
public int myGetlineNumber(){
return lineNumber ;
}
public void myClose()throws IOException{
r.close();
}
}
装饰设计模式:
当想要对已有的对象进行功能加强时,可以定义一个类,将已有的对象传入,基于已有的功能并提供加强功能。自定义的类称为装饰类。
装饰类通常会通过构造方法接受被装饰的对象,并基于被装饰的对象进行功能的加强。
- 通过继承可以实现讲一个类的功能进行加强
MyReader :专门用于读取数据的类
| --MyTextReader
| --MyBufferTextReader
| --MyMediaReader
| --MyBufferMediaReader
| --MyDataReader
| --MyBufferDataReader
通过继承实现,展现性不好,继承关系复杂。对不同的类增加相同的功能时,每个都要添加,添加的代码还是一样的。
- 通过继承可以实现讲一个类的功能进行加强
MyReader :专门用于读取数据的类
| --MyTextReader
| --MyMediaReader
| --MyDataReader
| --MyBufferReader
装饰模式比继承要灵活,避免了继承关系的臃肿,而且降低了类与类之间的关系。
装饰类因为只是增强已有的对像,具有的功能和已有的功能相同,只是提供了更强的功能。所以装饰类和被装饰类通常位于一个体系中。
public class PersonTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
SuperPerson person1 =new SuperPerson(new Person());
person1.chifan();
SuperPerson2 person2 = new SuperPerson2() ;
person2.chifan();
}
}
class Person{
public void chifan(){
System.out.println("吃饭");
}
}
//采用装饰的方式增强Person类
class SuperPerson{
Person p ;
public SuperPerson(Person p){
this.p = p ;
}
public void chifan(){
System.out.println("开胃酒") ;
p.chifan();
System.out.println("甜点");
}
}
//采用继承的方式增强Person类
class SuperPerson2 extends Person{
public void chifan(){
System.out.println("开胃酒") ;
super.chifan();
System.out.println("甜点");
}
}
自定一个读取缓冲区类,模拟一个BufferReader
缓冲原理:从源中获取一批数据到缓冲区中,再从缓冲区中不断地取出一个一个数据,当缓冲区中的数据取完了,再从源中缓存一批数据到缓冲区中。当数据取完是返回-1.
public class MyBufferReaderTest {
public static void main(String[] args)throws IOException{
MyBufferReader mr = new MyBufferReader(new FileReader("g:\\test.txt"));
String str =null ;
while((str=mr.myReadLine())!=null){
System.out.println(str);
}
}
}
class MyBufferReader{
Reader r ;
//定义一个数组最为缓冲区
char[] buf = new char[1024] ;
public MyBufferReader(Reader r){
this.r = r ;
}
//定义count保存每次读取字符的个数,表示可以读的个数。index为数组的下表
int count ,index ;
public int myRead() throws IOException{
//当count为0时从源中读取数据,将读取个数放到count中,
//将数组游标清0;
if(count ==0){
count = r.read(buf) ;
index =0;
return buf[index];
}
//当count==-1是表示已经读到末尾了
if(count ==-1){
return -1 ;
}
//每读一次,游标向下移动一次,可读个数减1.
char c = buf[index];
count--;
index++;
return c ;
}
public String myReadLine()throws IOException{
StringBuilder buf = new StringBuilder();
int ch ;
while((ch=myRead())!=-1){
if(ch=='\r')
continue ;
if(ch=='\n')
return buf.toString();
else
buf.append((char)ch);
}
if(buf.length()!=0){
return buf.toString();
}
return null;
}
}