JAVA SE之面向对象15:IO流之字节流与字符流

今日内容:

  • IO流之字节流
  • IO流之字符流

1.IO流概述及其分类

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

  • IO流分类

    • a.按照数据流向 站在内存角度
      输入流 读入数据
      输出流 写出数据
    • b.按照数据类型
      字节流 可以读写任何类型的文件 比如音频 视频 文本文件
      字符流 只能读写文本文件
  • 什么情况下使用哪种流呢?
    如果数据所在的文件通过windows自带的记事本打开并能读懂里面的内容,就用字符流。其他用字节流;如果你什么都不知道,就用字节流

2.IO流基类概述和FileOutputStream(输出流)的引入

  • IO流基类概述

    • a.字节流的抽象基类:
      InputStream ,OutputStream

    • b.字符流的抽象基类:
      Reader , Writer
      **注:**由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。

    • 如:InputStream的子类FileInputStream

    • 如:Reader的子类FileReader

  • FileOutputStream的构造方法
    由一个案例引出使用IO流写数据,由于字节流先出现就先使用字节输出流基类OutputStream,使用具体子类FileOutputStream。

  • 按照操作的数据类型进行划分

    • a.字节流
      字节输入流 InputStream 读
      字节输出流 OutputStream 写

    • b.字符流
      字符输入流 Reader 读
      字符输出流 Writer 写

  • 需求:往一个文本文件中写一串数据 Hello,IO

  • 分析:

    • a.我们现在操作的是文本文件,所有按照我们的想法,我们优先现在字符流,但是字节流是优先于字符流. 所以先使用字节流;
    • b.因为我们要写数据,所以我们应该使用字节流中输出流 OutputStream

2.1 FileOutputStream写出数据

  • 构造方法
    FileOutputStream(File file)
    FileOutputStream(String name)

注意事项:

  • a.调用系统资源创建a.txt文件

  • b.创建了一个fos对象

  • c.把fos对象指向这个文件

  • 为什么一定要close()?

    • a.通知系统释放关于管理a.txt文件的资源
    • b.让Io流对象变成垃圾,等待垃圾回收器对其回收

2.2 FileOutputStream的三个write()方法

  • public void write(int b):
    写一个字节 超过一个字节 砍掉前面的字节

  • public void write(byte[] b):
    写一个字节数组

  • public void write(byte[] b,int off,int len):
    写一个字节数组的一部分

2.3 FileOutputStream写出数据加入异常处理

public class Test {
     
    public static void main(String[] args) {
     
        //流的异常处理
        FileOutputStream out = null;
        try {
     
            out = new FileOutputStream("a.txt");
            out.write("abc".getBytes());
            //System.out.println(1 / 0);
        } catch (IOException e) {
     
            e.printStackTrace();
        } catch (Exception e) {
     
            e.printStackTrace();
        } finally {
     
            try {
     
                if (out != null) {
     
                    System.out.println("进来了");
                    out.close();
                }
            } catch (IOException e) {
     
                e.printStackTrace();
            }
        }
    }
}

2.4 FileInputStream读取数据一次一个字节

public class Test {
     
    public static void main(String[] args) throws IOException {
     
        FileInputStream in = new FileInputStream("a.txt");
        //读取文件数据,
        int by = in.read(); //一次读取一个字节数据,返回的是你读取到的那个字节
        System.out.println(by);
        //System.out.println((char) by);
        by = in.read(); //一次读取一个字节数据
        System.out.println(by);
        by = in.read(); //一次读取一个字节数据
        System.out.println(by);
        //文件中数据读取完毕,然后读取不到了,返回 -1 我们可以使用 -1 来判断文件是否读取完毕。
        by = in.read(); //一次读取一个字节数据
        System.out.println(by);
    }
}

2.5 FileInputStream读取数据一次一个字节数组

public class Test {
     
