一、java.io.File类
1、File类:文件和目录路径名的抽象表示形式。
(1)无论是表示文件还是目录(文件夹)都是用File类的对象
(2)无论是表示文件还是目录,都是通过指定“路径名”来表示
例如:表示D盘的D:\to_student\尚硅谷_210728Java_柴林燕_JavaSE\ppt\尚硅谷_柴林燕_JDK8的安装及配置.pdf文件
表示D盘的D:\to_student\尚硅谷_210728Java_柴林燕_JavaSE\ppt文件夹
2、File类的API
(1)获取文件或目录的一些基本信息:文件名、大小、时间等属性
其中有一个方法需要说明:
long length():它只能获取到文件的大小,不能直接获取文件夹的大小。如果文件不存在,返回0L。
思考?如何获取文件夹的大小?
(2)获取文件或目录的一些路径信息
相对路径:除了绝对路径以外都是相对路径
绝对路径:从根目录开始指定的路径是绝对路径
windows操作系统是从盘符开始 D:\to_student\尚硅谷_210728Java_柴林燕_JavaSE\ppt\尚硅谷_柴林燕_JDK8的安装及配置.pdf
linux操作系统是从 / 开始
getPath()构造路径:new File对象时,构造器传的路径
getAbsolutePath() :
如果构造路径就是绝对路径,就和构造路径一样
如果构造路径就是相对路径,就用 当前项目或当前模块的路径 + 构造路径
getCanonicalPath():如果路径中有..等非规范的路径表示方式,就对它进行解析
(3)判断某个File对象是代表文件还是代表目录?
isFile():是否是文件 文件存在并且是个文件才会返回true
isDirectory():是否是目录 目录存在并且是个目录才会返回true
public class TestFile {
@Test
public void test09(){
File dir = new File("D:/1.txt"); //不存在
System.out.println("是否是文件:" + dir.isFile());//false
System.out.println("是否是目录:" + dir.isDirectory());//false
}
@Test
public void test08(){
File dir = new File("D:\\to_student\\尚硅谷_210728Java_柴林燕_JavaSE\\ppt");
System.out.println("是否是文件:" + dir.isFile());//false
System.out.println("是否是目录:" + dir.isDirectory());//true
}
@Test
public void test07() throws IOException {
File file = new File("D:\\to_student\\尚硅谷_210728Java_柴林燕_JavaSE\\ppt\\尚硅谷_柴林燕_JDK8的安装及配置.pdf");
System.out.println("是否是文件:" + file.isFile());//true
System.out.println("是否是目录:" + file.isDirectory());//false
}
public static void main(String[] args) throws IOException{
//main相对于当前IDEA的project的根目录
File file = new File("..\\..\\尚硅谷_柴林燕_JDK8的安装及配置.pdf");//相对路径 new对象不会自动创建对应的文件,只是在JVM的堆中创建了一个对象
System.out.println("构造路径(普通路径):" + file.getPath());
System.out.println("绝对路径:" + file.getAbsolutePath()); //(构造路径是相对路径的话)绝对路径 = 当前项目或当前模块的路径 + 构造路径
System.out.println("规范路径:" + file.getCanonicalPath());
System.out.println("是否存在:" + file.exists());//false
/*
构造路径(普通路径):..\..\尚硅谷_柴林燕_JDK8的安装及配置.pdf
绝对路径:D:\atguigu\javaee\JavaSE20210728\code\..\..\尚硅谷_柴林燕_JDK8的安装及配置.pdf
规范路径:D:\atguigu\javaee\尚硅谷_柴林燕_JDK8的安装及配置.pdf
是否存在:false
*/
}
@Test
public void test06() throws IOException {
//JUnit相对于当前IDEA的模块的根目录
File file = new File("..\\..\\尚硅谷_柴林燕_JDK8的安装及配置.pdf");//相对路径 new对象不会自动创建对应的文件,只是在JVM的堆中创建了一个对象
System.out.println("构造路径(普通路径):" + file.getPath());
System.out.println("绝对路径:" + file.getAbsolutePath());//(构造路径是相对路径的话) 绝对路径 = 当前项目或当前模块的路径 + 构造路径
System.out.println("规范路径:" + file.getCanonicalPath());
System.out.println("是否存在:" + file.exists());//false
System.out.println("文件大小:" + file.length());
/*
构造路径(普通路径):..\..\尚硅谷_柴林燕_JDK8的安装及配置.pdf
绝对路径:D:\atguigu\javaee\JavaSE20210728\code\day0828_teacher_code\..\..\尚硅谷_柴林燕_JDK8的安装及配置.pdf
规范路径:D:\atguigu\javaee\JavaSE20210728\尚硅谷_柴林燕_JDK8的安装及配置.pdf
*/
}
@Test
public void test05() throws IOException {
File file = new File("D:\\to_student\\尚硅谷_210728Java_柴林燕_JavaSE\\ppt\\尚硅谷_柴林燕_JDK8的安装及配置.pdf");
System.out.println("构造路径(普通路径):" + file.getPath());
System.out.println("绝对路径:" + file.getAbsolutePath());
System.out.println("规范路径:" + file.getCanonicalPath());
/*
路径:D:\to_student\尚硅谷_210728Java_柴林燕_JavaSE\ppt\尚硅谷_柴林燕_JDK8的安装及配置.pdf
绝对路径:D:\to_student\尚硅谷_210728Java_柴林燕_JavaSE\ppt\尚硅谷_柴林燕_JDK8的安装及配置.pdf
规范路径:D:\to_student\尚硅谷_210728Java_柴林燕_JavaSE\ppt\尚硅谷_柴林燕_JDK8的安装及配置.pdf
*/
}
@Test
public void test04(){
File dir = new File("D:\\to_student\\尚硅谷_210728Java_柴林燕_JavaSE\\ppt");
System.out.println("文件夹的大小:" + dir.length());//8192 不正确
}
@Test
public void test03(){
//演示获取文件的一些基本信息
File file = new File("D:\\to_student\\尚硅谷_210728Java_柴林燕_JavaSE\\ppt\\尚硅谷_柴林燕_JDK8的安装及配置.pdf");
System.out.println("文件名:" + file.getName());
System.out.println("文件大小:" + file.length() +"字节");//数组.length属性,字符串.length()方法,文件对象.length()方法
System.out.println("最后修改时间:" + file.lastModified() +"毫秒"); //距离1970年1月1日 0:0:0 0毫秒的一个时间差
long time = file.lastModified();
Date date = new Date(time);
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
System.out.println("最后修改时间:" + sf.format(date));
System.out.println("文件是否可读:" + file.canRead());
System.out.println("文件是否可写:" + file.canWrite());
System.out.println("文件是否存在:" + file.exists());
//...
}
@Test
public void test02(){
//表示D盘的D:\to_student\尚硅谷_210728Java_柴林燕_JavaSE\ppt文件夹
File dir = new File("D:\\to_student\\尚硅谷_210728Java_柴林燕_JavaSE\\ppt");//dir这个对象是代表ppt这个文件夹
}
@Test
public void test01(){
//表示D盘的D:\to_student\尚硅谷_210728Java_柴林燕_JavaSE\ppt\尚硅谷_柴林燕_JDK8的安装及配置.pdf文件
File file1 = new File("D:\\to_student\\尚硅谷_210728Java_柴林燕_JavaSE\\ppt\\尚硅谷_柴林燕_JDK8的安装及配置.pdf");
//上面的\\是windows平台支持的方式
File file2 = new File("D:/to_student/尚硅谷_210728Java_柴林燕_JavaSE/ppt/尚硅谷_柴林燕_JDK8的安装及配置.pdf");
//下面这个/是所有平台都支持的方式
}
}
3、File类的API:关于文件或目录的操作
(1)boolean createNewFile() :创建一个新文件
(2)boolean mkdir():创建最末尾的一级目录
boolean mkdirs() :创建多级目录
(3)boolean delete() :删除
delete()可以删除文件
delete()可以删除空目录
思考?如何删除非空目录?
(4)boolean renameTo(File dest):重命名文件或目录
public class TestFileOperate {
@Test
public void test7() throws IOException {
File dir = new File("d:/java");
File dest = new File("d:/javase");
dir.renameTo(dest);
}
@Test
public void test6() throws IOException {
File dir = new File("d:/java");
dir.delete();
}
@Test
public void test5() throws IOException {
File dir = new File("d:/temp");
dir.delete();
}
@Test
public void test4() throws IOException {
File file = new File("d:/1.txt");
file.delete();
}
@Test
public void test3() throws IOException {
File dir = new File("d:/java/io/chai");
// dir.mkdir();
dir.mkdirs();
}
@Test
public void test2() throws IOException {
File dir = new File("d:/temp");
dir.mkdir();
}
@Test
public void test() throws IOException {
File file = new File("d:/1.txt");
file.createNewFile();
}
}
4、File的API:关于文件夹的下一级的获取
(1)String[] list():返回值类型是String[]
(2)File[] listFiles() :返回值类型是File[]
思考:如何获取下一级,如果下一级还是目录,继续获取它的下一级。
思考:统计文件夹大小
思考:删除非空目录
public class TestListDir {
//思考:删除非空目录
@Test
public void test04(){
File dir = new File("D:\\to_student - 副本");
forceDir(dir);
}
public void forceDir(File dir){
if(dir.isDirectory()){//如果是目录,先删除目录的下一级
//(1)先获取它的下一级
File[] files = dir.listFiles();
//(2)遍历挨个删除下一级
for (File sub : files) {//sub是dir的下一级
forceDir(sub);
}
}
//经过上面的if,如果dir是文件,上面的if条件不成立,直接删除文件
//经过上面的if,如果dir是目录,上面的if可以把dir的下一级删除,然后删除dir这个空目录
dir.delete();
}
//思考:统计文件夹大小
@Test
public void test03(){
File dir = new File("D:\\to_student");
System.out.println(size(dir) +"字节");//5847224217字节
}
public long size(File dir){
if(dir.isFile()){
return dir.length();
}else if(dir.isDirectory()){
long sum = 0;
//累加dir的所有下级的大小
//(1)获取dir的下一级
File[] files = dir.listFiles();
//(2)遍历并累加每一个下一级的大小
for (File sub : files) {//sub是dir的下一级
// sum += sub.length();//因为sub可能是一个文件,也可能是文件夹,如果文件夹的话,这样是错误
sum += size(sub);
}
return sum;
}else{
return 0L;
}
}
@Test
public void test02(){
File dir = new File("D:\\to_student");
listAllSub(dir);
}
//思考:如何获取下一级,如果下一级还是目录,继续获取它的下一级。
public void listAllSub(File dir){
if(dir.isDirectory()) {
File[] files = dir.listFiles();
for (File sub : files) {//sub是dir的下一级, sub可能是一个文件,也可能是一个文件夹
listAllSub(sub);//递归调用
}
}
System.out.println(dir);
}
@Test
public void test01(){
File dir = new File("D:\\to_student");
String[] strings = dir.list();
for (int i = 0; i < strings.length; i++) {
System.out.println(strings[i]);
}
}
}
5、File类中关于文件或目录的过滤问题:
File[] listFiles(FileFilter filter)
FileFilter接口:
boolean accept(File pathname) 抽象方法,重写时,告诉File类的listFiles方法,什么样文件或目录需要留下来
public class TestFileFilter {
@Test
public void test02(){
File dir = new File("D:\\to_student\\尚硅谷_210728Java_柴林燕_JavaSE\\预装软件");
ArrayList<File> allExeSubFiles = getAllExeSubFiles(dir);
for (File allExeSubFile : allExeSubFiles) {
System.out.println(allExeSubFile);
}
}
public ArrayList<File> getAllExeSubFiles(File dir){
ArrayList<File> list = new ArrayList<File>();
if(dir.isFile()){
String name = dir.getName();
if(name.endsWith(".exe")){
list.add(dir);
}
}else if(dir.isDirectory()){
//需求:列出它的下一级,只想看.exe的文件
File[] exeSubFiles = dir.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) { //这个方法是在File类的listFiles方法体中调用
//File pathname是在listFiles方法体中获取的dir的下一级(可能是一个文件,可能是一个目录)
//pathname.getName()获取下一级的文件或目录的名字
//文件或目录名 以 ".exe"结尾
return pathname.getName().endsWith(".exe") || pathname.isDirectory();
}
});
for (File exeSubFile : exeSubFiles) {//exeSubFile可能是一个.exe文件,或者是文件夹
ArrayList<File> allExeSubFiles = getAllExeSubFiles(exeSubFile);
list.addAll(allExeSubFiles);
}
}
return list;
}
@Test
public void test01(){
File dir = new File("D:\\to_student\\尚硅谷_210728Java_柴林燕_JavaSE\\预装软件");
//需求:列出它的下一级,只想看.exe的文件
File[] exeSubFiles = dir.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) { //这个方法是在File类的listFiles方法体中调用
//File pathname是在listFiles方法体中获取的dir的下一级(可能是一个文件,可能是一个目录)
//pathname.getName()获取下一级的文件或目录的名字
//文件或目录名 以 ".exe"结尾
return pathname.getName().endsWith(".exe");
}
});
for (File exeSubFile : exeSubFiles) {
System.out.println(exeSubFile);
}
}
}
二、IO
1、IO两个字母代表的意思:
I: input输入
O:output输出
数据的读和写。
2、IO的分类
(1)根据方向分:
A:输入流
B:输出流
(2)根据操作数据单位分:
A:字节流:以字节为最小单位
B:字符流:以字符为最小单位
(3)根据IO流的角色划分
A:节点流:和数据节点相连接,数据节点有:文件、网络、内存等
B:处理流:在节点流的基础上增加辅助功能的,或者增加装饰功能的,又称为包装流、装饰流
辅助功能:缓存、编码和解码、序列化和反序列化等
3、IO流有四个基本父类,抽象基类:
InputStream:字节输入流系列的超级父类
OutputStream:字节输出流系列的超级父类
Reader:字符输入流系列的超级父类
Writer:字符输出流系列的超级父类
4、其他类型
(1)文件IO流
FileInputStream:文件字节输入流
FileOutputStream:文件字节输出流
FileReader:文件字符输入流
FileWriter:文件字符输出流
FileInputStream和FileOutputStream适用于读和写任意类型的文件,包括文本文件,视频,音频,图片等。
FileReader和FileWriter只能用于读和写纯文本文件,而且文件内容的编码(字符集)与当前平台要一致。
(2)缓冲IO流
BufferedInputStream:缓冲字节输入流或字节缓冲输入流,它只能直接给InputStream系列的IO流增加缓冲功能
BufferedOutputStream:字节缓冲输出流,它只能直接给OutputStream系列的IO流增加缓冲功能
BufferedReader:字符缓冲输入流,它只能直接给Reader系列的IO流增加缓冲功能
BufferedWriter:字符缓冲输出流,它只能直接给Writer系列的IO流增加缓冲功能
(3)转换流
InputStreamReader:把字节流转换为字符流,把字节流中的数据转换为字符流中的数据,
把字节-->字符:“解码”
OutputStreamWriter:从IO流感觉也是把字节流转为字符流,但是从数据来看,把字符流的数据转为字节流中的数据
把字符-->字节:“编码”
(4)数据流
DataInputStream:用于Java的各种基本数据类型的数据和字符串的读取
DataOutputStream:用于输出Java的各种基本数据类型的数据和字符串
(5)对象流
ObjectInputStream:用于Java对象的读取
ObjectOutputStream:用于输出Java对象
(6)打印流
PrintStream:字节打印流
代表:System.out
PrintWriter:字符打印流
代表:web阶段从服务器端给客户端反馈消息时用的打印流
request(请求):客户端给服务器端发“请求”
response(相应):服务器端给客户端发送“响应”
<1>=====================================================================
FileInputStream:用于读文件,以“字节”方式读取文件内容
使用FileInputStream的步骤:
第一步:要告诉FileInputStream从哪个文件读取内容
创建FileInputStream的对象,通过构造器的参数指定要读取的文件
FileInputStream fis = new FileInputStream("d:/1.txt");
第二步:选择读取的方法,这些方法适用于所有的InputStream系列的IO流
int read():读取一个字节的内容,返回的是一个字节的内容的int值
如果流中没有数据了,返回-1
int read(byte[] data):一次读取多个字节,返回的是读取的字节总数。
如果流中没有数据了,返回-1。最多一次读取data.length个字节,
读取的数据依次放到data的元素中,从[0]元素开始放
int read(byte[] data, int off, int len) : 一次读取多个字节,返回的是读取的字节总数。
如果流中没有数据了,返回-1。最多一次读取len个字节,
读取的数据依次放到data的元素中,从[off]元素开始放
第三步:关闭IO流
调用IO流对象的close()
关闭IO流的目的:释放对应的内存等资源,包括JVM中和JVM以外的OS系统中的内存
public class TestFileInputStream {
@Test
public void test06() throws IOException {
//需求:读取d:/2.txt文件
FileInputStream fis = new FileInputStream("d:/2.txt");//文件内容比较多,有很多字符
byte[] data = new byte[10];
int len;
/*
第一个事情,从fis流中读取了多个字节,放到data数组中
第二个事情,把本次读取的字节数赋值给len变量
第三个事情:判断len是否是-1,如果是-1说明fis中已经没有数据了
*/
while((len=fis.read(data)) != -1){ //while的条件中做了3个事情
// System.out.println(Arrays.toString(data));
System.out.println(new String(data,0, len));
}
fis.close();
}
@Test
public void test05() throws IOException {
//需求:读取d:/2.txt文件
FileInputStream fis = new FileInputStream("d:/2.txt");//文件内容比较多,有很多字符
//当文件内容超过10个字节时,那么一次最多只能读取10个字节
byte[] data = new byte[10];
int len = 0;
//第一次读取
len = fis.read(data);
System.out.println("len = " + len);
System.out.println(Arrays.toString(data));
System.out.println("-------------------");
//第二次读取
len = fis.read(data);//这一次读取的2个字节,放到了data数组的[0][1]元素中,剩下的元素是上次读取的内容
System.out.println("len = " + len);//2
System.out.println(Arrays.toString(data));
System.out.println("-------------------");
//第三次读取
len = fis.read(data);
System.out.println("len = " + len);//-1 流中没有数据了
System.out.println(Arrays.toString(data));//本次data中的元素都是之前读取的
fis.close();
}
@Test
public void test04() throws IOException {
//需求:读取d:/1.txt文件
FileInputStream fis = new FileInputStream("d:/1.txt");//文件内容是abcd
System.out.println(fis.read());//97 调用一次read()方法读取一个字节
System.out.println(fis.read());//98
System.out.println(fis.read());//99
System.out.println(fis.read());//100
System.out.println(fis.read());//-1
fis.close();
}
@Test
public void test03() throws IOException {
//需求:读取d:/2.txt文件
FileInputStream fis = new FileInputStream("d:/2.txt");//文件内容比较多,有很多字符
//当文件内容超过10个字节时,那么一次最多只能读取10个字节
byte[] data = new byte[10];
int len = fis.read(data);
System.out.println("len = " + len);
System.out.println(Arrays.toString(data));
fis.close();
}
@Test
public void test02() throws IOException {
//需求:读取d:/1.txt文件
FileInputStream fis = new FileInputStream("d:/1.txt");//文件内容是abcd
byte[] data = new byte[10];
int len = fis.read(data);
System.out.println("len = " + len);
System.out.println(Arrays.toString(data));
fis.close();
}
@Test
public void test01() throws IOException {
//需求:读取d:/1.txt文件
FileInputStream fis = new FileInputStream("d:/1.txt");//文件内容是abcd
int data = fis.read();
System.out.println(data);//97
fis.close();
}
}
FileOutputStream:用于输出数据到文件,以“字节“方式
步骤:
第一步:告诉FileOutputStream把数据输出到哪个文件
创建FileOutputStream的对象时,通过构造器的参数告诉文件路径名
FileOutputStream fos = new FileOutputStream("d:/1.txt");
第二步:调用输出内容的方法
void write(int c):一次输出一个字节
void write(byte[] cbuf):输出整个字节数组
void write(byte[] cbuf, int off, int len):输出字节输出的一部分
第三步:关闭
注意:
(1)默认情况下,FileOutputStream以覆盖的方式输出内容到文件,即原来文件的内容会被覆盖掉。
可以使用“追加”模式输出内容到文件。
(2)FileWriter和FileOutputStream输出内容到文件,如果文件不存在,会自动创建这个文件
FileInputStream和FileReader如果要读取的文件不存在,报错FileNotFoundException
public class TestFileOutputStream {
@Test
public void test01() throws IOException {
FileOutputStream fos = new FileOutputStream("d:/1.txt",true);
fos.write("helle".getBytes());//字符串变为字节数组的方法 getBytes()
fos.close();
}
}
<2>======================================================================
FileReader:用于读文件,以“字符”方式读取文件内容
使用FileReader的步骤:
第一步:要告诉FileReader从哪个文件读取内容
创建FileReader的对象,通过构造器的参数指定要读取的文件
FileReader fr = new FileReader("d:/1.txt");
第二步:选择读取的方法,这些方法适用于所有的Reader系列的IO流
int read():读取一个字符的内容,返回的是一个字符的内容的int值
如果流中没有数据了,返回-1
int read(char[] data):一次读取多个字符,返回的是读取的字符总数。
如果流中没有数据了,返回-1。最多一次读取data.length个字符,
读取的数据依次放到data的元素中,从[0]元素开始放
int read(char[] data, int off, int len) : 一次读取多个字符,返回的是读取的字符总数。
如果流中没有数据了,返回-1。最多一次读取len个字符,
读取的数据依次放到data的元素中,从[off]元素开始放
第三步:关闭IO流
调用IO流对象的close()
关闭IO流的目的:释放对应的内存等资源,包括JVM中和JVM以外的OS系统中的内存
public class TestFileReader {
@Test
public void test06() throws IOException {
//需求:读取d:/2.txt文件
FileReader fr = new FileReader("d:/2.txt");//文件内容比较多,有很多字符
char[] data = new char[10];
int len;
/*
第一个事情,从fr流中读取了多个字节,放到data数组中
第二个事情,把本次读取的字符数赋值给len变量
第三个事情:判断len是否是-1,如果是-1说明fis中已经没有数据了
*/
while((len=fr.read(data)) != -1){ //while的条件中做了3个事情
// System.out.println(Arrays.toString(data));
System.out.println(new String(data,0, len));
}
fr.close();
}
}
FileWriter:用于输出数据到文件,以“字符”方式
步骤:
第一步:告诉FileWriter把数据输出到哪个文件
创建FileWriter的对象时,通过构造器的参数告诉文件路径名
FileWriter fw = new FileWriter("d:/1.txt");
第二步:调用输出内容的方法
void write(int c):一次输出一个字符
void write(char[] cbuf):输出整个字符数组
void write(char[] cbuf, int off, int len):输出字符输出的一部分
void write(String str) :输出字符串
void write(String str, int off, int len) :输出字符串的一部分
第三步:关闭
注意:
(1)默认情况下,FileWriter以覆盖的方式输出内容到文件,即原来文件的内容会被覆盖掉。
可以使用“追加”模式输出内容到文件。
(2)FileWriter和FileOutputStream输出内容到文件,如果文件不存在,会自动创建这个文件
FileInputStream和FileReader如果要读取的文件不存在,报错FileNotFoundException
public class TestFileWriter {
@Test
public void test04() throws IOException {
FileWriter fw = new FileWriter("d:/3.txt");
fw.write("hello");
fw.close();
}
@Test
public void test03() throws IOException {
FileWriter fw = new FileWriter("d:/1.txt",true);//true代表追加
fw.write("java");
fw.close();
}
@Test
public void test02() throws IOException {
FileWriter fw = new FileWriter("d:/1.txt");
fw.write("hello");
fw.close();
}
@Test
public void test01() throws IOException {
FileWriter fw = new FileWriter("d:/1.txt");
fw.write('a');
fw.write('尚');
fw.write(99);//字符的编码
fw.close();
}
}
复制
public class FileTools {
public static void main(String[] args) throws IOException {
copy("D:\\atguigu\\javaee\\JavaSE20210728\\video\\day0827_21video\\day0827_01多线程的相关概念.avi","d:/1.avi");
}
/**
* 把srcFile的文件复制一份,存在destFile文件中,要求适用于复制任何类型的文件
* @param srcFile
* @param destFile
*/
public static void copy(String srcFile, String destFile) throws IOException {
//文件的复制过程:从一个文件“读”数据,“写”到另一个文件中
//从srcFile文件读取,写到destFile文件
//(1)先创建两个IO流,因为要求适用于复制任何类型的文件,所以选择FileInputStream和FileOutputStream
FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(destFile);
//(2)一边从fis流中读,一边写到fos中
byte[] data = new byte[1024];
int len;
while((len = fis.read(data)) != -1){
// fos.write(data);//复制后可能会多出数据来
fos.write(data,0,len);//本次读几个,写几个字节,本次读了len个字节
}
//(3)关闭
fos.close();
fis.close();
}
/**
* 把srcFile的文件复制一份,存在destFile文件中,要求适用于复制任何类型的文件
* @param srcFile
* @param destFile
*/
public static void copyBuffer(String srcFile, String destFile) throws IOException {
//文件的复制过程:从一个文件“读”数据,“写”到另一个文件中
//从srcFile文件读取,写到destFile文件
//(1)先创建两个IO流,因为要求适用于复制任何类型的文件,所以选择FileInputStream和FileOutputStream
FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(destFile);
//增加缓冲流
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream bos = new BufferedOutputStream(fos);
//(2)一边从bis流中读,一边写到bos中
byte[] data = new byte[1024];
int len;
while((len = bis.read(data)) != -1){
bos.write(data,0,len);//本次读几个,写几个字节,本次读了len个字节
}
//(3)关闭
bis.close();
bos.close();
fos.close();
fis.close();
}
}
<3>======================================================================
缓冲流:Buffered开头的四个IO流
BufferedInputStream:缓冲字节输入流或字节缓冲输入流,它只能直接给InputStream系列的IO流增加缓冲功能
BufferedOutputStream:字节缓冲输出流,它只能直接给OutputStream系列的IO流增加缓冲功能
BufferedReader:字符缓冲输入流,它只能直接给Reader系列的IO流增加缓冲功能
BufferedWriter:字符缓冲输出流,它只能直接给Writer系列的IO流增加缓冲功能
说明:
(1)BufferedReader比FileReader多了一次读取一行的功能
(2)提高效率(缓冲区的大小,默认是8192个字节/字符)
为什么是更快?
如果不使用缓冲流,每次从原文件读取 len 个字节,然后又写len 个字节到目标文件中。
如果使用缓冲流,先从源文件缓冲一部分数据到缓冲区(内存中),然后每次从缓冲区读取len个字节,然后写len个字节到缓冲区(内存中),当缓冲区满,或者我们调用flush或close方法时,会把数据写到目标文件中。
提高效率的秘籍在于,减少了与文件的交互次数。
比喻:桶装水需要送水公司送桶装水过来。
如果不使用缓冲流,相当于每次送水工从 水站 扛一桶水到尚硅谷,然后回去扛下一桶。
如果使用缓冲流,相当于每次送水工,先在水站,用一个“车”装了很多桶,一车拉到尚硅谷,在尚硅谷的楼下,一桶一桶扛到楼上,再回去拉下一车。
不用缓冲区,是否也可以很快呢?
如果你力气够大,一次扛20桶。在Java中,如果一次把byte[]数组,定义的够大,也很快。
(3)缓存输出流,如果没有及时关闭,那么最后一次在缓冲区的数据,有可能在缓冲区中留存。
如果需要把数据及时写出,可以调用flush方法。
public class TestBuffered {
@Test
public void test05() throws IOException {
FileWriter fw = new FileWriter("d:/1.txt");
BufferedWriter bw = new BufferedWriter(fw);
bw.write("hello");
bw.flush();
//.....
bw.close();
}
@Test
public void test04() throws IOException {
//不使用缓冲流复制文件
long start = System.currentTimeMillis();
FileTools.copyBuffer("D:\\software\\IntelliJ IDEA\\ideaIC-2021.1.2.exe", "d:/idea2.exe");
long end = System.currentTimeMillis();
System.out.println("用时:" + (end-start));//用时:1579
}
@Test
public void test03() throws IOException {
//不使用缓冲流复制文件
long start = System.currentTimeMillis();
FileTools.copy("D:\\software\\IntelliJ IDEA\\ideaIC-2021.1.2.exe", "d:/idea1.exe");
long end = System.currentTimeMillis();
System.out.println("用时:" + (end-start));//用时:7321
}
@Test
public void test02() throws IOException {
//演示用BufferedReader辅助FileReader来读取纯文本文件
FileReader fr = new FileReader("d:/1.txt");
BufferedReader br = new BufferedReader(fr);//BufferedReader在FileReader增加缓冲功能
String line;
while((line = br.readLine()) != null){
System.out.println(line);
}
br.close();
fr.close();
}
@Test
public void test01() throws IOException {
//演示用BufferedReader辅助FileReader来读取纯文本文件
FileReader fr = new FileReader("d:/1.txt");
BufferedReader br = new BufferedReader(fr);//BufferedReader在FileReader增加缓冲功能
System.out.println(br.read());//一次读取一个字符
char[] data = new char[10];
int len = br.read(data);
System.out.println("len = " + len);
System.out.println(Arrays.toString(data));
br.close();
fr.close();
}
}
<4>======================================================================
转换流:在字符和字节流之间做转换用的
InputStreamReader: 把字节流转为字符流类型
把字节流中的字节数据按照指定的编码,如果没有指定编码就默认用平台编码,进行解码,转为字符流的字符。
OutputStreamWriter: 把字节流转为字符流类型
把字符流中的字符数据按照指定的编码,如果没有指定编码就默认用平台编码,进行编码,转为字节流的字节。
public class TestTransfer {
@Test
public void test07() throws IOException {
//输出一句话到d:/1.txt文件中,这个文件是GBK
FileOutputStream fos = new FileOutputStream("d:/1.txt");//字节流
OutputStreamWriter osw = new OutputStreamWriter(fos,"GBK");//字符流
//数据的流向: (1)先把数据write到 osw流(字符流)
// (2)从osw字符流中,把数据用"GBK"编码进行处理,编码为字节流的数据 写到 fos字节流中
// (3)从fos字节流中把数据写到 "d:/1.txt"
osw.write("大家现在努力是为了明天挣钱");
osw.close();
fos.close();
}
@Test
public void test06() throws IOException {
//输出一句话到d:/1.txt文件中,这个文件是GBK
FileOutputStream fos = new FileOutputStream("d:/1.txt");
fos.write("大家现在努力是为了明天挣钱".getBytes("GBK"));
//String类 byte[] getBytes(String charsetName) 编码
fos.close();
}
@Test
public void test05() throws IOException {
//输出一句话到d:/1.txt文件中,这个文件是GBK
FileWriter fw = new FileWriter("d:/1.txt");
fw.write("大家现在努力是为了明天挣钱");
fw.close();
}
@Test
public void test04() throws IOException {
//读取一个“GBK”编码的纯文本文件
//当前平台(Java程序)是UTF-8
FileInputStream fis = new FileInputStream("d:/1.txt");//字节流
InputStreamReader isr = new InputStreamReader(fis, "GBK");//字符流
BufferedReader br = new BufferedReader(isr);//字符流
//数据的流向: "d:/1.txt" ==> fis(字节流) ==> 进行GBK解码==>isr(字符流)==>br==>程序中
String line;
while((line = br.readLine())!=null){
System.out.println(line);
}
br.close();
isr.close();
fis.close();
}
@Test
public void test03() throws IOException {
//读取一个“GBK”编码的纯文本文件
//当前平台(Java程序)是UTF-8
FileInputStream fis = new FileInputStream("d:/1.txt");
InputStreamReader isr = new InputStreamReader(fis, "GBK");
char[] data = new char[10];
int len = isr.read(data);
System.out.println("len = " + len);
System.out.println(new String(data,0, len));
isr.close();
fis.close();
}
@Test
public void test02() throws IOException {
//读取一个“GBK”编码的纯文本文件
//当前平台(Java程序)是UTF-8
FileInputStream fis = new FileInputStream("d:/1.txt");
byte[] data = new byte[5];
int len = fis.read(data);
System.out.println("len = " + len);
System.out.println(new String(data,0, len,"GBK"));
//String(byte[] bytes, int offset, int length, String charsetName) String类的解码方式
fis.close();
}
@Test
public void test01() throws IOException {
//读取一个“GBK”编码的纯文本文件
//当前平台(Java程序)是UTF-8
FileReader fr = new FileReader("d:/1.txt");
char[] data = new char[10];
int len = fr.read(data);
System.out.println("len = " + len);
System.out.println(new String(data,0, len));
fr.close();
}
}