Java-IO流

掌握常见流的读写操作、文件复制、对象序列化和反序列化的含义、理解序列化版本号的含义、自定义固定序列化版本号等操作。


什么是IO流

IO就是Input、Output,输入输出相对于内存而言,可以把内存作为参照物,从内存中出来就是输出、到内存中去就是输入。输入输出还有一种形象的说法就是读、写。

“流”实际上就是“数据移动”的形象说法。

IO流的分类

  • 根据流的方向分为输入流、输出流。相当于内存而言。
  • 根据流的数据单位分为字节流、字符流。
    1、字节流以字节为单位,一次读取一个字节,属于万能流,任何类型文件都可以读写,但是文件是汉字容易出现乱码,汉字是两个字节,字符流读的时候,会读到一般,如果直接写出,会出现乱码。
    2、字符流以字符为单位,一次读取一个字符。读写普通文档,不容易出现乱码,不适合读写图片、声音、视频等文件。
  • 根据流的功能分为节点流、处理流(包装流)。
    1、节点流直接对目标设备进行操作。
    2、处理流(包装流)一般是对节点进行包装,生成更大功能的流。

Java对流的支持

API中java.io下面的流很对,但分了四大类:字节输入流(InputStream)、字节输出流(OutputStream)、字符输入流(Reader)、字符输出流(Writer),这四类没有父类,并且都是抽象类,无法实例化。

在java中以Stream结尾的都是字节流、以Reader\Write r结尾的都是字符流。

所有的流都实现了:java.io.Closeable接口,都是可关闭的,都有close()方法。流毕竟是内存和硬盘之间的通道,用完之后一定要关闭,不然会耗费资源。

所有的输出流都实现了:ava.io.Flushable接口,都是可刷新的,都有flush()方法。刷新表示将通道中剩余未输出的数据强行输出完。作用就是清空通道。如果没有flush方法,可能导致文件数据丢失。

掌握常用流

java.io包下 需要掌握的流有16个,文件流四个、转换流(将字节流转换为字符流)两个、缓冲流四个、数据流两个、打印流两个、对象流两个。

文件流

文件流主要包括四个:文件字节输入流(FileInputStream)、文件字节输出流(FileOutputStream)、文件字符输入流(FileReader)、文件字符输出流。

FileInputStream

按照字节方式读取文件,事先创建一个txt文件,然后读取它,使用方法有read()、available()、skip()等方法

代码如下:
注意写代码时候的异常抛出情况、流的关闭

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

/*文件字节输入流,万能的,可以读任何类型的文件
字节方式读取文件,完成输入操作,完成读的操作(从硬盘-->内存)
一个字节一个字节读 效率低 内存与硬盘交互太频繁
 */
