文件操作练习
1.文件复制图解:通过 buf 缓冲区 两个字符流建立联系。
2. 将E 盘文件复制到D盘:
package day21;
import java.io.*;
public class FileDemo {
private static int BUF_SIZE=1024;
public static void main(String[] args) {
test1();
//test2();
}
/**
* 需求:把 E盘的文件复制到D盘
* 1.需要
* 读取源。
* 2.将读取的数据写入目的地。
* 3.使用字符流
*
* 步骤:
* 1.读取已知文本文件。使用字符和文件关联。
* FileReadear fr =new FileReader ("IO_文件.txt");
* 2.创建一个目标
* FileWriter fw= new FileWriter("copytext_1.txt");
* 3.频繁的读写操作。
* int ch=0;
* 方式1
* while(ch=(fr.read())!=-1){
*
* }
* 方式2:效率高
* while((len=fw.read(buf))=-1)
* 4.关闭流
*
*/
public static void test1(){
int ch=0; //1.
FileReader fr=null;
FileWriter fw=null;
try{
fr = new FileReader("E:\\java\\20190420_1\\test1.txt");//E:\java\20190420_1
fw = new FileWriter("D:\\test1.txt");
while((ch =fr.read())!=-1){
fw.write(ch);
}
}catch ( IOException e) {
e.getMessage();
} finally {
try{
if(fr!=null){
fr.close();
}
} catch (IOException e)
{
e.printStackTrace();
}
try{
if(fw!=null){
fw.close();
}
}catch (IOException e){
e.printStackTrace();
}
}
//2.
//3.
}
public static void test2(){
int len=0; //1.读取的长度
FileReader fr=null;
FileWriter fw=null;
try{
fr = new FileReader("E:\\java\\20190420_1\\test1.txt");//E:\java\20190420_1
fw = new FileWriter("D:\\test3.txt");
char[] buf =new char[BUF_SIZE];// 不建议写成char[1024*4] 会做运算
while((len =fr.read(buf))!=-1){
}
fw.write(buf,0,len);
}catch ( IOException e) {
e.getMessage();
throw new RuntimeException(" 文件读取失败");
} finally {
try{
fw.close();// 没做关流操作的话这个文件删不掉。
fr.close();
} catch (IOException e)
{
e.printStackTrace();
}
}
//2.
//3.
}
}
BufferedReader ,BufferedWriter 字符流缓冲区
字符流的缓冲区,缓冲区的出现提高了对数据的读写效率。对应类 • BufferedWriter • BufferedReader缓冲区要结合流才可以使用。在流的基础上对流的功能进行了增强。
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
public void newLine()
throws IOException写一行行分隔符。 行分隔符字符串由系统属性line.separator定义,并不一定是单个换行符('\ n')字符。
异常
IOException - 如果发生I / O错误
public static void bufferwriter(){
String seperator =System.getProperty("line.separator");// 行分隔符字符串由系统属性line.separator定义
try{
FileWriter fw = new FileWriter ("bufferwriter.txt");
BufferedWriter bw =new BufferedWriter(fw);
// 接下来使用缓冲区的write flush close
bw.write("aaaaa\r\naaadzzzz");
bw.write("ddddd"+seperator+"ddddddd");
for(int i=0;i<10;i++){
bw.newLine();// 换行
bw.write("aafffffff");
bw.flush();
}
bw.flush();
// close 的操作实际是内部是fw 的close 操作。buffedwriter 只是起到了缓冲作用。提高效率。
bw.close();
} catch (IOException e ){
e.printStackTrace();
}
}
BufferedReader : 可以读一行
demo:
public static void bufferedreader(){
FileReader fr=null;
BufferedReader bf = null;
String str=null;
try{
fr = new FileReader("bufferedwriter.txt");
bf = new BufferedReader(fr);
try{
while((str=bf.readLine())!=null){//public String readLine()
System.out.println(str);
}
}catch (IOException e){
e.printStackTrace();
}
} catch ( FileNotFoundException e){
e.printStackTrace();
}
finally{
try{
if(bf!=null){
bf.close();
}
}catch ( IOException e ){
e.printStackTrace();
}
}
}
这个方法的原理是什么?
练习:利用缓冲区 文件复制
public static void bufferedWriteAndBufferedReader(){
FileReader fr=null;
BufferedReader br=null;
FileWriter fw = null;
BufferedWriter bw= null;
String filename ="bufferedwriter.txt";
String file_write="file_write.txt";
String len =null;
try{
fr= new FileReader(filename);
br= new BufferedReader(fr);
try{
fw= new FileWriter(file_write);
bw= new BufferedWriter(fw);
while ((len=br.readLine())!=null ){
bw.write(len);
bw.newLine();//换行
bw.flush();
}
} catch ( IOException e){
}
}catch ( FileNotFoundException e){
e.printStackTrace();
}
finally {
try{
if(bw!=null){
bw.close();
}
}catch ( IOException e){
e.printStackTrace();
}
try{
if(br!=null){
br.close();
}
}catch ( IOException e){
}
}
}
自定义 MyBufferedReader:
package day21;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.Arrays;
/***
* 缓冲原理:从源中获取一批数据,装入缓冲区
* 从缓冲区取出一个个数据,数据取完再获取一批。直到数据取完返回-1;
*/
public class MyBufferedReader extends Reader {
private Reader reader ;
private int pos=0;//定义一个指针操作数组元素,
private char[] buf =new char[1024];//定义一个数组作为缓冲区
private int count =0;// 元素个数
public MyBufferedReader(FileReader fileReader){
this.reader= fileReader;
count=0;
pos=0;
}
@Override
public void close() throws IOException {
reader.close();
}
@Override
public int read(char[] chars, int i, int i1) throws IOException {
return 0;
}
public int myread(){//有问题
if(count>=0){
if(count==0){
try{
int len= reader.read(buf);
// System.out.println("len ="+len);
pos=0;
if(len==-1){
return -1;
}else{
count=len;
}
}catch ( IOException e){
e.printStackTrace();
}
}
count--;
// System.out.println("pos ="+pos+" buf "+buf[pos]);
char ch= buf[pos++];
return ch ;
}
return -1;
}
/****
* 需求:读取一行,
* 思路:
* @return
*/
public String readLine()throws IOException{
StringBuilder sb= new StringBuilder();
int ch=0;
while((ch=myread())!=-1){
// if(buf[pos]=='\r')//不应该 使用 pos 写成buf[pos ]会丢失 一个字符 因为 里面已经当处在 '\r'前一个 字符ch , pos++
// 已经指向‘\r’ ,这个字不会被添加到 sb
if(ch=='\r')
{
// System.out.println("-----");
continue;
}
if(ch=='\n'){
return sb.toString();//123 \r \n a22222222baqqqqqqqqqqcaeeeeeeeeeeeeeeeeedaeeeeeeeeeeeeef
}
sb.append((char) ch);//如果最后的没有回车 被删除了。这时不会进入 ch=='\n' ,最后一串会丢失
// 在while 外做判断 字符串不为空就返回保证最后一串返回
}
if(sb.length()!=0){
return sb.toString();
}
return null;
}
/**
* 该方法从缓冲区中一次取一个字符。
* @return
* @throws IOException
*/
public int myRead() throws IOException{
if(count==0){//一个数据
count = reader.read(buf);
pos = 0;
}
if(count<0)
return -1;
char ch = buf[pos++];
count--;
return ch;
/*
//1,从源中获取一批数据到缓冲区中。需要先做判断,只有计数器为0时,才需要从源中获取数据。
if(count==0){
count = r.read(buf);
if(count<0)
return -1;
//每次获取数据到缓冲区后,角标归零.
pos = 0;
char ch = buf[pos];
pos++;
count--;
return ch;
}else if(count>0){
char ch = buf[pos];
pos++;
count--;
return ch;
}*/
}
}
package cn.itcast.p4.io.charstream.mybuffer;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
/**
* 自定义的读取缓冲区。其实就是模拟一个BufferedReader.
*
* 分析:
* 缓冲区中无非就是封装了一个数组,
* 并对外提供了更多的方法对数组进行访问。
* 其实这些方法最终操作的都是数组的角标。
*
* 缓冲的原理:
* 其实就是从源中获取一批数据装进缓冲区中。
* 在从缓冲区中不断的取出一个一个数据。
*
* 在此次取完后,在从源中继续取一批数据进缓冲区。
* 当源中的数据取光时,用-1作为结束标记。
*
*
* @author Administrator
*
*/
public class MyBufferedReader extends Reader {
private Reader r;
//定义一个数组作为缓冲区。
private char[] buf = new char[1024];
//定义一个指针用于操作这个数组中的元素。当操作到最后一个元素后,指针应该归零。
private int pos = 0;
//定义一个计数器用于记录缓冲区中的数据个数。 当该数据减到0,就从源中继续获取数据到缓冲区中。
private int count = 0;
MyBufferedReader(Reader r){
this.r = r;
}
/**
* 该方法从缓冲区中一次取一个字符。
* @return
* @throws IOException
*/
public int myRead() throws IOException{
if(count==0){一个数据
count = r.read(buf);
pos = 0;
}
if(count<0)
return -1;
char ch = buf[pos++];
count--;
return ch;
/*
//1,从源中获取一批数据到缓冲区中。需要先做判断,只有计数器为0时,才需要从源中获取数据。
if(count==0){
count = r.read(buf);
if(count<0)
return -1;
//每次获取数据到缓冲区后,角标归零.
pos = 0;
char ch = buf[pos];
pos++;
count--;
return ch;
}else if(count>0){
char ch = buf[pos];
pos++;
count--;
return ch;
}*/
}
public String myReadLine() throws IOException{
StringBuilder sb = new StringBuilder();
int ch = 0;
while((ch = myRead())!=-1){
if(ch=='\r')
continue;
if(ch=='\n')
return sb.toString();
//将从缓冲区中读到的字符,存储到缓存行数据的缓冲区中。
sb.append((char)ch);
}
if(sb.length()!=0)
return sb.toString();
return null;
}
public void myClose() throws IOException {
r.close();
}
@Override
public int read(char[] cbuf, int off, int len) throws IOException {
return 0;
}
@Override
public void close() throws IOException {
}
}
装饰设计模式;
BufferedReader ,BufferedWriter 是使用了装饰设计模式,对FileReader,FileWriter 装饰。增强效率。
装饰的与继承 有什么区别?
对一组对象的功能进行增强时,就可以使用该模式进行问题的解决。
装饰和继承都能实现一样的特点:进行功能的扩展增强。
有什么区别呢?
首先有一个继承体系。
Writer
|--TextWriter:用于操作文本
|--MediaWriter:用于操作媒体。
想要对操作的动作进行效率的提高。
按照面向对象,可以通过继承对具体的进行功能的扩展。
效率提高需要加入缓冲技术。
Writer
|--TextWriter:用于操作文本
|--BufferTextWriter:加入了缓冲技术的操作文本的对象。
|--MediaWriter:用于操作媒体。
|--BufferMediaWriter:
到这里就哦了。但是这样做好像并不理想。
如果这个体系进行功能扩展,有多了流对象。
那么这个流要提高效率,是不是也要产生子类呢?是。这时就会发现只为提高功能,进行的继承,
导致继承体系越来越臃肿。不够灵活。
重新思考这个问题?
既然加入的都是同一种技术--缓冲。
前一种是让缓冲和具体的对象相结合。
可不可以将缓冲进行单独的封装,哪个对象需要缓冲就将哪个对象和缓冲关联。
class Buffer{
Buffer(TextWriter w)//缓冲 TextWriter
{}
Buffer(MediaWriter w)//缓冲 MediaWriter
{
}
}
class BufferWriter extends Writer{//本身是继承 Writer
BufferWriter(Writer w)
{
}
}
Writer
|--TextWriter:用于操作文本
|--MediaWriter:用于操作媒体。
|--BufferWriter:用于提高效率。
装饰比继承灵活。
特点:装饰类和被装饰类都必须所属同一个接口或者父类。
package cn.itcast.p5.wrapper;
public class PersonDemo {
/**
* @param args
*/
public static void main(String[] args) {
Person p = new Person();
// p.chifan();
NewPerson p1 = new NewPerson(p);
p1.chifan();
NewPerson2 p2 = new NewPerson2();
p2.chifan();
}
}
class Person{
void chifan(){
System.out.println("吃饭");
}
}
//这个类的出现是为了增强Person而出现的。
class NewPerson{
private Person p ;
NewPerson(Person p){
this.p = p;
}
public void chifan(){
System.out.println("开胃酒");
p.chifan();//不要随便修改原代码
System.out.println("甜点");
}
}
class NewPerson2 extends Person{
public void chifan(){
System.out.println("开胃酒");
super.chifan();
System.out.println("甜点");
}
}
LineNumReader :
是继承BufferedReader :
例子:
package day21;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
public class LineNumberDemo {
public static void main(String[] args) {
lineNumber();
}
public static void lineNumber(){
FileReader fr;
LineNumberReader lineNumberReader;
try{
fr = new FileReader("test2.txt");
lineNumberReader= new LineNumberReader(fr);
try{
String str=null;
lineNumberReader.setLineNumber(3);
while( ( str= lineNumberReader.readLine())!=null) {
System.out.println(str + " 行号" + lineNumberReader.getLineNumber());
}
}catch (IOException e){
e.printStackTrace();
}
}catch ( FileNotFoundException e){
e.printStackTrace();
}
}
}
/***
123 行号1
sssssssss 行号2
a22222222b 行号3
aqqqqqqqqqqc 行号4
aeeeeeeeeeeeeeeeeed 行号5
aeeeeeeeeeeeeef 行号6
调用 set 3后 ,只会影响 get 的行号
123 行号4
sssssssss 行号5
a22222222b 行号6
aqqqqqqqqqqc 行号7
aeeeeeeeeeeeeeeeeed 行号8
aeeeeeeeeeeeeef 行号9
*/