IO流
1 缓冲区的出现
缓冲区的出现是为了提高流的操作效率而出现的,避免了频繁的读写,但是缓冲区的服务对象是流,如果没有了流,那么缓冲区的存在会失去意义。
2 BufferedWriter与BufferedReader
关于BufferedWriter类,它的作用是为了在写入之前暂时存储字符,它的一般用法有:
.write(),写入字符进入缓冲区方法
.newLine(),换行操作
.flush(),将缓冲区内容写入目标文件
.close(),关闭缓冲区资源,在.close()之前,如果没有执行.flush(),则.close()会自动执行关闭内容
// 一个例子
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(),可以分行读取文本内容,但是也需要FileReader对象,将它传入BufferedReader()中,装饰器的做法
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class BufferedReaderDemo {
public static void main(String[] args) throws IOException
{
FileReader FR = new FileReader("demo.txt");
BufferedReader bfr = new BufferedReader(FR);// 加入缓冲区
String line = null;
while ((line=bfr.readLine())!=null)
{
System.out.println(line);
}
}
}
3 一个例子:拷贝文件的内容
内容描述:通过缓冲区复制一个文件
import java.io.*;
public class CopyTextByBuf3 {
public static void main(String[] args)
{
BufferedReader bufr = null;
BufferedWriter bufw = null;
try
{
bufr = new BufferedReader(new FileReader("demo.txt"));// 在缓冲器中添加读入器,读入demo.txt
bufw = new BufferedWriter(new FileWriter("demo_copy.txt")); // 在缓冲器中添加写入器,拷贝的目标文件 demo_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("关闭bufr失败");
}
try {
if(bufw!=null)
bufw.close(); // 关闭资源
}
catch (IOException e)
{
throw new RuntimeException("关闭bufw失败");
}
}
}
}
4 实现BufferedReadLine()方法
5 装饰器设计模式、与继承的区别
装饰器比较继承来说,可以先通过一个例子来描述:
public class PersonDemo {
public static void main(String[] args)
{
Person p = new Person();
// 装饰器写法:将普通人对象传入超级人
SuperPerson sp = new SuperPerson(p);
sp.SuperEat();
p.eat();
}
}
class Person
{
public void eat()
{
System.out.println("普通方法:坐着吃饭");
}
}
class SuperPerson
{
private Person p;
SuperPerson(Person p) // 普通对象传入超级对象类中
{
this.p = p;
}
public void SuperEat()
{
System.out.println("升级方法:倒立吃饭");
}
}
打印结果:
升级方法:倒立吃饭
普通方法:坐着吃饭
————分割线 ————
这里有一个问题,既然装饰器可以写一个新的方法“超级吃饭”,那么为什么不用继承的方法,复写父类方法中的“普通方法”呢?
回答是当然可以使用继承的方法来复写父类方法,但是这样的做法会让原本的继承体系更加臃肿,而使用装饰器写法,改变了类与类之间的关系。
将继承关系转化为了组合关系
例如:
MyReader//专门用于读取数据的类。
|--MyTextReader
|--MyBufferTextReader // 继承
|--MyMediaReader
|--MyBufferMediaReader // 继承
|--MyDataReader
|--MyBufferDataReader // 继承
MyReader//专门用于读取数据的类。
|--MyTextReader
|--MyMediaReader
|--MyDataReader
|--MyBufferReader //装饰器
装饰器和这些类是同一级的,关于装饰器的一个比喻:装饰者做的事情就像是面包店里的甜点师,向不同的面包上涂抹同一种味道的奶油。
总结:
- 装饰者将继承关系转化为了组合关系,消解了类与子类之间的耦合性
- 装饰者类与其它类之间为同级关系,它们都属于同一个体系
- 装饰者提供了某个方法的更强的功能
- 装饰者通过构造函数接收对象
6 一个例子:自定义一个行计数器
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public class MyLineNumberReader {
private Reader R;
private int LineNum;
MyLineNumberReader(Reader R)
{
this.R = R; //
}
public String MyReadLine() throws IOException
{
LineNum++; // 调用自增计数器
StringBuilder sb = new StringBuilder();
int ch = 0;
while ((ch=R.read())!=-1) // 单个读取
{
if (ch=='\r') // 遇到\r,跳过
continue;
if (ch=='\n') // 遇到换行标志,返回字符串
return sb.toString();
else
sb.append((char)ch); // 添加字符串进入StringBuilder
}
if (sb.length()!=0)
return sb.toString(); // 如果结尾没有\n时,也返回字符串
return null;
}
public void setLineNumber(int LineNum)
{
this.LineNum = LineNum;
}
public int getLineNumber()
{
return LineNum;
}
public void myClose() throws IOException
{
R.close();
}
}
class MyLineNumberReaderDemo
{
public static void main(String[] args) throws IOException
{
// 自定义
FileReader fr = new FileReader("/Users/zy/zy_Javase/my_work/day19/19/src/BufferedReaderDemo.java");
// 装饰器
MyLineNumberReader mylnr = new MyLineNumberReader(fr);
String line = null;
while (((line=mylnr.MyReadLine())!=null)) // 调用类中方法
{
System.out.println(mylnr.getLineNumber()+" - "+line);
}
mylnr.myClose();
}
}
7 一个例子:使用字节流复制图片
关于字节流,字节流操作的对象是多媒体文件,例如视频、图片、歌曲文件,字节流有两个类:InputStream、OutputStream,下面实例演示如何复制一张图片,用到了一个暂时的数据容器buf
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyPicture {
public static void main(String[] args) throws IOException
{
FileInputStream fis = null;
FileOutputStream fos = null;
try
{
fis = new FileInputStream("PIG.jpg");// 需要复制文件
fos = new FileOutputStream("PIG_copy.jpg");// 得到的文件
byte[] buf = new byte[1024]; // 以1k为单位写入
int len = 0;
while ((len=fis.read(buf))!=-1) // 写入到缓存buf
{
fos.write(buf,0,len); // 将缓存内容写入文件,直到文件复制结束。
}
}
catch (IOException e)
{
throw new RuntimeException("复制文件失败");
}
finally {
try
{
if (fis!=null)
System.out.println("复制成功");
fis.close();
}
catch (IOException e)
{
}
}
}
}