public class FileInputStreamTest01 {
    public static void main(String[] args) {
        //初始化为null
        FileInputStream fis =null;

        //创建文件字节输入流对象
        //文件路径: D:\test\temp.txt
        try {
            fis = new FileInputStream("D:\\test\\temp.txt");
            //开始读
           /* int b = 0;
            while((b=fis.read())!=-1){
                System.out.println(b);
            }
            读出来的是字节
            */
            
            //创建字节数组 往字节数组中读 然后通过构造方法将字节转换为字符串
            byte[] bytes = new byte[3];
            //读取的字节数
            int count =0;
            while((count = fis.read(bytes))!=-1){
                System.out.print(new String(bytes,0,count));
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                //如果流不为空 进行关闭
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

运行结果:
在这里插入图片描述
使用available方法获取文件字节数,然后创建字节数组,再在改字节中读,就可以不使用循环,但是不能用于读太大的文件

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

/*
提高程序执行效率 在内存中准备byte[] 数组 ,一次可以读取多个字节
int read(byte[] b )
 */
public abstract class FileInputStreamTest02 {
    public static void main(String[] args) {
        //初始化
        FileInputStream file = null;

        //创建文件字节输入流对象
        try {
            file = new FileInputStream("D:\\idea\\Practise\\src\\com\\lic\\File");
            //available方法 剩余多少字节没读
            System.out.println("总字节数:"+file.available());

            //创建字节数组 往该字节中读
            byte[] bytes1 = new byte[file.available()]; //不适合读太大的文件 因为byte数组不能太大
            file.read(bytes1);
            System.out.println(new String(bytes1));

            file.skip(3); //跳跃几个字节不读
            System.out.println(file.read());

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (file != null) {
                try {
                    file.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

FileOutputStream

FileOutputStream是文件字节输出流,通过write方法在磁盘上写出,可以一个字节一个字节写,也可以字节数组写。文件不存在会新建 存在文件会先将文件清空 再写进去。

注意输出流一定要有flush()方法刷新,将剩余未输出的数据强行输出完。作用就是清空通道。如果没有flush方法,可能导致文件数据丢失。

代码:

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputStreamTest01 {
    public static void main(String[] args) {
        FileOutputStream file = null;
        FileOutputStream file1 = null;
        try {
            //创建对象
            //文件不存在会新建 存在文件会先将文件清空 再写进去
            file = new FileOutputStream("test01");
            //在文件末尾写入,不会清空原文件
            file1 = new FileOutputStream("D:\\idea\\Practise\\src\\com\\lic\\File",true);

            //test01文件
            //写一个字节数组
            byte[] bytes = {97,98,99,100};
            file.write(bytes);
            //从下标0开始写 写2个字节
            file.write(bytes,0,2);

            //File文件
            // 写一个字符串
            String s = "哈哈哈哈哈哈哈";
            byte[] bytes1 = s.getBytes();
            file1.write(bytes1);

            //记得刷新
            file.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (file != null) {
                try {
                    file.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

写入的结果:

在这里插入图片描述

![在这里插入图片描述](https://img-blog.csdnimg.cn/2f91649d1e0e4921bf631d4fdfa0bcdb.png

文件拷贝

文件拷贝的原理就是一边读一边写,文件字节输入流和文件字节输出流联合起来完成文件的复制。

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class Copy {
    public static void main(String[] args) {
        //初始化
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            //创建对象
            fis = new FileInputStream("D:\\test\\picture\\IMG_1068(20210409-103539).JPG");
            
            fos = new FileOutputStream("D:\\test\\copy\\IMG_1068(20210409-103539).JPG");
            //边读边写
            int count = 0;
            byte[] bytes =  new byte[1024*1024]; //一次读取1MB 字节
            while((count = fis.read(bytes)) != -1){
                fos.write(bytes,0,count);
            }

            //文件字节输出流刷新
            fos.flush();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }//关闭流
        finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

完成文件拷贝
在这里插入图片描述

FileReader

照葫芦画瓢。

文件字符输入流,代码和文件字节输入流相似,不过FileInputStream是使用byte数组、 FileReader使用char数组,一次读取一个字符。

示例代码:

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

/*文件字符输入流
  只能读取普通文件
  方便 快捷
  使用char数组
 */
public class FileReaderTest01 {
    public static void main(String[] args) {
        //初始化
        FileReader fileReader = null;
        try {
            //创建文件字节输入流
            fileReader = new FileReader("D:\\idea\\Practise\\src\\com\\lic\\io\\FileReader");
            //开始读 char[]数组
            char[] chars = new char[16];
            int count = 0 ;
            while ((count = fileReader.read(chars)) != -1){
                System.out.print(new String(chars,0,count));
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileReader != null) {
                try {
                    fileReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

运行结果:
在这里插入图片描述

FileWriter

文件字符输出流,方便快捷,可以直接写字符串。

import java.io.FileWriter;
import java.io.IOException;

public class FileWriterTest {
    public static void main(String[] args) {
        FileWriter fileWriter = null;
        try {
            // //在文件末尾写入,不会清空原文件
            fileWriter = new FileWriter("fileTest",true);
            //字符数组
            char[] chars = {'中','秋','节','快','乐'};
            //开始读 char数组内容
            fileWriter.write(chars);
            fileWriter.write("\n");
            //读字符串内容
            fileWriter.write("教师节快乐");       
            //刷新
            fileWriter.flush();

        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (fileWriter != null) {
                try {
                    fileWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
文件拷贝

一边读一边写,char数组,数组下标是-127到128.

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class Copy02 {
    public static void main(String[] args) {
        FileReader fileReader = null;
        FileWriter fileWriter = null;
        try {
            fileReader = new FileReader("D:\\test\\temp.txt");

            fileWriter = new FileWriter("file");

            int count = 0;
            char[] chars =  new char[1024*512]; //一次读取1MB 字节
            while ((count = fileReader.read(chars)) != -1){
                fileWriter.write(chars,0,count);
            }

            //刷新
            fileWriter.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                fileReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                fileWriter.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

缓冲流

缓冲流主要是提高效率,减少物理读取次数。主要有 BufferedReader、BufferedWriter、BufferedInputStream、BufferedOutputStream。

前两个字符缓冲流、后两个字节缓冲流,方法都一样,示例字符缓冲流。

BufferedReader

BufferedReader提供的readLine()方法可以读取一行,采用BufferedReader对Reader进行装饰,BufferedReader先将数据读到缓存里,Java程序再次读取数据时,直接到缓存中读取,减少Java程序物理读取次数,提高性能。

代码:

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
//使用缓冲流 不需要自定义数组 自带缓冲
public class BufferedReaderTest {
    public static void main(String[] args) {
       BufferedReader bf = null;
        try {
            //当一个流的构造方法有另一个流 传进来的流叫节点流
            //外部负责包装的流 叫包装流/处理流
            bf = new BufferedReader(new FileReader("fileTest"));
            String s= null;
            //读一个文本行
            while((s = bf.readLine()) != null){
                System.out.println(s);
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bf == null) {
                try {
                    //关闭流 只需要关闭包装流 节点流会自动关闭
                    bf.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

BufferedWriter

//带有缓冲的字符输出流

import java.io.*;

//带有缓冲的字符输出流
public class BufferedWriterTest {
    public static void main(String[] args) {
        BufferedWriter bufferedWriter = null;
        try {
            bufferedWriter = new BufferedWriter(new FileWriter("BufferedWriter"));
            //bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("BufferedWriter")));

            bufferedWriter.write("hello");
            bufferedWriter.write("\n");
            bufferedWriter.write("world");
            bufferedWriter.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (bufferedWriter != null) {
                try {
                    bufferedWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

转换流

转换流主要有 InputStreamReader和 OutputStreamReader

字节流转换成字符流

InputStreamReader

InputStreamReader是将字节输入流转换成字符输入流

构造BufferedReader对象时候,参数是reader,假设是FileInputStream流,可以通过InputStreamReader将FileInputStream转换成FileReader

bufferedReader = new BufferedReader(
                      new InputStreamReader(
                            new FileInputStream("fileTest")));

OutputStreamWriter

OutputStreamWriter是将字节输出流转换成字符输出流

bufferedWriter = new BufferedWriter(
                      new OutputStreamWriter(
                          new FileOutputStream("BufferedWriter")));

数据流

数据专属的流,可以用来加密文件

DataOutputStream

import java.io.*;

/*

数据流
可以将数据连同数据的类型一并写进文件
不是普通文档,(记事本打不开)
 */
public class DataOutputStreamTest {
    public static void main(String[] args) {
        DataOutputStream dataOutputStream = null;
        //构造方法 参数传OutputStream
        try {
            dataOutputStream = new DataOutputStream(new FileOutputStream("data") );

            //写数据 把数据和数据类型一并写进去
            dataOutputStream.writeByte(12);
            dataOutputStream.writeShort(13);
            dataOutputStream.writeInt(14);
            dataOutputStream.writeDouble(12.2);
            dataOutputStream.writeFloat(12.0f);
            dataOutputStream.writeLong(233l);
            dataOutputStream.writeChar('c');
            dataOutputStream.writeBoolean(true);


            //刷新
            dataOutputStream.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (dataOutputStream != null) {
                try {
                    dataOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

如果用记事本打开,会乱码。

在这里插入图片描述

DataInputStream

DataOutputStream写的文件 只能使用DataInputStream去读。
还要求 读的顺序必须和写的顺序相同 读的时候 必须已知写的什么

import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

//DataOutputStream写的文件 只能使用DataInputStream去读
//还要求 读的顺序必须和写的顺序相同 读的时候 必须已知写的什么

public class DataInputStreamTest {
    public static void main(String[] args) {
        DataInputStream dataInputStream = null;
        try {
            dataInputStream = new DataInputStream(new FileInputStream("data"));
            //开始读
            //读的顺序必须和写的顺序相同 读的时候 必须已知写的什么
            System.out.println(dataInputStream.readByte());
            System.out.println(dataInputStream.readShort());
            System.out.println(dataInputStream.readInt());
            System.out.println(dataInputStream.readDouble());
            System.out.println(dataInputStream.readFloat());
            System.out.println(dataInputStream.readLong());
            System.out.println(dataInputStream.readChar());
            System.out.println(dataInputStream.readBoolean());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (dataInputStream != null) {
                try {
                    dataInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}

运行结果:

在这里插入图片描述

打印流

打印流主要包含两个:PrintStream和PrintWriter,对应字节流和字符流。

PrintStream

System.out对应的是PrintStream,默认输出到控制台,我们可以重新定向输出。不输出到控制台,输出到文件。

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.Date;

public class PrintStreamTest {
    public static void main(String[] args) {
        PrintStream printStream = null;
        try {
            printStream = new PrintStream(new FileOutputStream("print"),true);
            //改变输出方向
            System.setOut(printStream);
            //输出到print文件
            System.out.println("日志文件,不会关机消失,写到磁盘中。\n日期:"+
                              new SimpleDateFormat("yyyy-MM-dd").format(new Date())+
                                       "发生打印事件");

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }finally {
            if (printStream != null) {
                printStream.close();
            }
        }

    }
}

运行结果:
在这里插入图片描述

PrintWriter

可用来创建一个文件并向文本文件写入数据。可以理解为java中的文件输出。

import java.io.*;

public class PrintWriterTest {
    public static void main(String[] args) throws IOException {
        PrintWriter p = null;
        BufferedReader bf = null;

            //创建输出流 写文件
            p = new PrintWriter(new FileOutputStream("printWriter"));

            //开始写
            p.write("hello");
            p.write("world");

            p.flush();
            p.close();

            //开始读
        //创建输入流 读到控制台

            bf = new BufferedReader(new InputStreamReader(new FileInputStream("printWriter")));
            String s = null;
            while ((s = bf.readLine()) != null){
                System.out.println(s);
            }
            /*
        bf = new FileReader("printWriter");
        char[] chars = new char[5];
        int count = 0;
        while ((count = bf.read(chars)) != -1) {
            System.out.println(new String(chars,0,count));
        }
             */
            bf.close();

    }
}

对象流

对象流将内存中的Java对象转换成二进制写入磁盘,这个过程称作序列化:Serialize(拆分对象),并且可以从磁盘中读出完整的Java对象,这个过程称作反序列化:DeSerialize(组装对象)。

对象流主要包括:ObjectOutputStream、ObjectInputStream

序列化的实现

参与序列化的类必须实现Serializable接口,这个接口标记这个类是可序列化的。
java虚拟机会默认提供这个类的序列化版本号。

序列化多个对象使用List集合。
写出来的数据相当于加密文件

主类:

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;

public class ObjectOutputStreamTest02 {
    public static void main(String[] args) throws Exception {
        List<User> userList = new ArrayList<>();
        userList.add(new User(001,"张三"));
        userList.add(new User(002,"张四"));
        userList.add(new User(003,"张五"));
        userList.add(new User(004,"张六"));

        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("userList"));

        oos.writeObject(userList);

        //刷新
        oos.flush();

        //关闭
        oos.close();

    }
}

User类

import java.io.Serializable;

//实现序列化接口 Serializable
//标志接口 给java虚拟机看 为该类自动生成序列化版本号

public class User implements Serializable {
    int id;
    String name;

    public User(int id, String name) {
        this.id = id;
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

运行结果:

![在这里插入图片描述](https://img-blog.csdnimg.cn/19ca1fadff1f48d79b179dba35cadedf.png
这个内容是序列化的结果,等同于乱码。可以根据反序列化恢复文件。

反序列化

通过反序列化可以将序列化到磁盘中的数据恢复到内存中,直接恢复成java对象。

恢复数据相当于解密文件。

import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.util.List;

public class ObjectInputStreamTest02 {
    public static void main(String[] args) throws Exception {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("userList"));
        //反序列化集合
        for (User user : (List<User>) ois.readObject()) {
            System.out.println(user);
        }


        //关闭流
        ois.close();
    }
}

运行结果:

在这里插入图片描述

transient关键字

不想让某个字段参与序列化,用transient关键字进行修饰,反序列化出来结果就是null。

public class User implements Serializable {
    int id;
    String transient name; //不参与序列化
}

序列化版本号

Java语言通过什么区分类?一是比对类名;二是靠序列化版本号比对。

一个类实现Serializable,自动生成序列化版本号,优点是可以区分类;缺点是代码确定后,不能后续修改,如果修改,会重新编译,生成新的序列化版本号,java虚拟机这时候就认为这是全新的类,java认为是不兼容的两个类。

建议序列化版本号手动写出。

//添加一个固定的序列化版本号
private static final long serialVersionUID  = 123456789L;

这样,无论后续代码怎样升级,他的序列号是一样的,不会产生兼容的问题

File类

  • 在IO包里,唯一表示与文件本身有关的类是File类,进行文件创建、删除操作。
  • File对象是文件或目录路径的抽象表示形式,
  • File和流没有关系
  • 通过File无法完成文件读写。

常用方法

掌握File类的常用方法,学会创建文件、目录,查找文件、目录的绝对路径,获取文件最后修改时间(和Date类关联),获取父目录、子目录等方法。

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

/*文件类的常用方法
创建文件、目录
查找文件、目录的绝对路径
获取最后修改时间
获取父目录
 */
public class FileTest01 {
    public static void main(String[] args) throws IOException {
       //创建file对象
        File file = new File("D:\\a");
        //如果文件不存在 创建文件
        if(!file.exists()){
            file.createNewFile();
        }
        System.out.println(file.exists()); //true
        //获取绝对路径
        System.out.println("文件的绝对路径:"+file.getAbsolutePath());
        //获取文件名
        System.out.println("文件名:"+file.getName());
        //获取最后修改时间
        long l = file.lastModified();
        //格式
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
        System.out.println("最后修改时间:"+simpleDateFormat.format(new Date(l)));

        File file1 = new File("D:\\test\\picture");
        //如果不存在 则创建目录
        if (!file1.exists()) {
            file1.mkdir();
        }
        //获取父目录
        System.out.println("父目录:"+file1.getParent());
        //获取目录名
        System.out.println("目录名"+file1.getName());
        //判断是否是目录
        System.out.println("是不是目录:"+file1.isDirectory());

        //获取目录下所有子文件
        File file2 = new File("D:\\test");

        File[] files = file2.listFiles();
        for (File f: files
             ) {
            System.out.println("文件名:"+file2.getName()+" 绝对路径:"+file2.getAbsolutePath());
        }


    }
}

目录文件拷贝

实现目录文件的拷贝,首先确定拷贝源和拷贝目标,拷贝目标到时候会新建。

我们实现一个方法,叫copy方法,传入参数拷贝源和拷贝目标。

在这个方法中,我们分两部分,文件部分、目录部分。

确定了是文件的话,我们采用边读边写,创建字节输入输出流对象,输入流对象就是传的拷贝源。输出流对象比较复杂,是拷贝目标路径返回的字符串连接拷贝源的绝对路径从3下标开始截取的字符串,这样就是目标文件的绝对路径。下来就是边读边写了,创建字节数组,调read方法,开始写。

确定是目录的话,我们需要调用listFiles方法去获取子目录,拷贝目标路径返回的字符串连接拷贝源的绝对路径从3下标开始截取的字符串,这就是目标目录的绝对路径,获取目标目录后,我们就可以新建目录。

因为拷贝源不一定只有一个目录,也有可能目录套目录,所以我们采用递归递归传入参数,拷贝源,目标目录

这样,就完整的实现目录文件的拷贝。

import java.io.*;

//目录拷贝 边读边写
public class Copy03 {
    public static void main(String[] args) {
        //拷贝源
        File file1 = new File("D:\\test");
        //拷贝目标
        File file2 = new File("D:\\ab");
        copy(file1,file2);
    }

    private static void copy(File file1, File file2) {
        //如果是文件 递归结束  边读边写
        if(file1.isFile()){
            
            FileInputStream in = null;
            FileOutputStream out = null;
            try {
                in = new FileInputStream(file1);
                //目标文件的绝对路径 :目标路径+拷贝目标的子目录
               String path =( file2.getAbsolutePath().endsWith("\\")? file2.getAbsolutePath():file2.getAbsolutePath()+"\\")
                        + file1.getAbsolutePath().substring(3);
                out = new FileOutputStream(path);
                byte[] bytes = new byte[1024*1024];
                int count = 0;
                while ((count = in.read(bytes))!=-1){
                    out.write(bytes,0,count);
                }
                out.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (out != null){
                    try {
                        out.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }

            return;
        }
        //获取源下面的子目录
        File[] files = file1.listFiles();
        for (File f: files) {
            if(f.isDirectory()){
                //目标目录
            String s =( file2.getAbsolutePath().endsWith("\\")? file2.getAbsolutePath():file2.getAbsolutePath()+"\\")
                    + f.getAbsolutePath().substring(3);
            System.out.println("目标文件的绝对路径"+s);
                File file = new File(s);
                if (!file.exists()){
                    //新建目录方法名特别注意 mkdirs与mkdir不一样
                    file.mkdirs();
                    System.out.println(file.getAbsolutePath());
                }

            }
            copy(f,file2);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值