IO流基础知识

IO流

file类能够操作文件外部的内容,却无法操作文件内部的内容,如果想操作文件内部的内容需要通过IO流。IO流可以实现文件内容的读入写出,文件的拷贝,上传和下载。

流根据流向可分为输入流和输出流,根据操作单元可分为字符流和字节流,根据功能可分为节点流和功能流。

1. 字节流

InputStream/OutputStream

字节流是万能的,具体使用方式见下方代码。

字节输入流:

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
//使用数组进行读取
public class IODemo01 {
    public static void main(String[] args) throws IOException {
        //定义文件
        File file = new File("D://haha.txt");
        //定义数组
        byte[] arr = new byte[10];
        //创建文件输入流
        InputStream is = new FileInputStream(file);
        int len = -1;
        while ((len = is.read(arr))!=-1){
            System.out.println(new String(arr,0,len));
        }
        //关闭流
        is.close();
    }
}

字节输出流:

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class IODemo02 {
    public static void main(String[] args) throws IOException {
        //创建流
        OutputStream os = new FileOutputStream("D://haha.txt");
        //定义数组
        byte[] car = "我知道我的未来不是梦!!".getBytes();
        //写入数据
        os.write(car);
        //字节输出流刷出
        os.flush();
        //字节输出流关闭
        os.close();
    }
}

字节流实现文件的拷贝:

//字节输入流和字节输出流实现文件的拷贝
import java.io.*;
public class IOCopyDemo01 {
    public static void main(String[] args) throws IOException {
        //创建流
        InputStream is = new FileInputStream("D://picture.jpg");
        OutputStream os = new FileOutputStream("D://picture2.jpg");
        //定义字节数组
        byte[] car = new byte[1024];
        int len = -1;
        //循环写出
        while((len=is.read(car))!=-1){
            os.write(car,0,len);
        }
        //字节输出流刷出
        os.flush();
        //字节输出流关闭
        os.close();
        //字节输入流关闭
        is.close();
    }
}

2. 字符流

Reader/Writer

字符流只能用来操作纯文本的文件,具体使用方式见下方代码。

字符流实现文件的拷贝:

//字符输入流和字符输出流实现文件的拷贝
import java.io.*;

public class IOCopyDemo02 {
    public static void main(String[] args) throws IOException {
        //创建流
        FileReader rd = new FileReader("D://haha.txt");
        FileWriter wt = new FileWriter("D://haha02.txt");
        //定义字符数组
        char[] car = new char[1024];
        int len = -1;
        //循环写出
        while((len=rd.read(car))!=-1){
            wt.write(car,0,len);
        }
        //字符输出流刷出
        wt.flush();
        //字符输出流关闭
        wt.close();
        //字符输入流关闭
        rd.close();
    }
}

3. 拓展:IO流实现文件夹的复制

代码:

import java.io.*;
//拷贝文件夹   数据源 D://haha   目的地 D://AAA
public class CopyDir {
    public static void main(String[] args) throws IOException {
        copyDir("D://haha","D://AAA");
    }

