装饰设计模式:
当想要对已有的对象进行功能增强时,可以自定义类,将已有的对象传入,基于已有的对象,并提供加强功能,那么自定义的类就称为加强类。装饰类通常通过构造方法传递。
装饰类和继承的区别:
装饰模式比继承模式要灵活,而且降低了类与类之间的关系。
装饰类增强已有对象,与已有对象具备的功能是相同的,只不过提供了更强的功能,装饰类和被装饰类通常都是属于一个体系中。
LineNumberReader实例
/*
LineNumberReader Demo.
*/
import java.io.*;
class LineNumberDemo
{
public static void main(String[] args)
{
BufferedReader buf=null;
LineNumberReader lineNumber=null;
try{
buf=new BufferedReader(new FileReader("buf.txt"));
lineNumber=new LineNumberReader(buf);
String str=null;
while((str=lineNumber.readLine())!=null){
System.out.println(lineNumber.getLineNumber()+"..."+str);
}
}
catch(IOException e){
throw new RuntimeException("read error.");
}
finally{
try{
if(lineNumber!=null){
lineNumber.close();
}
}
catch(Exception e){
System.out.println(e);
}
}
}
}
自定义LineNumberReader实例
/*
重写LineNumber类,实现行号的显示和设置。
*/
import java.io.*;
class MyLineNumberDemo
{
public static void main(String[] args)
{
FileReader fr=null;
BufferedReader buf=null;
//捕捉异常。
try{
fr=new FileReader("buf.txt");
buf=new BufferedReader(fr);
//使用自定义的MyLineNumber类。
MyLineNumber myLine=new MyLineNumber(buf);
String str=null;
//设置行号。
myLine.setLineNumber(100);
//读取缓冲区中的数据。
while((str=myLine.readLine())!=null){
//获取行号并显示。
System.out.println(myLine.getLineNumber()+"..."+str);
}
}
catch(Exception e){
System.out.println(e);
}
finally{
try{
if(buf!=null)
buf.close();
}
catch(Exception e){
System.out.println(e);
}
}
}
}
//自定义MyLineNumber类,显示和获取行号。
class MyLineNumber
{
//将数据读取到缓冲区中。
private BufferedReader bufr;
//设置行号属性。
private int lineNumber=0;
//在构造函数中直接初始化操作的缓冲区。
MyLineNumber(BufferedReader bufr){
this.bufr=bufr;
}
//获取行号。
public int getLineNumber(){
return lineNumber;
}
//设置行号。
public void setLineNumber(int num){
this.lineNumber=num;
}
//关闭缓冲区并抛出异常。
public void close()throws IOException{
bufr.close();
}
//自定义一行行读取,并抛出异常。
public String readLine()throws IOException{
//每读取一行,行号自定增加。
this.lineNumber++;
//将读取到的行数据存储在字符串缓冲区中。
StringBuilder sb=new StringBuilder();
int ch=0;
//依次读取字符,并判断是否达到行尾。
while((ch=bufr.read())!=-1){
//windows行尾由\r\n来确定。
//读取到\r继续但不存储。
if(ch=='\r')
continue;
//读取到\n直接将存储的行数据转化到字符串。
if(ch=='\n')
return sb.toString();
//如果不是到行尾则将读取的字符存储到字符串缓冲区。
else
sb.append((char)ch);
}
//读取完成后,若最后一行不换行,此时ch!=\n,但字符串缓冲区中
//仍有数据,需将该数据输出。
if(sb.length()!=0)
return sb.toString();
return null;
}
}
字节流
字节流的读取方式
import java.io.*;
class FileInput
{
public static void main(String[] args) throws Exception
{
//单个字节逐个读取。
readFile_1();
//按照固定长度读取。
//建议采用该方法。
readFile_2();
//根据要读取的字节长度读取。
//由于读取的文件大小不定,有可能内存溢出,该方法慎用。
readFile_3();
}
//单个字节逐个读取。
public static void readFile_1() throws Exception{
FileInputStream fop=new FileInputStream("buf.txt");
int by=0;
while((by=fop.read())!=-1){
System.out.print((char)by);
}
fop.close();
}
//按照固定的长度读取字节数。
public static void readFile_2() throws Exception{
FileInputStream fop=new FileInputStream("buf.txt");
byte[] by=new byte[1024];
int len=0;
while((len=fop.read(by))!=-1){
System.out.print(new String(by,0,len));
}
fop.close();
}
//按照操作文本的长度读取字节数
public static void readFile_3() throws Exception{
FileInputStream fop=new FileInputStream("buf.txt");
byte[] by=new byte[fop.available()];
fop.read(by);
System.out.print(new String(by));
fop.close();
}
}
图片的复制
思路:
1.用字节读取流和要读取的图片关联
2.用字节写入流对象创建一个图片,用于存储读取到的图片数据
3.循环读取,直到将图片数据读取完毕
4.关闭资源(异常处理)
/*
复制图片
*/
import java.io.*;
class CopyPicture
{
public static void main(String[] args)
{
FileInputStream fis=null;
FileOutputStream fos=null;
try{
fis=new FileInputStream("1.jpg");
fos=new FileOutputStream("1copy.jpg");
byte[] picData=new byte[1024];
int len=0;
while((len=fis.read(picData))!=-1){
fos.write(picData,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音频文件(方式一)
/*
复制MP3音频文件
*/
import java.io.*;
class copyMp3
{
public static void main(String[] args)
{
//起始时间
long start =System.currentTimeMillis();
//复制MP3文件
copyMedia();
//终止时间
long end =System.currentTimeMillis();
System.out.println(end-start+"ms");
}
public static void copyMedia(){
BufferedInputStream bufi=null;
BufferedOutputStream bufo=null;
try{
//定义读取和写入缓冲区
bufi=new BufferedInputStream(new FileInputStream("1.mp3"));
bufo=new BufferedOutputStream(new FileOutputStream("1copy.mp3"));
int by=0;
while((by=bufi.read())!=-1){
bufo.write(by);
}
}
catch(Exception e){
throw new RuntimeException("读写失败");
}
finally{
try{
if(bufi!=null)
bufi.close();
}
catch(Exception e){
throw new RuntimeException("关闭读取失败");
}
try{
if(bufo!=null)
bufo.close();
}
catch(Exception e){
throw new RuntimeException("关闭写入失败");
}
}
}
}
复制MP3音频文件(方式二)
/*
MP3复制(方式二)
自定义缓冲区
*/
import java.io.*;
class mp3Copy2
{
public static void main(String[] args) throws IOException
{
long start=System.currentTimeMillis();
copyMedia();
long end=System.currentTimeMillis();
System.out.println(end-start+"ms");
}
public static void copyMedia(){
MyBufferedInputStream bufi=null;
BufferedOutputStream bufo=null;
try{
//定义读取和写入缓冲区
bufi=new MyBufferedInputStream(new FileInputStream("1.mp3"));
bufo=new BufferedOutputStream(new FileOutputStream("3copy.mp3"));
int by=0;
while((by=bufi.myRead())!=-1){
//通过myRead方法将byte提升了int型,而write方法则又
//将int型转化为byte型,只截取了int型的低8位。
//write返回的是byte
bufo.write(by);
}
}
catch(Exception e){
throw new RuntimeException("读写失败");
}
finally{
try{
if(bufi!=null)
bufi.myClose();
}
catch(Exception e){
throw new RuntimeException("关闭读取失败");
}
try{
if(bufo!=null)
bufo.close();
}
catch(Exception e){
throw new RuntimeException("关闭写入失败");
}
}
}
}
class MyBufferedInputStream
{
private InputStream in;
private int count=0,pos=0;
private byte[] buf=new byte[1024];
MyBufferedInputStream(InputStream in){
this.in=in;
}
//一次读取一个字节,从缓冲区获取。
public int myRead()throws IOException{
//count为0表示buf中么有数据了。
if(count==0){
//从缓冲区中抓去一批数据存储到buf中,in.read(buf)返回获取到
//的字节个数,并将获取到的数据存储到buf中
count=in.read(buf);
//倘若count小于0,则没有读取到数据。
if(count<0){
return -1;
}
//获取到数据后,pos指向数组的0位置。
pos=0;
//从数组中获取一个字节的数据并返回
byte b=buf[pos];
count--;
pos++;
//由于myRead()函数返回的是int型,而b为byte型,相当于向上提升。
//音频文件中可能出现连续的1111 1111,而此时不是文件结束的标志,
//只有当count<0返回-1时才表示读取到文件末尾。
//若b为1111 1111,返回int时在原值前面补了1,为11111111 11111111 11111111 11111111
//若在前面补0,则可以避免-1的出现。
return b&0xff;
}
else if(count>0){
byte b=buf[pos];
count--;
pos++;
return b&0xff;
}
return -1;
}
public void myClose()throws IOException{
in.close();
}
}