Java IO流概述及字节流与字符流

一、IO流概述

1. IO流概述

  • Java中随数据操作的方式
    • 通过流
  • IO流的作用
    • 处理设备之间的数据传输
  • 所在包
    • Java中用于操作流的对象都在 java.io 包中

2. IO流分类

  • 站在内存的角度
    • 将数据读入内存的叫做输入流
    • 将数据写出内存的叫做输出流
  • 按照读写的数据类型
    • 字节流
      • 以字节的形式读写
      • 适用于任何类型,包括音频,视频,图片,文本等
    • 字符流
      • 以字符的形式读写
      • 只适用于读写文本文件,一般文本文件的读写使用字符流

3. IO流基类概述

  • 字节流基类
    • 字节输入流:InputStream
    • 字节输出流:OutputStream
  • 字符流基类
    • 字符输入流:Reader
    • 字符输出流:Writer

二、字节流

1. FileOutputStream

  • 概述

    • 将数据以字节形式写入文件的输出流,用于写入原始字节,适用于任何类型的文件
  • 构造方法

    • FileOutputStream(File file)
      • 使用文件对象创建一个字节输出流,如果目标文件不存在则自动创建
    • FileOutputStream(String name)
      • 使用文件的路径创建一个字节输出流,如果目标文件不存在则自动创建
    • 注意
      • 不管创建了什么流,流在使用完之后一定要手动调用close方法关闭,因为流底层会调用一些C代码
      • 输出流在进行输出时,如果在相应的文件对象或文件路径下已经存在该文件,会将写出的数据写到该文件中;如果没有该文件,则会先自动创建该文件,再将写出的数据写到创建的文件中。
  • write方法

    • public void write(int b)
      • 将指定的一个字节写入
    • public void write(byte[] b)
      • 将指定的字节数组写入
    • public void write(byte[] b,int off,int len)
      • 将指定的字节数组,从指定索引处向后的指定元素个数的字节写入
  • 练习

    • 使用write方法的三个重载给指定的文件中填充数据
    public class InputFile {//使用字节输出流,为指定的文件中填充数据
    
        public static void main(String[] args) throws IOException {
            FileOutputStream output = new FileOutputStream("Test.txt");//创建字节输出流
            output.write(97);
            output.write(98);
            output.write(99);//添加单个字节数据
            output.write("\r\n".getBytes());//换行
    
            byte[] bytes = {97, 98, 99};
            output.write(bytes);//添加字节数组
            output.write("\r\n".getBytes());//换行
    
            output.write(bytes, 0, 2);//添加字节数组的一部分
            output.write("\r\n".getBytes());//换行
    
            output.close();//关闭字节输出流
        }
    }

2. FileInputStream

  • 概述

    • 从某个文件中读取字节,适用于任何文件
  • 构造方法

    • FileInputStream(File file)
      • 使用文件对象创建字节输入流
    • FileInputStream(String name)
      • 使用文件的路径名创建字节输入流
    • 注意
      • 任何输入流关联的文件对象或文件路径下一定要有对应的具体的文件,不然程序会报找不到文件异常
      • 输入流使用完毕以后也要记得关闭
  • read方法

    • int read ()
      • 一次读入一个字节
    • int read (byte[] b)
      • 一次读入一个字节数组
    • int read (byte[] b,int off,int len)
      • 一次读入一个字节数组,从指定的位置开始读指定个数的字节
  • 练习

    • 使用文件输入流与文件输出流复制文件
    public class FileCopy {//使用字节输入流与字节输出流复制文件到桌面
    
        public static void main(String[] args) throws IOException {
    
            File file = new File("录像1046.exe");//封装文件对象,可以换成你想拷贝的文件的全路径
            FileInputStream inputStream = new FileInputStream(file);//创建字节输入流
            FileOutputStream outputStream = new FileOutputStream("C:\\Users\\Administrator\\Desktop\\录像1046.exe");//创建字节输出流,字符串是眼拷贝到的地方的全路径
    
            int len = 0;//表示读取到的字节的个数
            byte[] bytes = new byte[1024 * 8];//定义字节缓冲区,表示一次读取缓冲区容量的字节
    
            while ((len = inputStream.read(bytes)) != -1) {//当要被复制的文件的字节数被读取完时,会返回-1,此时不再读取字节,复制完成
                outputStream.write(bytes, 0, len);//将读取到的字节复制到目标文件中
                outputStream.flush();
            }
            inputStream.close();
            outputStream.close();//关闭输入输出流
        }
    }

