------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
BufferedWriter:
缓冲区的出现是为了提高流的操作效率而出现的。所以在创建缓冲区之前,必须要先有流对象。该缓冲区中提供了一个跨平台的换行符newLine();
练习:
package IO;
import java.io.*;
public class BufferedWriterDemo {
public static void main(String[] args)throws Exception {
//实例化一个字符写入流
Writer w=new FileWriter("e:/a.txt");
//给字符写入流包装一下,提高效率
BufferedWriter bw=new BufferedWriter(w);
bw.write("abc");
bw.newLine();//换行符
bw.write("efg");
bw.flush();
bw.close();//关闭资源
}
}
BufferedReader:字符读取流缓冲区:该缓冲区可以进行读一行操作,方便对文件的读取。当返回Null时,就读到末尾了。
练习:
package IO;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.Reader;
public class BufferedReaderDemo {
public static void main(String[] args)throws Exception {
//创建一个读取流对象和文件关联
Reader r=new FileReader("e:/a.txt");
//加入缓冲技术,提高效率,与读取流对象关联起来
BufferedReader bw=new BufferedReader(r);
String line=null;
while((line=bw.readLine())!=null){
System.out.println(line);
}
<span style="white-space:pre"> </span>bw.colse();
}
}
要求:通过缓冲区复制文本文件
package IO;
/*
* 思路:
* 1.先有读取流和需要被复制的文件关联,然后加入缓冲区
* 2.有一个写入流和目的文件相关联,然后加入缓冲区
* 3.一边读取一行,一边写进一行,这样就能完成复制
*/
import java.io.*;
public class CopyFile {
public static void main(String[] args)throws Exception {
//读取流
BufferedReader br=new BufferedReader(new FileReader("e:/CopyFile.java"));
//写入流
BufferedWriter bw=new BufferedWriter(new FileWriter("e:/copy.txt"));
//一边读,一边写
String line=null;
while((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
bw.close();
br.close();
}
}
readLine的原理:
将读到的\r\n时,就将数组中的已有数据打印出来。然后继续读下一行的元素。
模拟readLine功能写一个自己的MyBufferedReader
代码:
package IO;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.io.Reader;
/*
* 思路:
* 1.readLine的原理就是读到\r\n时,才把所读到的所有存进缓冲区。
* 2.知道原理后,自己可以写一个BufferedReader
*/
public class MyBufferedReader {
private FileReader r;
public MyBufferedReader(FileReader r){
this.r=r;
}
//为了方便,这里定义StringBuilder容器,因为最终还是要将数组转换成字符串
public String myReadLine()throws Exception{
StringBuilder sb=new StringBuilder();
int ch=0;
while((ch=r.read())!=-1){
if(ch=='\r')
continue;
if(ch=='\n')
return sb.toString();
else
sb.append((char)ch);//这点很重要,记得要强制转换成char,不然复制出来全是数字。
}
if(sb.length()!=0){//如果最后一行没有换行符,它就导致最后一行存进缓冲区,没被返回。所有自己判断一下
return sb.toString();
}
return null;
}
public void myClose()throws Exception{
r.close();
}
public static void main(String[] args){
MyBufferedReader mbr=null;
BufferedWriter bw=null;
try {
mbr=new MyBufferedReader(new FileReader("e:/copy.txt"));
bw=new BufferedWriter(new FileWriter("e:/copy_1.txt"));
String line=null;
while((line=mbr.myReadLine())!=null){//运用自己的读一行的方法
bw.write(line);
bw.newLine();
bw.flush();
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try{
if(mbr!=null){
mbr.myClose();
}
}catch(Exception e){
e.printStackTrace();
}
try{
if(bw!=null){
bw.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
}
注意:最后一行可能没有换行符,那么数据也只是存到缓冲区,并没有被返回,所有最好进行自己的判断,返回。
if(sb.length()!=null){
retren sb.toString();
}
装饰者设计模式:
将被增强的对象,传给增强的对象,基于原本的读一个的功能,扩展为读一行的功能。
装饰类通常通过构造方法接收被装饰的对象,并基于被装饰的对象的功能,提供更强大的功能。
实例:
package IO;
public class Decorator {
Student s;
public Decorator(Student s){
this.s=s;
}
public void sleep(){
System.out.println("看书");
System.out.println("听歌");
s.sleep();
}
}
class Student{
public void sleep(){
System.out.println("睡觉");
}
}
装饰和继承的区别:
如读这个体系,有读文本,读照片,读电影等,不可能每个类都继承Buffer,那么这样会造成这个体系太臃肿,且扩展性不强,这时可以直接定义一个装饰类(Buffer),把读文件等类作为参数传入,这样就具备了Buffer的增强功能。
装饰者模式就是为已有功能加强的,还是原来的体系中的类。
装饰者比继承要灵活,降低了类与类直接的关系。
自定义装饰类:
package IO;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Reader;
/*
* 这就是一个装饰类,还是属于Reader体系中
* 它继承了Reader,复写了Reader中的方法,也加强了read方法,使原来读一个变为读一行
*/
public class MyBufferedReader extends Reader {
private FileReader r;
public MyBufferedReader(FileReader r){
this.r=r;
}
//为了方便,这里定义StringBuilder容器,因为最终还是要将数组转换成字符串
public String myReadLine()throws Exception{
StringBuilder sb=new StringBuilder();
int ch=0;
while((ch=r.read())!=-1){
if(ch=='\r')
continue;
if(ch=='\n')
return sb.toString();
else
sb.append((char)ch);//这点很重要,记得要强制转换成char,不然复制出来全是数字。
}
if(sb.length()!=0){//如果最后一行没有换行符,它就导致最后一行存进缓冲区,没被返回。所有自己判断一下
return sb.toString();
}
return null;
}
@Override
public int read(char[] cbuf, int off, int len) throws IOException {
return r.read(cbuf, off, len);
}
@Override
public void close() throws IOException {
r.close();
}
}
拷贝图片:
不要用字符流来拷贝媒体文件,字符流是用来处理文字数据的。
package IO;
import java.io.*;
public class CopyPic {
public static void main(String[] args)throws Exception {
FileInputStream fis=new FileInputStream("e:/2.png");
FileOutputStream fos=new FileOutputStream("e:/copy_pic.png");
int len=0;
while((len=fis.read())!=-1){
fos.write(len);
}
fis.close();
fos.close();
}
}
自定义字节流的缓冲区--read和write的特点:
先从硬盘上抓上一把数据,再存到数组缓冲区去,然后通过指针,一个一个读出来。取完之后,再取硬盘中抓一把数据,再存到数组中去。再通过指针取。
package IO;
/*
* 定义数组:当做缓冲区,存放从硬盘中读取来的数据
* 定义指针:从数组中一个一个的读取出来
* 定义计数器:当数组中的数据读完,计数器显示为0 ,这时继续从硬盘中读取
*/
import java.io.*;
public class MyBufferedInputStream {
private InputStream ins;
byte[] buf = new byte[1024];
private int pos = 0;// 定义指针
private int count = 0;// 用来判断缓冲区数据是否读完
private MyBufferedInputStream(InputStream ins) {
this.ins = ins;
}
// 一次读一个自己 从字符缓冲区(数组)中获取
public int myRead() throws Exception {
if (count == 0) {// 当数组中的数据读完时
pos = 0;
count = ins.read(buf);
if (count == -1)
return -1;
byte b = buf[pos];
count--;
pos++; // 从数组读数据,自动从Byte提升int
return b & 255;// 防止出现-1的情况,导致文件复制不成功
}
else if(count>0){
byte b=buf[pos];
count--;
pos++;
return b & 0xff;
}
return -1;
}
public void myClose()throws Exception{
ins.close();
}
public static void main(String[] args)throws Exception{
MyBufferedInputStream fis=new MyBufferedInputStream(new FileInputStream("e:/copy.txt"));
FileOutputStream fos=new FileOutputStream("e:/copy_c.txt");
int b=0;
while((b=fis.myRead())!=-1){
fos.write(b);
}
fos.flush();
fos.close();
fis.myClose();
}
}
读取键盘的录入:
System.in对应键盘的输出设备,控制台
System.out:对应标准输入设备:键盘
注意:Read是阻塞式方法。
需求:
通过录入一行数据,然后打印出来。直到录入为over,那就停止录入。
package IO;
import java.io.*;
public class SystemDemo {
public static void main(String[] args) throws Exception {
InputStream ins = System.in;
StringBuffer sb = new StringBuffer();// 把数据先存入里面
int b = 0;
while (true) {
b = ins.read();
if (b == '\r')
continue;
if (b == '\n') {
if ("over".equals(sb.toString())) {
break;
}
System.out.println(sb.toString());
sb.delete(0, sb.length());
} else {
sb.append((char) b);
}
}
}
}
运行结果:
读取转换流:
操作字节流的字符流InputStreamReader.
怎么来的呢?实际是因为字节流没有读一行的方法,而字符流有这方法,我想要使用,那么我就必须变为字符流才可以。
package IO;
import java.io.*;
/*
* 因为BufferedReader有读一行的方法,那么把字节流转换为字符流,
* 再提高效率后,就能使用这个方法readLine();
*/
public class TransStreamDemo {
public static void main(String[] args) throws Exception {
//键盘录入对象
InputStream ins=System.in;
//字节流转换为字符流
InputStreamReader irs=new InputStreamReader(ins);
//提高效率
BufferedReader br=new BufferedReader(irs);
String line=null;
while((line=br.readLine())!=null){
if("over".equals(line)){
break;
}else
System.out.println(line);
}
}
}
写入转换流:
字符流通向字节的桥梁:OutputStreamWriter.
文件以字节的形式存在,录入的是字符,存在硬盘的是字节。字符输出流内部是缓冲区,要flush
package IO;
import java.io.*;
/*
* 因为BufferedReader有读一行的方法,那么把字节流转换为字符流,
* 再提高效率后,就能使用这个方法readLine();
*/
public class TransStreamDemo {
public static void main(String[] args) throws Exception {
//键盘录入对象
InputStream ins=System.in;
//字节流转换为字符流
InputStreamReader irs=new InputStreamReader(ins);
//提高效率
BufferedReader br=new BufferedReader(irs);
//写入转换流
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(System.out));
String line=null;
while((line=br.readLine())!=null){
if("over".equals(line)){
break;
}else
bw.write(line);
bw.newLine();
bw.flush();
}
}
}
流操作规律:
通过三个明确来完成。
1.明确源和目的
源:输入流。InputStream Reader
目的:输出流。OutputStrema Writer
2.操作的数据是否是纯文本
是:字符流
不是:字节流
3.当体系明确后,在明确要使用哪个具体的对象。
通过设备来区分
源设备:内存,硬盘,键盘
目的设备:内存,硬盘,控制台。
当涉及到字符编码转换时,需要用到转换流。
改变标准流输入输出设备:
System.setIn(new FileInputStream());
System.setOut(new FileOutputStream());