    public static void main(String[] args) throws IOException {
     
        FileInputStream in = new FileInputStream("a.txt");
        //我们创建一个字节数组,作为缓冲区,
        byte[] bytes = new byte[100];
        //返回的是你实际读取到的字节个数,
        int len = in.read(bytes); //把文件中的字节一次读取满,你这个字节数组
        System.out.println(len);
        //len = in.read(bytes); //读取不到返回-1
        //System.out.println(len);

        System.out.println("================================");

       /* for (byte aByte : bytes) {
            System.out.println(aByte);
        }*/

        String s = new String(bytes, 0, len);
        System.out.println(s);
        // byte[] bytes1 = s.getBytes();


        in.close(); //不要忘了


    }
}

2.6 字节流复制文本文件

public class Test {
     
    public static void main(String[] args) throws IOException {
     
        //复制文件,读取一个字节,写入一个字节来复制

        FileInputStream in = new FileInputStream("C:\\Users\\ShenMouMou\\Desktop\\MyTest.java");
        FileOutputStream out = new FileOutputStream("D:\\test\\MyTest.java");
       /* while (true) {
            int by = in.read();
            if (by == -1) {
                break;
            }
            out.write(by);
        }*/
        int by = 0;
        while ((by = in.read()) != -1) {
     
            out.write(by);
        }

        in.close();
        out.close();
    }
}

2.7 字节流复制MP3

演示:	字节流一次读写一个字节数组复制MP3

代码如下:

public class Test {
     
    public static void main(String[] args) {
     
        FileInputStream in = null;
        FileOutputStream out = null;
        try {
     
            in = new FileInputStream("想要复制的文件名称路径");
            out = new FileOutputStream("想要复制到指定盘符文件夹下的路径");

            byte[] bytes = new byte[1024 * 8];
            int len = 0;
            while ((len = in.read()) != -1) {
     
                out.flush();
                out.write(bytes, 0, len);
            }
        } catch (FileNotFoundException ex) {
     
            ex.printStackTrace();
        } catch (IOException ex) {
     
            ex.printStackTrace();
        } finally{
     
            try{
     
                if (in != null) {
     
                    in.close();
                }
                if(out != null){
     
                    out.close();
                }
            }catch (IOException e){
     
                e.printStackTrace();
            }
        }
    }
}

3.BufferedOutputStream写出数据与BufferedInputStream读取数据

  • 缓冲思想
    字节流一次读写一个数组的速度明显比一次读写一个字节的速度快很多,
    这是加入了数组这样的缓冲区效果,java本身在设计的时候,
    也考虑到了这样的设计思想(装饰设计模式后面讲解),所以提供了字节缓冲区流

  • BufferedOutputStream的构造方法
    该类实现缓冲的输出流。通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必针对每次字节写入调用底层系统。
    BufferedOutputStream(OutputStream out)

  • BufferedInputStream的构造方法
    BufferedInputStream 为另一个输入流添加一些功能,即缓冲输入以及支持 mark 和 reset 方法的能力
    在创建 BufferedInputStream 时,会创建一个内部缓冲区数组。在读取或跳过流中的字节时,可根据需要从包含的输入流再次填充该内部缓冲区,一次填充多个字节

  • 演示:BufferedOutputStream写出数据和BufferedInputStream读取数据

代码如下:
public class MyTest {
     
    public static void main(String[] args) throws IOException {
     
       
       Test(); 
       
    }

    private static void Test1() throws IOException {
     
        FileInputStream in = new FileInputStream("想要复制的文件名称路径");
        FileOutputStream out = new FileOutputStream("想要复制到指定盘符文件夹下的路径");
        BufferedInputStream bin = new BufferedInputStream(in);
        BufferedOutputStream bout = new BufferedOutputStream(out);
        byte[] bytes = new byte[1024 * 8];
        int by = 0;
        while ((by = bin.read(bytes)) != -1) {
     
            bout.write(bytes, 0, by);
        }
        bin.close();
        bout.close();
    }

练习:字节流四种方式复制MP3并测试效率

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