3. BufferedOutputStream

  • 概述
    • 自带缓冲区数组的字节输出流,比FileOutputStream效率更高
  • 构造方法
    • BufferedOutputStream(OutputStream out)
      • 将指定的字节输出流包装成高效的字节输出流,缓冲区的大小为默认值
    • BufferedOutputStream(OutputStream out, int size)
      • 将指定的字节输出流包装成高效的字节输出流,缓冲区大小可以指定
  • write方法
    • 与FileOutputStream一致

4. BufferedInputStream

  • 概述
    • 具有内部缓冲区数组的字节输入流
  • 构造方法
    • BufferedInputStream(InputStream in)
      • 将指定的字节输入流包装成更高效的字节输入流,缓冲区大小为默认值
    • BufferedInputStream(InputStream in, int size)
      • 将指定的字节输入流包装成更高效的字节输入流,缓冲区大小为指定大小
  • read方法
    • 与FileInputStream一致

5. 字节流练习

  • 基本字节流一次读写一个字节

    public class CopyFile {//方式1:基本字节流一次读写一个字节
    
        public static void main(String[] args) throws IOException {
            File oldfile = new File("D:\\韩红 - 飞云之下.flac");//封装原文件
            File newfile = new File("D:\\韩红 - 飞云之下2.flac");//封装新文件
    
            FileInputStream inputStream = new FileInputStream(oldfile);
            FileOutputStream outputStream = new FileOutputStream(newfile);//创建输入输出流
    
            int len = 0;
            while ((len = inputStream.read()) != -1) {//当原文件读取完时返回-1,循环结束
                outputStream.write(len);//将读取到的字节写入新文件
                outputStream.flush();
            }
            inputStream.close();
            outputStream.close();//h=关闭输入输出流
        }
    }
  • 基本字节流一次读写一个字节数组

    public class CopyFile2 {//方式2:基本字节流一次读写一个字节数组
    
        public static void main(String[] args) throws IOException {
            File oldfile = new File("D:\\韩红 - 飞云之下.flac");//封装原文件
            File newfile = new File("D:\\韩红 - 飞云之下2.flac");//封装新文件
    
            FileInputStream inputStream = new FileInputStream(oldfile);
            FileOutputStream outputStream = new FileOutputStream(newfile);//创建输入输出流
    
            int len = 0;
            byte[] bytes = new byte[1024 * 8];//自定义长度字节数组
            while ((len = inputStream.read(bytes)) != -1) {//获取的到的字节数组的长度,当原文件读取完时返回-1,循环结束
                outputStream.write(bytes, 0, len);//将读取到的字节数组写入新文件
                outputStream.flush();
            }
            inputStream.close();
            outputStream.close();//关闭输入输出流
        }
    }
  • 高效字节流一次读写一个字节

    public class CopyFile3 {//方式3:高效字节流一次读写一个字节
    
        public static void main(String[] args) throws IOException {
            File oldFile = new File("D:\\韩红 - 飞云之下.flac");//封装原文件
            File newFile = new File("D:\\韩红 - 飞云之下2.flac");//封装新文件
    
            BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(oldFile));
            BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(newFile));//创建输入输出流
    
            int len = 0;
            while ((len = inputStream.read()) != -1) {//获取文件中的字节,当原文件读取完时返回-1,循环结束
                outputStream.write(len);//将读取到的字节写入新文件
                outputStream.flush();
            }
            inputStream.close();
            outputStream.close();//关闭输入输出流
        }
    }
  • 高效字节流一次读写一个字节

    public class CopyFile4 {//方式4:高效字节流一次读写一个字节数组
    
        public static void main(String[] args) throws IOException {
            File oldFile = new File("D:\\韩红 - 飞云之下.flac");//封装原文件
            File newFile = new File("D:\\韩红 - 飞云之下2.flac");//封装新文件
    
            BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(oldFile));
            BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(newFile));//创建输入输出流
    
            int len = 0;
            byte[] bytes = new byte[1024 * 8];//自定义长度字节数组
            while ((len = inputStream.read(bytes)) != -1) {//获取的到的字节数组的长度,当原文件读取完时返回-1,循环结束
                outputStream.write(bytes, 0, len);//将读取到的字节数组写入新文件
                outputStream.flush();
            }
            inputStream.close();
            outputStream.close();//关闭输入输出流
        }
    }

三、字符流

