目录
处理流-BufferedReader和BufferedWriter
对于文件的拷贝,对于我们日常的使用来说,也就是复制粘贴的事情,但是我们如何在Java程序中实现呢
文件拷贝
代码演示:
首先我们要定义好几个熟悉,分别是文件的输入流和输出流,然后要定好,要拷贝那一个文件的路径,然后指定要拷贝到那一个目录下去
然后我们先使用文件输入流,先读取文件,在读取的过程中,我们直接写入,这样当fileInputStream.read(buf)这个方法的返回值是-1的时候,表示读取完毕了,此事文件也写入完毕了
注意,读取和写入完毕之后,要关闭对应的输入流和输出流
package com.outputstream_;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileCopy {
public static void main(String[] args) {
//完成 文件拷贝,将 e:\\Koala.jpg 拷贝 c:\\
//思路分析
//1. 创建文件的输入流 , 将文件读入到程序
//2. 创建文件的输出流, 将读取到的文件数据,写入到指定的文件.
String srcFilePath = "e:\\123.jpg";
String destFilePath = "d:\\123.jpg";
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
try {
fileInputStream = new FileInputStream(srcFilePath);
fileOutputStream = new FileOutputStream(destFilePath);
//定义一个字节数组,提高读取效果
byte[] buf = new byte[1024];
int readLen = 0;
while ((readLen = fileInputStream.read(buf)) != -1) {
//读取到后,就写入到文件 通过 fileOutputStream
//即,是一边读,一边写
fileOutputStream.write(buf, 0, readLen);//一定要使用这个方法
}
System.out.println("拷贝ok~");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
//关闭输入流和输出流,释放资源
if (fileInputStream != null) {
fileInputStream.close();
}
if (fileOutputStream != null) {
fileOutputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
FileReader
FileReader基本介绍
FileReader类用于读取字符文件,可以读取一个字符、一行或整个文件。 它的构造函数接受一个文件名或文件对象作为参数,并打开该文件以供读取。读取时,可以使用read()方法读取单个字符,或者使用readLine()方法读取一个字符串并自动跳过行末换行符。
FileReader相关方法:
1.new FileReader(File/String)
2.read:每次读取单个字符,返回该字符,如果到文件未尾返回-1
3.read(char[]): 批量读取多个字符到数组,返回读取到的字符数,如果到文件末尾返回-1
相关API:
1.new String(char[]):将char[]转换成String
2.new String(char[],off,len):将char[]]的指定部分转换成String
代码演示:
package com.reader_;
import org.junit.jupiter.api.Test;
import java.io.FileReader;
import java.io.IOException;
public class FileReader_ {
public static void main(String[] args) {
}
/**
* 单个字符读取文件
*/
@Test
public void readFile01() {
String filePath = "e:\\story.txt";
FileReader fileReader = null;
int data = 0;
//1. 创建FileReader对象
try {
fileReader = new FileReader(filePath);
//循环读取 使用read, 单个字符读取
while ((data = fileReader.read()) != -1) {
System.out.print((char) data);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fileReader != null) {
fileReader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 字符数组读取文件
*/
@Test
public void readFile02() {
System.out.println("~~~readFile02 ~~~");
String filePath = "e:\\story.txt";
FileReader fileReader = null;
int readLen = 0;
char[] buf = new char[8];
//1. 创建FileReader对象
try {
fileReader = new FileReader(filePath);
//循环读取 使用read(buf), 返回的是实际读取到的字符数
//如果返回-1, 说明到文件结束
while ((readLen = fileReader.read(buf)) != -1) {
System.out.print(new String(buf, 0, readLen));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fileReader != null) {
fileReader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
FileWriter
FileWriter基本介绍
FileWriter类用于写入字符文件。与FileReader类似,它的构造函数接受一个文件名或文件对象作为参数,并打开该文件以供写入。写入时,可以使用write()方法写入单个字符,或者使用write(String)方法写入一个字符串。最后必须调用close()方法关闭文件或使用try-with-resources语句自动关闭文件。
FileWriter常用方法
1.new FileWriter(File/String): 覆盖模式,相当于流的指针在首端
2.new FileWriter(File/String,true): 追加模式,相当于流的指针在尾端
3.write(int):写入单个字符
4.write(char[]):写入指定数组
5.write(char[],off,len):写入指定数组的指定部分
6.write (string): 写入整个字符串
7.write(string,offlen):写入字符串的指定部分
相关API: String类: toCharArray:将String转换成char[]
注意:
FileWriter使用后,必须要关闭(close)或刷新(flush),否则写入不到指定的文件!
代码演示:
这里需要注意的是 //关闭文件流,等价 flush() + 关闭
package com.writer_;
import java.io.FileWriter;
import java.io.IOException;
public class FileWriter_ {
public static void main(String[] args) {
String filePath = "e:\\note.txt";
//创建FileWriter对象
FileWriter fileWriter = null;
char[] chars = {'a', 'b', 'c'};
try {
fileWriter = new FileWriter(filePath);//默认是覆盖写入
// 3) write(int):写入单个字符
fileWriter.write('H');
// 4) write(char[]):写入指定数组
fileWriter.write(chars);
// 5) write(char[],off,len):写入指定数组的指定部分
fileWriter.write("韩顺平教育".toCharArray(), 0, 3);
// 6) write(string):写入整个字符串
fileWriter.write(" 你好北京~");
fileWriter.write("风雨之后,定见彩虹");
// 7) write(string,off,len):写入字符串的指定部分
fileWriter.write("上海天津", 0, 2);
//在数据量大的情况下,可以使用循环操作.
} catch (IOException e) {
e.printStackTrace();
} finally {
//对应FileWriter , 一定要关闭流,或者flush才能真正的把数据写入到文件
//看源码就知道原因.
/*
private void writeBytes() throws IOException {
this.bb.flip();
int var1 = this.bb.limit();
int var2 = this.bb.position();
assert var2 <= var1;
int var3 = var2 <= var1 ? var1 - var2 : 0;
if (var3 > 0) {
if (this.ch != null) {
assert this.ch.write(this.bb) == var3 : var3;
} else {
this.out.write(this.bb.array(), this.bb.arrayOffset() + var2, var3);
}
}
this.bb.clear();
}
*/
try {
//fileWriter.flush();
//关闭文件流,等价 flush() + 关闭
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("程序结束...");
}
}
节点流和处理流
基本介绍
1.节点流可以从一个特定的数据源读写数据,如FileReader、FileWriter [源码]
2.处理流(也叫包装流)是“连接”在已存在的流(节点流或处理流)之上,为程序提供更为强大的读写功能,如BufferedReader、BufferedWriter [源码]
节点流和处理流的区别
节点流和处理流的区别和联系
1.节点流是底层流/低级流,直接跟数据源相接
2.处理流(包装流)包装节点流,既可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入输出。[源码理解]
3.处理流(也叫包装流)对节点流进行包装,使用了修饰器设计模式,不会直接与数据源相连[模拟修饰器设计模式]
处理流的功能主要体现在以下两个方面:
1.性能的提高:主要以增加缓冲的方式来提高输入输出的效率
2.操作的便捷: 处理流可能提供了一系列便捷的方法来一次输入输出大批量的数据,使用更加灵活方便
代码演示:
package com;
public class Test_ {
public static void main(String[] args) {
BufferedReader_ bufferedReader_ = new BufferedReader_(new FileReader_());
bufferedReader_.readFiles(10);
//bufferedReader_.readFile();
//Serializable
//Externalizable
//ObjectInputStream
//ObjectOutputStream
//这次希望通过 BufferedReader_ 多次读取字符串
BufferedReader_ bufferedReader_2 = new BufferedReader_(new StringReader_());
bufferedReader_2.readStrings(5);
}
}
package com;
/**
* 节点流
*/
public class StringReader_ extends Reader_{
public void readString() {
System.out.println("读取字符串");
}
}
package com;
/**
* 节点流
*/
public class FileReader_ extends Reader_{
public void readFile(){
System.out.println("读取文件");
}
}
package com;
/**
* 做成处理流/包装流
*/
public class BufferedReader_ extends Reader_{
private Reader_ reader_; //属性是 Reader_类型
//接收Reader_ 子类对象
public BufferedReader_(Reader_ reader_) {
this.reader_ = reader_;
}
public void readFile() { //封装一层
reader_.readFile();
}
//让方法更加灵活, 多次读取文件, 或者加缓冲byte[] ....
public void readFiles(int num) {
for(int i = 0; i < num; i++) {
reader_.readFile();
}
}
//扩展 readString, 批量处理字符串数据
public void readStrings(int num) {
for(int i = 0; i <num; i++) {
reader_.readString();
}
}
}
package com;
public abstract class Reader_ {
public void readString() {
}
public void readFile() {
}
}
处理流-BufferedReader和BufferedWriter
BufferedReader类基本介绍
BufferedReader类用来读取字符流,通过将读取的字符缓存到内存中,减少了I/O操作的次数,提高了读取数据的效率。BufferedReader类中提供了read()、readLine()等方法用来读取字符流,同时也提供了mark()、reset()等方法来支持流的标记和重置。
BufferedReader 和 BufferedWriter 属于字符流是按照字符来读取数据的
关闭时处理流,只需要关闭外层流即可[后面看源码]
案例1
代码演示:
这里要注意的是bufferedReader.readLine())该方法,当把文件读取完毕的时候,会返回null
package com.reader_;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
/**
* 演示bufferedReader 使用
*/
public class BufferedReader_ {
public static void main(String[] args) throws Exception {
String filePath = "e:\\asd.java";
//创建bufferedReader
BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
//读取
String line; //按行读取, 效率高
//说明
//1. bufferedReader.readLine() 是按行读取文件
//2. 当返回null 时,表示文件读取完毕
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
//关闭流, 这里注意,只需要关闭 BufferedReader ,因为底层会自动的去关闭 节点流
//FileReader。
/*
public void close() throws IOException {
synchronized (lock) {
if (in == null)
return;
try {
in.close();//in 就是我们传入的 new FileReader(filePath), 关闭了.
} finally {
in = null;
cb = null;
}
}
}
*/
bufferedReader.close();
}
}
案例2
BufferedWriter类基本介绍
BufferedWriter类用来写入字符流,通过将写入的字符缓存到内存中,减少了I/O操作的次数,提高了写入数据的效率。BufferedWriter类中提供了write()、newLine()等方法用来写入字符流,同时也提供了flush()方法来将缓冲区的内容写入到文件中。
代码演示:
说明:关闭外层流即可 , 传入的 new FileWriter(filePath) ,会在底层关闭
package com.writer_;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
/**
* 演示BufferedWriter的使用
*/
public class BufferedWriter_ {
public static void main(String[] args) throws IOException {
String filePath = "e:\\ok.txt";
//创建BufferedWriter
//说明:
//1. new FileWriter(filePath, true) 表示以追加的方式写入
//2. new FileWriter(filePath) , 表示以覆盖的方式写入
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath));
bufferedWriter.write("hello, 你好!");
bufferedWriter.newLine();//插入一个和系统相关的换行
bufferedWriter.write("hello, 你好!");
bufferedWriter.newLine();
bufferedWriter.write("hello, 你好!");
bufferedWriter.newLine();
//说明:关闭外层流即可 , 传入的 new FileWriter(filePath) ,会在底层关闭
bufferedWriter.close();
}
}
案例3
代码演示:
和之前的拷贝文件一样,指定要读取的文件的路径,在指定一个,拷贝到哪里的路径,然后使用while循环读取,一边读取一边写入,当bufferedReader.readLine())等于null时,说明文件已经读取完毕,同时也写入完毕,最后关闭对应的流即可
package com.writer_;
import com.BufferedReader_;
import java.io.*;
public class BufferedCopy_ {
public static void main(String[] args) {
//说明
//1. BufferedReader 和 BufferedWriter 是按照字符操作
//2. 不要去操作 二进制文件[声音,视频,doc, pdf ], 可能造成文件损坏
//应该使用 BufferedInputStream 和 BufferedOutputStream因为他们是按字节操作
String scr = "e:\\asd.java";
String dest = "e:a2.java";
BufferedWriter bufferedWriter = null;
BufferedReader bufferedReader = null;
String line;
try {
bufferedReader = new BufferedReader(new FileReader(scr));
bufferedWriter = new BufferedWriter((new FileWriter(dest)));
//说明: readLine 读取一行内容,但是没有换行
while ((line = bufferedReader.readLine()) != null) {
//每读取一行,就写入
bufferedWriter.write(line);
//插入一个换行
bufferedWriter.newLine();
}
System.out.println("拷贝成功");
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
//关闭流
try {
if (bufferedWriter != null) {
bufferedWriter.close();
}
if (bufferedReader != null) {
bufferedReader.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}