        //test1();  //复制完成耗时:24962毫秒  14毫秒
        //test2(); // 复制完成耗时:188毫秒 复制完成耗时:12毫秒
    }

    private static void test2() throws IOException {
     
        FileInputStream in = new FileInputStream("C:\\Users\\ShenMouMou\\Desktop\\烟花易冷Live_林志炫.mp3");
        FileOutputStream out = new FileOutputStream("D:\\test\\烟花易冷Live.mp3");
        BufferedInputStream bin = new BufferedInputStream(in);
        //ctrl+Q 查看方法的文档
        //ctrl+P 查看方法的参数
        BufferedOutputStream bout = new BufferedOutputStream(out);
        byte[] bytes = new byte[1024 * 8];
        int by = 0;
        long start = System.currentTimeMillis();
        while ((by = bin.read(bytes)) != -1) {
     
            bout.write(bytes, 0, by);
        }
        long end = System.currentTimeMillis();
        bin.close();
        bout.close();
        System.out.println("复制完成耗时:" + (end - start) + "毫秒");
    }

    private static void test1() throws IOException {
     
        FileInputStream in = new FileInputStream("C:\\Users\\ShenMouMou\\Desktop\\烟花易冷Live_林志炫.mp3");
        FileOutputStream out = new FileOutputStream("D:\\test\\烟花易冷Live.mp3");
        byte[] bytes = new byte[1024 * 8];
        int by = 0;
        long start = System.currentTimeMillis();
        while ((by = in.read(bytes)) != -1) {
     
            out.write(bytes, 0, by);
            out.flush();
        }
        long end = System.currentTimeMillis();
        in.close();
        out.close();
        System.out.println("复制完成耗时:" + (end - start) + "毫秒");
    }
}

4.字符流出现的原因及编码表概述和常见编码表

  • 字符流出现的原因:由于字节流操作中文不是特别方便,所以,java就提供了字符流
  • 字符流:字符流 = 字节流 + 编码表

4.1 String类中的编码和解码问题

  • 编码:把字符串转换成字节数组

    • public byte[] getBytes():
      使用平台的默认字符集将此 String编码为 byte 序列,并将结果存储到一个新的 byte 数组中

    • public byte[] getBytes(String charsetName):
      使用指定的字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中

  • 解码:把字节数组转换成字符串

    • public String(byte[] bytes):
      通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String

    • public String(byte[] bytes, String charsetName):
      通过使用指定的 charset 解码指定的 byte 数组,构造一个新的 String。

4.2 字符流OutputStreamWriter的使用及写数据的方式

  • OutputStreamWriter的构造方法
    • OutputStreamWriter(OutputStream out):
      根据默认编码(GBK)把字节流的数据转换为字符流
  • OutputStreamWriter(OutputStream out,String charsetName):
    根据指定编码把字节流数据转换为字符流
  • 方法概述
    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) 写一个字符串的一部分

4.3 字符流InputStreamReader的使用及读数据的方式

  • InputStreamReader的构造方法
    InputStreamReader(InputStream is):用默认的编码(GBK)读取数据
    InputStreamReader(InputStream is,String charsetName):用指定的编码读取数据
  • 方法概述
    public int read() 一次读取一个字符,如果没有读到 返回-1
    public int read(char[] cbuf) 一次读取一个字符数组 如果没有读到 返回-1