1. 字符串与字节数组间转换

  • 为什么有字符流
    • 因为在编码中,使用字节对中文进行操作不是很方便,不同的编码中,一个中文字符可能是2个字节,也可能是3个字节,所以采用字符流对中文字符进行操作比较简单
  • 字符流 = 字节流 + 编码方式
  • 编码与解码
    • 编码
      • 将字符串转换为字节数组
    • 解码
      • 将字节数组转换为字符串
  • getBytes方法与string方法
    • public byte[] getBytes()
      • 使用默认的编码表将字符串编码为字节数组
    • public byte[] getBytes(String charsetName)
      • 使用指定的编码表将字符串编码为字节数组
    • public String(byte[] bytes)
      • 使用默认的编码表将字节数组解码为字符串
    • public String(byte[] bytes, String charsetName)
      • 使用指定的编码表将字节数组解码为字符串

2. OutputStreamWriter

  • 概述
    • 可以使用指定的编码表,将字符编码为字节,写入文件中
    • 可以给定编码表,否则使用默认的编码表
  • 构造方法
    • OutputStreamWriter(OutputStream out)
      • 使用默认的编码表,将字节输出流包装为字符输出流
    • OutputStreamWriter(OutputStream out, String charsetName)
      • 使用指定的编码表,将字节输出流包装成字符输出流
  • write方法
    • public void write(int c)
      • 写一个字符
    • public void write(char[] cbuf)
      • 写一个字符数组
    • public void write(char[] cbuf,int off,int len)
      • 写一个字符数组,从指定的位置开始往后指定数量的字符
    • public void write(String str)
      • 写一个字符串
    • public void write(String str,int off,int len)
      • 写一个字符串,从指定位置开始的指定长度的子串
    • 注意
      • 所有的字符流写完之后都必须要使用flush方法刷新一下,close方法附带刷新功能

3. InputStreamReader

  • 概述

    • 可以使用特定的编码表,将读取到的字节流转换为字符流
    • 编码表可以显示的给出,也可以使用默认的编码表
  • 构造方法

    • InputStreamReader(InputStream is)
      • 使用默认的编码表将字节输入流包装为字符输入流
    • InputStreamReader(InputStream is,String charsetName)
      • 使用指定的编码表将字节输入流包装为字符输入流
  • read方法

    • public int read()
      • 一次读一个字符
    • public int read(char[] cbuf)
      • 一次读一个字符数组
  • 练习

    • 使用OutputStreamWriter和InputStreamReader复制一个文本文件
    //a) 基本的流一次一个字符
    public class OneChar {//a) 基本的流一次一个字符
    
        public static void main(String[] args) throws IOException {
            File oldFile = new File("MusicCopies.java");
            File copyFile = new File("C:\\Users\\北风\\Desktop\\CopyMusicCopies.java");//封装原文件与目标文件
            InputStreamReader reader = new InputStreamReader(new FileInputStream(oldFile));
            OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(copyFile));//创建读写文件的基本字符流
            int len;
            while ((len = reader.read()) != -1) {//进行复制,当读完最后一个字符的时候结束
                writer.write(len);
            }
            reader.close();
            writer.close();//关闭字符输入输出流
        }
    }
    
    //b) 基本的流一次一个字符数组
    public class CharArrCopy {//b) 基本的流一次一个字符数组
    
        public static void main(String[] args) throws IOException {
            File oldFile = new File("MusicCopies.java");
            File copyFile = new File("C:\\Users\\北风\\Desktop\\CopyMusicCopies.java");//封装原文件与目标文件
            InputStreamReader reader = new InputStreamReader(new FileInputStream(oldFile));
            OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(copyFile));//创建读写文件的基本字符流
    
            char[] chars = new char[1024];//创建字符数组缓冲区,一次读入1024个字符
            int len;
            while ((len = reader.read(chars)) != -1) {//进行复制,当读完最后一个字符数组的时候结束
                writer.write(chars, 0, len);
            }
            reader.close();
            writer.close();//关闭字符输入输出流
        }
    }

4. FileWriter 和 FileReader

  • 概述
    • 字符流便捷类,为了便于书写,用法与InputStreamReader和OutputStreamWriter基本相同
    • FileWriter------->OutputStreamWriter
    • FileReader------->InputStreamReader

5. BufferedWriter

  • 概述
    • 带有缓冲区的高效字符输出流,缓冲区大小可指定,也可以使用默认大小
  • 构造方法
    • BufferedWriter(Writer out)
      • 创建一个默认缓冲区大小的高效字符输出流
    • BufferedWriter(Writer out,int sz)
      • 创建一个指定缓冲区大小的高效字符缓冲区
  • 方法
    • void write()
      • 可以写入任意类型的数据
    • void newLine()
      • 换行,不区分平台,建议优先使用此方法
    • void flush ()
      • 对该流的缓冲进行刷新