    //先判断路径是否为null
    public static void copy(String src, String desc){
        if(src!=null && desc!=null){
            copy(new File(src),new File(desc));
        }else{
            throw new NullPointerException("目标路径或者目的地路径为null");
        }
    }
    //定义拷贝文件的方法
    public static void copy(File src, File desc){
        InputStream is = null;
        OutputStream os = null;
        try {
            //1.构建流
            is = new FileInputStream(src);
            os = new FileOutputStream(desc);
            //2.读入写出
            byte[] car = new byte[1024];
            int len = -1;
            while((len=is.read(car))!=-1){
                os.write(car,0,len);
            }
            //3.刷出
            os.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4.关闭
            if(os!=null){
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(is!=null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    //先判断路径是否为null
    public static void copyDir(String src,String desc) throws IOException {
        copyDir(src!=null?new File(src):null,desc!=null?new File(desc):null);
    }
    //定义拷贝文件夹的方法
    public static void copyDir(File src, File desc) throws IOException {
        //提前判断,预防数据源或者目的地出现null值
        if (src == null || desc == null) {
            throw new NullPointerException();
        }
        //过滤条件:
        //1.不能拷贝到数据源的子路径下  D://AAA/BBB
        String srcPath = src.getAbsolutePath();
        String descPath = desc.getAbsolutePath();
        //判断 目的地路径是否包含数据源路径
        if(descPath.contains(srcPath)){
            throw new IOException("不能拷贝到数据源的子路径下");
        }
        //2.不能拷贝到数据源所在路径下
        String srcParentPath = src.getParent();
        //数据源的父路径是否与目的地路径完全相等
        if(srcParentPath.equals(descPath)){
            throw new IOException("不能拷贝到数据源所在路径下");
        }
        //拷贝
        copyDirDetails(src,desc);
    }
      /*
        拷贝文件|文件夹的细节:
        如果是文件,直接拷贝
        如果是文件夹,目的地创建文件夹,遍历源文件夹
        获取文件夹中的每一个文件,再次进行重复的拷贝细节
     */
    private static void copyDirDetails(File src,File desc){
        File descFile = new File(desc,src.getName());
        //如果是文件,直接拷贝
        if(src.isFile()){
            //判断目的地路径是否真实存在,不存在创建
            if(!desc.exists()){
                desc.mkdirs();
            }
            CopyFileUtils.copy(src,descFile);
        }else if(src.isDirectory()){ 
            descFile.mkdirs();
            //获取数据源中的所有子内容
            File[] arr = src.listFiles();
            //遍历操作
            for(File file:arr){
                //递归
                copyDirDetails(file,descFile);
            }
        }
    }
}

4. 缓冲流

BufferedInputStream/BufferedOutputStream/BufferedReader/BufferedWriter

缓冲流是功能流的一种,可增强节点流的读写效率,提升性能,一般使用字节流都应该加上。

字节缓冲流实现文件的拷贝:

import java.io.*;
public class BufferedDemo {
    public static void main(String[] args) throws IOException {
        bufferedStream01();
        bufferedStream02();
    }
    //字节缓冲流实现文件的拷贝
    public static void bufferedStream01() throws IOException {
        InputStream is = new BufferedInputStream(new FileInputStream("D://haha.txt"));
        OutputStream os = new BufferedOutputStream(new FileOutputStream("D://heihei.txt"));
        byte[] car = new byte[1024];
        int len = -1;
        while ((len=is.read(car))!=-1){
            os.write(car,0,len);
        }
        os.flush();
        os.close();
        is.close();
    }
    //字符缓冲流实现文件的拷贝
    public static void bufferedStream02() throws IOException {
        //使用字符缓冲流的新增方法,因而不使用多态
        BufferedReader is = new BufferedReader(new FileReader("D://haha.txt"));
        BufferedWriter os = new BufferedWriter(new FileWriter("D://hehe.txt"));
        String msg = null;
        //readline():读取一行数据
        while ((msg=is.readLine())!=null){
            os.write(msg);
            //换行
            os.newLine();
        }
        os.flush();
        os.close();
        is.close();
    }
}

5. 转换流

InputStreamReader/OutputStreamWriter

转换流是将字节流转换为字符流的流,作用是可以设置编码格式防止乱码问题。

代码:

import java.io.*;
public class ConvertDemo {
    public static void main(String[] args) throws IOException {
        //测试转换流 字节流-->字符流
        //以UFT-8格式读取
        BufferedReader br = new BufferedReader(new InputStreamReader(new BufferedInputStream(new FileInputStream("D://haha.txt")),"UTF-8"));
        //以GBK格式写出
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream("D://heihei.txt")),"GBK"));
        String msg = null;
        while ((msg=br.readLine())!=null){
            bw.write(msg);
            bw.newLine();
        }
        bw.flush();
        bw.close();
        br.close();
    }
}

6. 基本数据类型流

DataInputStream/DataOutputStream

基本数据类型流是字节流功能流的一种,可以使节点流具有传输基本数据类型和数据的能力。

代码:

import java.io.*;
public class DataStreamDemo {
    public static void main(String[] args) throws IOException {
        //测试基本数据流的使用
        writeData("D://test.txt");
        readData("D://test.txt");
    }
	//定义写入的方法
    public static void writeData(String desc) throws IOException {
        DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(desc)));
        int i = 1;
        char ch = 'a';
        boolean flag = true;
        String str = "哈哈哈";
        out.writeInt(i);
        out.writeChar(ch);
        out.writeBoolean(flag);
        out.writeUTF(str);
        out.flush();
        out.close();
    }
	//定义读出的方法
    public static void readData(String src) throws IOException {
        DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(src)));
        int i = in.readInt();
        char ch = in.readChar();
        boolean flag = in.readBoolean();
        String str = in.readUTF();
        System.out.println(i+"-->"+ch+"-->"+flag+"-->"+str);
        in.close();
    }
}

7. 对象流

ObjectInputStream/ObjectOutputStream

对象流可实现所有类型和对象的传输。

序列化即将对象类型的信息状态转换成为一个可存储,可传输的信息状态的过程。反序列化相反。

注:

  • 读写顺序要保持一致
  • 不是所有的类型的对象都能够序列化,需要实现java.io.Serializable空接口
  • 不是所有的属性都需要序列化 ,transient关键字修饰的字段不会被序列化
  • static修饰的成员不会被序列化
  • 父类实现了序列化接口,子类所有的内容都能序列化
  • 子类实现了序列化接口,子类只能序列化自己的内容,不能序列化父类中继承的内容