练习:字符流复制文本文件

	代码如下:
	public class Test {
     
	    public static void main(String[] args) {
     
	        InputStreamReader readr = null;
	        OutputStreamWriter writer = null;
	        try {
     
	            readr = new InputStreamReader(new FileInputStream(想要复制的文件名称路径"));
	            writer = new OutputStreamWriter(new FileOutputStream("想要复制到指定盘符文件夹下的路径"));
	            char[] chars = new char[200000];
	            int len = 0;
	            while ((len=readr.read())!=-1){
     
	                writer.flush();
	                writer.write(chars,0,len);
	            }
	        } catch (FileNotFoundException e) {
     
	            e.printStackTrace();
	        }catch(IOException e){
     
	            e.printStackTrace();
	        }finally {
     
	            try{
     
	                if(readr!=null){
     
	                    readr.close();
	                }
	                if(writer!=null){
     
	                    writer.close();
	                }
	            } catch (IOException e) {
     
	                e.printStackTrace();
	            }
	        }
	    }
	}

4.3 FileWriter和FileReader复制文本文件

  • A:FileReader和FileWriter的出现
    转换流的名字比较长,而我们常见的操作都是按照本地默认编码实现的,
    所以,为了简化我们的书写,转换流提供了对应的子类。
    FileWriter
    FileReader
  • 字符流便捷类: 因为转换流的名字太长了,并且在一般情况下我们不需要制定字符集,于是java就给我们提供转换流对应的便捷类
    转换流 便捷类
    • OutputStreamWriter ------- FileWriter
    • InputStreamReader ------- FileReader

4.4 字符缓冲流的基本使用

  • 高效的字符流
    高效的字符输出流: BufferedWriter
    构造方法: public BufferedWriter(Writer w)
    高效的字符输入流: BufferedReader
    构造方法: public BufferedReader(Reader e)

练习:字符缓冲流复制文本文件

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

        BufferedReader reader = new BufferedReader(new FileReader("a.txt"));
        BufferedWriter writer = new BufferedWriter(new FileWriter("c.txt"));
        //定义一个字符数组来充当缓冲区
        char[] chars = new char[1000];
        int len = 0; //记录读取到的实际的字符个数
        while ((len = reader.read(chars)) != -1) {
     
            System.out.println(len);
            writer.write(chars, 0, len);
            writer.flush();
            System.out.println("正在复制 ...");
        }
        reader.close();
        writer.close();
    }
}

4.5 字符缓冲流的特殊功能

  • BufferedWriter: public void newLine():根据系统来决定换行符 具有系统兼容性的换行符

  • BufferedReader: public String readLine():一次读取一行数据 是以换行符为标记的 读到换行符就换行 没读到数据返回null

  • 包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null

练习:字符缓冲流的特殊功能复制文本文件

public class MyTest2 {
     
    public static void main(String[] args) {
     
        BufferedReader reader = null;
        BufferedWriter writer = null;
        try {
     
            reader = new BufferedReader(new FileReader("a.txt"));
            writer = new BufferedWriter(new FileWriter("e.txt"));
       /*
        BufferedReader
       String readLine ()
        一次读取一行。*/
      /*
       BufferedWriter
        void newLine ()
        写入一个换行符,具有平台兼容。
        */
            String line = null;
            while ((line = reader.readLine()) != null) {
     
                writer.write(line);
                writer.newLine();
                writer.flush();
            }

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

    }
}

练习:把集合(ArrayList)中的数据存储到文本文件

  • 分析:
    a.创建一个ArrayList集合
    b.添加元素
    c.创建一个高效的字符输出流对象
    d.遍历集合,获取每一个元素,把这个元素通过高效的输出流写到文本文件中
    e.释放资源
public class Test {
     
    public static void main(String[] args) throws IOException {
     


        ArrayList<String> list = new ArrayList<>();
        list.add("陈更更");
        list.add("刘思雨");
        list.add("张学友");
        list.add("刘思雨");
        list.add("周润发");
        list.add("李德华");
        list.add("张柏芝");
        list.add("谢霆锋");
        list.add("汪峰");

        BufferedWriter writer = new BufferedWriter(new FileWriter("student.txt"));
        for (String s : list) {
     
            writer.write(s);
            writer.newLine();
            writer.flush();
        }
        writer.close();

    }
}

练习:随机获取文本文件中的姓名