6. BufferedReader

  • 概述

    • 带有缓冲区的高效字符输入流,缓冲区大小可指定,也可以采用默认大小
  • 构造方法

    • BufferedReader(Reader in)
      • 创建默认缓冲区大小的高效字符流
    • BufferedReader(Reader in,int sz)
      • 创建指定缓冲区大小的高效字符流
  • 方法

    • read()
      • 读取任何类型的数据
    • readLine()
      • 读取一行数据,没有读到则返回null
  • 练习

    • 使用BufferedWriter与BufferedReader复制一个文本文件
    //c)高效的流一次一个字符
    public class BufferOneCharCopy {//c) 高效的流一次一个字符
    
        public static void main(String[] args) throws IOException {
            File oldFile = new File("MusicCopies.java");
            File copyFile = new File("C:\\Users\\北风\\Desktop\\CopyMusicCopies.java");//封装原文件与目标文件
    
            BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(oldFile)));
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(copyFile)));//创建高效的字符输入输出流
    
            int len;
            while ((len = reader.read()) != -1) {//使用高效的字符输入流读取单个字符
                writer.write(len);//写单个字符
            }
            reader.close();
            writer.close();//关闭输入输出流
        }
    }
    
    //d) 高效的流一次一个字符数组
    public class BufferCharArrCopy {//d) 高效的流一次读写一个字符数组
    
        public static void main(String[] args) throws IOException {
            File oldFile = new File("MusicCopies.java");
            File copyFile = new File("C:\\Users\\北风\\Desktop\\CopyMusicCopies.java");//封装原文件与目标文件
    
            BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(oldFile)));
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(copyFile)));//创建高效的字符输入输出流
    
            char[] chars = new char[1024];//创建字符数组缓冲区
            int len;
            while ((len = reader.read(chars)) != -1) {//使用高效的字符输入流读取字符数组
                writer.write(chars, 0, len);//写字符数组
            }
            reader.close();
            writer.close();//关闭输入输出流
        }
    }
    
    //e) 高效的流一次一行字符串
    public class BufferALineCopy {//e) 高效的流一次读写一个行字符
    
        public static void main(String[] args) throws IOException {
            File oldFile = new File("MusicCopies.java");
            File copyFile = new File("C:\\Users\\北风\\Desktop\\CopyMusicCopies.java");//封装原文件与目标文件
    
            BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(oldFile)));
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(copyFile)));//创建高效的字符输入输出流
    
            String len;
            while ((len = reader.readLine()) != null) {//使用高效的字符输入流读取一行字符
                writer.write(len);//写入一行字符
                writer.newLine();
                writer.flush();
            }
            reader.close();
            writer.close();//关闭输入输出流
        }
    }

7. 字符流练习

  • 复制单层文件夹
public class DirectoryCopy {//复制单层文件夹

    public static void main(String[] args) throws IOException {
        //封装原文件夹
        String oldDirectoryPath = "C:\\Users\\Administrator\\Desktop\\img";
        File oldDirectory = new File(oldDirectoryPath);
        //封装新文件夹
        String newDirectoryPath = "C:\\Users\\Administrator\\Desktop\\img2";
        File newDirectory = new File(newDirectoryPath);
        //调用方法复制文件夹
        copyDirectory(oldDirectory, newDirectory);
    }

    /**
     * 此方法将制定的文件夹复制到指定的路径下
     */
    private static void copyDirectory(File oldDirectory, File newDirectory) throws IOException {
        newDirectory.mkdirs();//创建新文件夹
        for (File file : oldDirectory.listFiles()) {//循环遍历赋值子文件

            copyFile(file, newDirectory);//调用方法复制文件
        }
    }

    /**
     * 此方法将指定的文件复制到制定的路径下
     */
    private static void copyFile(File oldfile, File newDirectory) throws IOException {
        FileInputStream inputStream = new FileInputStream(oldfile);//输入流
        FileOutputStream outputStream = new FileOutputStream(newDirectory.getAbsolutePath() + "\\" + oldfile.getName());//输出流

        int len = 0;//得到实际遍历的字节数
        byte[] bytes = new byte[1024 * 8];//定义每次遍历字节数
        while ((len = inputStream.read(bytes)) != -1) {//当遍历所有元素后,循环退出
            outputStream.write(bytes, 0, len);//填入
            outputStream.flush();
        }

        //关闭输入输出流
        inputStream.close();
        outputStream.close();
    }
}
  • 复制多级文件夹