序列号是用来控制版本更新的,如果之前数据的序列号与当前类型的序列号id不一致,证明版本不统一,如果想做版本兼容,需要手动提供一个序列号id,保证一直不变,就可以实现兼容。前提要求是类必须实现Serializable空接口。

代码:

import java.io.*;
import java.util.Arrays;
import java.util.Objects;
public class ObjectStreamDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //测试对象流
        writeObject("D://testobj.txt");
        readObject("D://testobj.txt");
    }
    //定义方法写入
    public static void writeObject(String desc) throws IOException {
        ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(desc)));
        int[] arr = {1,2,3,4,5};
        out.writeObject(arr);
        Student stu = new Student(1001,"张三","软件工程","清华大学");
        out.writeObject(stu);
        out.flush();
        out.close();
    }
    //定义方法读出
    public static void readObject(String src) throws IOException, ClassNotFoundException {
        ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(new FileInputStream(src)));
        int[] arr1 = (int[]) in.readObject();
        System.out.println(Arrays.toString(arr1));//[1, 2, 3, 4, 5]
        Student s = (Student) in.readObject();
        System.out.println(s);//Student{id=1001, name='张三', subject='null', school='清华大学'}
        in.close();
    }
}
//定义Student类javabean实现序列化接口
class Student implements Serializable {
    //定义序列号控制版本更新
    private static final long serialVersionUID = -969685844904026500L;
    private int id;
    private String name;
    //添加transient关键字的属性无法被序列化
    private transient String subject;
    //static关键字修饰的属性无法被序列化
    private static String school;

    public Student() {
    }

    public Student(int id, String name, String subject, String school) {
        this.id = id;
        this.name = name;
        this.subject = subject;
        this.school = school;
    }

    public static long getSerialVersionUID() {
        return serialVersionUID;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSubject() {
        return subject;
    }

    public void setSubject(String subject) {
        this.subject = subject;
    }

    public String getSchool() {
        return school;
    }

    public void setSchool(String school) {
        this.school = school;
    }

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

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return id == student.id &&
                Objects.equals(name, student.name) &&
                Objects.equals(subject, student.subject) &&
                Objects.equals(school, student.school);
    }
}

8. commonsio

commonsio是别人写好的工具类,是一个开源的工具包,提供了一些工具类。

8.1 IO工具类IOUtils

IOUtils.copy(InputStream input, OutputStream output) // 此方法有多个重载方法,满足不同的输入输出流
// 这个方法适合拷贝较大的数据流,比如2G以上
IOUtils.copyLarge(Reader input, Writer output) // 默认会用1024*4的buffer来读取
IOUtils.toInputStream(String input, String encoding) // 通过文本获取输入流,可以指定编码格式
IOUtils.toBufferedInputStream(InputStream input) // 获取一个缓冲输入流,默认缓冲大小1KB,也可以指定缓冲大小
IOUtils.toBufferedReader(Reader reader) // 获取一个字符缓冲流,可指定缓冲大小

8.2 IO 工具类 FilenameUtils

FilenameUtils.getBaseName(String filename) // 去除目录和后缀后的文件名
FilenameUtils.getExtension(String filename) // 获取文件的后缀
FilenameUtils.getName(String filename) // 获取文件名
FilenameUtils.getPath(String filename) // 去除盘符后的路径
FilenameUtils.getPrefix(String filename) // 盘符
isExtension(String fileName, String text) // 判断fileName是否是text后缀名

8.3 IO 工具类 FileUtils

FileUtils.copyDirectory(File srcDir, File destDir) // 复制文件夹(文件夹里面的文件内容也会复制)
FileUtils.copyDirectory(File srcDir, File destDir, FileFilter filter) // 复制文件夹,带有文件过滤功能
FileUtils.copyDirectoryToDirectory(File srcDir, File destDir) // 以子目录的形式将文件夹复制到到另一个文件夹下
FileUtils.copyFile(File srcFile, File destFile) // 复制文件
FileUtils.copyFileToDirectory(File srcFile, File destDir) // 复制文件到一个指定的目录
FileUtils.writeStringToFile(File file, String data, String encoding) // 字符串以指定的编码写到文件
FileUtils.writeStringToFile(File file, String data, String encoding, boolean
append) // 指定知否追加
FileUtils.writeByteArrayToFile(File file, byte[] data) // 系列方法,可以指定追加,偏移量等
FileUtils.moveFile(File srcFile, File destFile) // 移动文件
FileUtils.deleteDirectory(File directory) // 删除文件夹,包括文件夹和文件夹里面所有的文
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值