  • 需求:我有一个文本文件,每一行是一个学生的名字,请写一个程序,每次允许随机获取一个学生名称
  • 分析:
    a.创建一个高效的字符输入流对象
    b.创建集合对象
    c.读取数据,把数据存储到集合中
    d.产生一个随机数,这个随机数的范围是 0 - 集合的长度 . 作为: 集合的随机索引
    e.根据索引获取指定的元素
    f.输出
    g.释放资源
	```java
public class Test {
     
    public static void main(String[] args) throws IOException {
     

        BufferedReader reader = new BufferedReader(new FileReader("student.txt"));
        ArrayList<String> list = new ArrayList<>();
        while (true) {
     
            String name = reader.readLine();
            if (name == null) {
     
                break;
            }
            list.add(name);
        }
        reader.close();
        //System.out.println(list);
        //点名器
        Random random = new Random();
        int index = random.nextInt(list.size());
        String s = list.get(index);
        System.out.println(s);
    }
}

练习:复制单级文件夹

  • 分析:
    a.封装D:\course为一个File对象
    b.封装E:\course为一个File对象,然后判断是否存在,如果不存在就是创建一个目录
    c.获取a中的File对应的路径下所有的文件对应的File数组
    d.遍历数组,获取每一个元素,进行复制
    e.释放资源
public class Test {
     
    public static void main(String[] args) throws IOException {
     
        //封装源文件夹
        File oldfile = new File("D:\\fxx");
        //封装目标文件夹
        File newfile = new File("E:\\fxx");
        if(!newfile.exists()){
     
            newfile.mkdirs();
        }
        CopyFiles(oldfile,newfile);
    }

    //复制文件夹中的文件
    private static void CopyFiles(File oldfile, File newfile) throws IOException {
     
        //遍历源文件夹并获取数组
        File[] files = oldfile.listFiles();
        for (File file : files){
     
            if(file.isFile()) {
     
                CopyFile(file, newfile);
            }
            else{
     
            }
        }
    }
    private static void CopyFile(File file, File newfile) throws IOException {
     
        FileInputStream in = new FileInputStream(file);
        FileOutputStream out = new FileOutputStream(new File(newfile, file.getName()));

        byte[] bytes = new byte[430205700];
            int len = 0;
            while ((len = in.read(bytes)) != -1) {
     
                out.flush();
                out.write(bytes, 0, len);
            }
            in.close();
            out.close();
        }
    }

练习:复制指定目录下指定后缀名的文件并修改名称

  • 需求: 复制D:\demo目录下所有以.java结尾的文件到E:\demo .并且将其后缀名更改文.jad
public classCopyFolderDemo {
     
   public static void main(String[] args) throws IOException {
     
      // 封装目录

      FilesrcFolder = newFile("e:\\java");

      // 封装目的地

      FiledestFolder = newFile("e:\\jad");

      // 如果目的地目录不存在,就创建

      if (!destFolder.exists()){
     
         destFolder.mkdir();

      }
      // 获取该目录下的java文件的File数组

      File[]fileArray = srcFolder.listFiles(new FilenameFilter() {
     
         @Override

         public boolean accept(File dir, Stringname) {
     
            return new File(dir,name).isFile() && name.endsWith(".java");

         }

      })// 遍历该File数组,得到每一个File对象

      for (File file : fileArray){
     
         // System.out.println(file);

         // 数据源:e:\java\DataTypeDemo.java

         // 目的地:e:\\jad\DataTypeDemo.java

         Stringname = file.getName();

         FilenewFile = newFile(destFolder, name);

         copyFile(file,newFile);

      }
      // 在目的地目录下改名

      File[]destFileArray = destFolder.listFiles();

      for (File destFile :destFileArray) {
     
         // System.out.println(destFile);

         // e:\jad\DataTypeDemo.java

         // e:\\jad\\DataTypeDemo.jad

         Stringname =destFile.getName(); //DataTypeDemo.java

         StringnewName = name.replace(".java", ".jad");//DataTypeDemo.jad

         FilenewFile = newFile(destFolder,newName);

         destFile.renameTo(newFile);

      }

   }

   private static void copyFile(File file,File newFile) throwsIOException {
     
      BufferedInputStreambis = newBufferedInputStream(new FileInputStream(

            file));

      BufferedOutputStreambos = newBufferedOutputStream(

            newFileOutputStream(newFile));

 

      byte[] bys = new byte[1024];

      int len = 0;

      while ((len = bis.read(bys))!= -1) {
     
         bos.write(bys,0, len);

      }
      bos.close();
      bis.close();
   }
}

练习:键盘录入学生信息按照总分排序并写入文本文件

需求:键盘录入3个学生信息(姓名,语文成绩(chineseScore),数学成绩(mathScore),英语成绩(englishScore)),按照总分从高到低存入文本文件
分析: 	
a.创建一个学生类: 姓名,语文成绩(chineseScore),数学成绩(mathScore),英语成绩(englishScore)
b.因为要排序,所以需要选择TreeSet进行存储学生对象
c.键盘录入学生信息,把学生信息封装成一个学生对象,在把学生对象添加到集合中
d.创建一个高效的字符输出流对象
e.遍历集合,把学生的信息写入到指定的文本文件中
f.释放资源
//学生类
public class Student implements Comparable {
     
    private String name;
    private int chineseScore;
    private int mathScore;
    private int englishScore;
    private int totalScore;

    public Student() {
     
        this.name = name;
        this.chineseScore = chineseScore;
        this.mathScore = mathScore;
        this.englishScore = englishScore;
        this.totalScore = totalScore;
    }

    public String getName() {
     
        return name;
    }

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

    public int getChineseScore() {
     
        return chineseScore;
    }

    public void setChineseScore(int chineseScore) {
     
        this.chineseScore = chineseScore;
    }

    public int getMathPerScore() {
     
        return mathScore;
    }

    public void setMathPerScore(int mathPerScore) {
     
        this.mathScore = mathPerScore;
    }

    public int getEnglishScore() {
     
        return englishScore;
    }

    public void setEnglishScore(int englishScore) {
     
        this.englishScore = englishScore;
    }

    public int getTotalScore() {
     
        return totalScore;
    }

    public void setTotalScore(int totalScore) {
     
        this.totalScore = totalScore;
    }

    @Override
    public String toString() {
     
        return "Student{" +
                "name='" + name + '\'' +
                ", chineseScore=" + chineseScore +
                ", mathPerScore=" + mathScore +
                ", englishScore=" + englishScore +
                ", totalScore=" + totalScore +
                '}';
    }
    @Override
    public int compareTo(Object o) {
     
        Student s = (Student) o;

        int num = this.getTotalScore() > s.getTotalScore() ? -1 : 1;

        return num;
    }
}
//测试类
public class Test {
     
    public static void main(String[] args)throws IOException {
     

        TreeSet<Student> set = new TreeSet<>();
        BufferedWriter bw = new BufferedWriter(new FileWriter("成绩.txt"));

        for (int i = 0; i < 2; i++) {
     
            Student s = new Student();

            System.out.println("请输入第"+(i+1)+"个学生姓名:");
            Scanner sc1 = new Scanner(System.in);
            String s1 = sc1.nextLine();
            s.setName(s1);

            System.out.println("请输入"+s.getName()+"的语文成绩:");
            Scanner sc2 = new Scanner(System.in);
            int i1 = sc2.nextInt();
            s.setChineseScore(i1);

            System.out.println("请输入"+s.getName()+"的数学成绩:");
            Scanner sc3 = new Scanner(System.in);
            int i2 = sc3.nextInt();
            s.setMathPerScore(i2);

            System.out.println("请输入"+s.getName()+"的英语成绩:");
            Scanner sc4 = new Scanner(System.in);
            int i3 = sc4.nextInt();
            s.setEnglishScore(i3);

            s.setTotalScore(s.getChineseScore()+s.getMathPerScore()+s.getEnglishScore());

            set.add(s);
        }

        bw.write("学生成绩表如下:");
        bw.newLine();
        bw.flush();
        bw.write("姓名 语文成绩 数学成绩 英语成绩 总分");
        bw.newLine();
        bw.flush();
        for (Student student : set) {
     
            StringBuilder sb = new StringBuilder();
            sb.append(student.getName()).append(" ").append(student.getChineseScore()).
                    append("        ").append(student.getMathPerScore()).append("       ").
                    append(student.getEnglishScore()).append("        ").append(student.getTotalScore());
            bw.write(sb.toString());
            bw.newLine();
            bw.flush();
        }
    }
}

你可能感兴趣的:(IO流,java,面向对象编程)