public class DirectoriesCopy {//使用递归
    public static void main(String[] args) throws IOException {
        //封装原文件夹
        String oldDirectoryPath = "C:\\Users\\Administrator\\Desktop\\imgs";
        File oldDirectory = new File(oldDirectoryPath);
        //封装新文件夹
        String newDirectoryPath = "C:\\Users\\Administrator\\Desktop\\imgs2";
        File newDirectory = new File(newDirectoryPath);

        copyDirectory(oldDirectory, newDirectory);
    }

    /**
     * 此方法将制定的文件夹复制到指定的路径下
     */
    private static void copyDirectory(File oldDirectory, File newDirectory) throws IOException {

        System.out.println(oldDirectory.getAbsolutePath());
        System.out.println(newDirectory.getAbsolutePath());

        newDirectory.mkdirs();//创建新文件夹
        for (File file : oldDirectory.listFiles()) {//循环遍历赋值子文件
            if (file.isFile()) {
                copyFile(file, newDirectory);//如果是文件直接复制
            } else {
                File newDire = new File(newDirectory.getAbsolutePath() + "\\" + file.getName());
                copyDirectory(file, newDire);//如果是文件夹,先创建对应的文件夹,再调用方法,复制文件夹内的文件
            }
        }
    }

    /**
     * 此方法将指定的文件复制到制定的路径下
     */
    private static void copyFile(File oldfile, File newDirectory) throws IOException {
        FileInputStream inputStream = new FileInputStream(oldfile);//输入流
        FileOutputStream outputStream = new FileOutputStream(newDirectory.getAbsolutePath() + "\\" + oldfile.getName());//输出流
        byte[] bytes = new byte[1024 * 8];//定义每次遍历字节数
        int len = 0; //得到实际遍历的字节数

        while ((len = inputStream.read(bytes)) != -1) {//当遍历所有元素后,循环退出
            outputStream.write(bytes, 0, len);//填入
            outputStream.flush();
        }

        //关闭输入输出流
        inputStream.close();
        outputStream.close();
    }
}
  • 键盘录入学生的信息与成绩,按总分倒序将信息写入文本文件中
//在实际过程中,成员变量应该私有,给出对应的get、set方法即可,以保证封装性
public class Student {//学生成绩类
    public String name = "";
    public double chScore = 0;
    public double mathScore = 0;
    public double engScore = 0;
    public double totalScore = 0;//成员变量

    public Student(String name, double chScore, double mathScore, double engScore) {//有参构造
        this.name = name;
        this.chScore = chScore;
        this.mathScore = mathScore;
        this.engScore = engScore;
        this.totalScore = chScore + mathScore + engScore;
    }
}

public class StudentScoreSort {//请编写程序,完成键盘录入学生信息按照总分排序并写入文本文件

    public static void main(String[] args) throws IOException {

        int number = 3;//学生人数

        TreeSet<Student> studentTreeSet = new TreeSet<>(new Comparator<Student>() {//创建集合用来存储学生信息
            @Override
            public int compare(Student s1, Student s2) {
                int num1 = (int) (s1.totalScore - s2.totalScore);
                int num2 = num1 == 0 ? (s1.name.compareTo(s2.name)) : (num1);
                return -num2;
            }
        });
        for (int i = 0; i < number; i++) {//循环得到5个学生的成绩信息
            Scanner input = new Scanner(System.in);
            System.out.println("请输入第" + (i + 1) + "个学生的姓名");
            String name = input.nextLine();
            System.out.println("请输入第" + (i + 1) + "个学生的语文成绩");
            double chScore = input.nextDouble();
            System.out.println("请输入第" + (i + 1) + "个学生的数学成绩");
            double mathScore = input.nextDouble();
            System.out.println("请输入第" + (i + 1) + "个学生的英语成绩");
            double engScore = input.nextDouble();
            Student stu = new Student(name, chScore, mathScore, engScore);
            studentTreeSet.add(stu);
        }

        File file = new File("StuScoreInfo.txt");//将学生信息存储到文件中
        BufferedWriter stuWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file)));//创建字符输出流对象
        int num = 5;
        for (Student student : studentTreeSet) {//遍历学生信息并写入
            stuWriter.write("成绩排名:" + (num--) + "\t");
            stuWriter.write("姓名:" + student.name + "\t");
            stuWriter.write("语文成绩:" + student.chScore + "\t");
            stuWriter.write("数学成绩:" + student.mathScore + "\t");
            stuWriter.write("英语成绩:" + student.engScore + "\t");
            stuWriter.write("总成绩:" + student.totalScore + "\t");
            stuWriter.newLine();
        }
        stuWriter.close();//关闭流
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值