JavaSE进阶九 IO流一

1,IO流的概述

  • IO流,什么是IO?

      I:Input
      O:Output
      通过IO可以完成硬盘文件的读和写。
    
  • IO流的分类(多种分类方式:)?

    • 1,按照流的方向进行分类,以内存作为参照物:
      • 往内存中去:叫做输入(Input),或者叫做读(Read)。
      • 从内存中出来:叫做输出(Output),或者叫做写(Write)。
    • 2,按照读取数据方式不同进行分类:
      • 有的流按照字节的方式读取数据,一次读取1一个字节byte,等同一次读取8个二进制位。 这种流是万能的,什么类型的文件都可以读取。包括:文本文件、图片、声音文件、视频文件等...

      • 有的流是按照字符的方式读取数据的,一次读取一个字符,这种流是为了方便读取普通文本文件而
        存在的,这种流不能读取:图片、声音、视频等...;只能读取纯文本文件,连word文件都无法读取。

      • 综上所述流的分类:

         输入流、输出流;
         字节流、字符流
        
  • IO流的四大家族:(四大首领)

       java.io.InputStream 字节输入流
       java.io.OutputStream 字节输出流
       java.io.Reader 字符输入流
       java.io.Writer 字符输出流
    
    • 四大首领都是抽象类。(abstract class)
  • 所有的流都实现了:

      java.io.Closeable接口,都是可关闭的,都有close()方法。
      流毕竟是一个管道,这个是内存和硬盘支架的通道,用完之后一定要关闭,
      不然会耗费(占用)很多资源。养成好习惯:用完流一定要关闭。
    
  • 所有的输出流都实现了:

      java.io.Flushable接口,都是可刷新的,都有flush()方法;
      输出流在最终输出之后,一定要记得flush()刷新一下。这个刷新表示将通道/管道当中剩余
      未输出的数据强行输出完(清空管道)!刷新的作用就是清空管道。
    
  • 在java中只有类名以"Stream"结尾的都是字节流,以"Reader/Writer"结尾的都是字符流。

  • java.io包下需要掌握的流有16个:

      文件专属:
          java.io.FileInputStream
          java.io.FileOutputStream
          java.io.FileReader
          java.io.FileWriter
    
      转换流:(将字节流转换成字符流)
          java.io.InputStreamReader
          java.io.OutputStreamWriter
    
      缓存流专属:
          java.io.BufferedReader
          java.io.BufferedWriter
          java.io.BufferedInputStream
          java.io.BufferedOutputStream
    
      数据专属:
          java.io.DataInputStream
          java.io.DataOutputStream
    
      标准输出流:
          java.io.PrintWriter
          java.io.PrintStream
    
      对象专属流:
          java.io.ObjectInputStream
          java.io.ObjectOutputStream
    

2,文件字节输入流(FileInputStream)

  • java.io.FileInputStream

    • 文件字节输入流,万能的,任何类型的文件都可以采用这个流来读。
    • 字节的方式,完成输入的操作,完成读的操作(硬盘---> 内存)
  • java.io.FileInputStream常用方法

      int read(); // 读取字节数据
      int available() // 返回值当中剩余的没有读到的字节数量
      long skip(long n) // 跳过几个字节不读
    

代码示例:

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

public class FileInputStreamTest01 {
    public static void main(String[] args) {
        // 创建文件字节输入流对象
        FileInputStream file = null;
        FileInputStream file2 = null;
        FileInputStream file3 = null;
        try {
            // 绝对路径: /Users/a1/Desktop/Java/Simon_JavaSE/JavaTest/src/temp
            // 相对路径:  src/temp
            file = new FileInputStream("src/temp");

            // 读取流数据

            // 一个字节一个字节的读取
            int data =  0;
            while (data != -1){ // 读取到文件的末尾了,在读的时候读取不到任何数据,返回-1
                data =  file.read(); // 这个方法读取的是"字节"本身
                System.out.println(data); //
            }

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

            file2 = new FileInputStream("src/temp");

            // 采用byte数组,一次读取多个字节;最多读取"数组.length"个字节
            byte[] bytes = new byte[4]; //定义一个长度为4的byte数组,一次读取4个字节

            int byteData = 0;
            while ((byteData = file2.read(bytes)) != -1){
                // 这个方法的返回值是:读取到字节的数量(不是字节本身)
                System.out.println(byteData);// 4 2
                // 将字符数组全部装换成字符串
                // System.out.println(new String(bytes));// abcd  efcd
                // 不应该全部转换应该读取多少个字符,转换多少个
                System.out.println(new String(bytes,0,byteData)); //abcd  ef
            }

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

            file3 = new FileInputStream("src/temp");
            // 先读1个字节
            int readByte = file3.read();
            System.out.println(readByte);

            System.out.println("还剩下几个字节未读:" + file3.available());
            // 跳过2个字节不读
            file3.skip(2);
            System.out.println("还剩下几个字节未读:" + file3.available());

            // 读取字节数据
            System.out.println(file3.read());

        }catch (FileNotFoundException e){
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 在finally语句块中确保流一定被关闭
            if (file != null){ // 关闭流的前提是:流不为空;流为空没必要关闭。
                try {
                    file.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
    }
}

3,文件字节输出流(FileOutputStream)

  • java.io.FileInputStream
    • 文件字节输出流,负责写;从内存到硬盘
代码示例
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputStreamTest01 {
    public static void main(String[] args) {
        FileOutputStream fos = null;
        FileOutputStream fos2 = null;
        try {
            // myFile文件不存在的时候会自动新建!
            // 这种方式谨慎使用,会将原文件内容情况再重新写入
            // fos = new FileOutputStream("myFile");

            // 以追加的方式在文件末尾写入,不会清空原文件内容。
            fos = new FileOutputStream("myFile",true);

            // 开始写入
            byte[] bytes = {97,98,99,100};
            //将byte数组全部写出
            fos.write(bytes);// abcd
            fos.write(bytes,0,2); //将byte数组的一部分写出,再写ab

            // 字符串
            String s = "我是一个中国人,我很骄傲!!!";
            byte[] bs = s.getBytes();
            // 将字符串转换成byte数组。
            // 写
            fos.write(bs);

            // 写完之后,一定要进行刷新
            fos.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos != null){
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}

4,使用FileInputStream和FileOutputStream完成文件的拷贝

  • 拷贝的过程是一边读,一边写
  • 使用以上的字节流拷贝文件的时候,文件类型随意,万能的;什么样的文件都能拷贝。
demo示例
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class CopyTest01 {
    public static void main(String[] args) {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            // 创建一个输入流对象  拷贝对象地址
            fis = new FileInputStream("/Users/a1/Desktop/1620637732904119.mp4");
            // 创建一个输出流对象   拷贝到哪里(地址)
            fos = new FileOutputStream("/Users/a1/Desktop/Java/Simon_Java/src/1620637732904119-copy.mp4");
            byte[] bytes = new byte[1024 * 1024]; // 1M(一次读取1M)

            int readCount = 0;
            while ((readCount = fis.read(bytes)) != -1){
                fos.write(bytes,0,bytes.length);
            }

            // 刷新输出流
            fos.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 分开try,不要一起try;
            // 一起的时候,其中一个出现异常,可能会影响另一个流的关闭。
            if (fis != null){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fos != null){
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

5,FileReader和FileWriter

  • FileReader:
    • 文件字符输入流,只能读取普通文本。
    • 读取文本内容时,比较方便,快捷。
  • FileWriter:
    • 文件字符输出流,写。
    • 只能输出普通文本
代码示例
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class FileReaderWriterTest {
    public static void main(String[] args) {
        FileReader reader = null;
        FileWriter writer = null;

        FileReader readerCopy = null;
        FileWriter writerCopy = null;
        try {

            // ---------------------------FileReader------------------------------------------------
            // 创建文件字符输入流
            reader = new FileReader("src/temp");
            // 开始读
            char[] chars = new char[4]; // 一次读取四个字符
            int readCount = 0;
            while ((readCount = reader.read(chars)) != -1){
                System.out.print(new String(chars,0, readCount));
            }

            // ---------------------------FileWriter------------------------------------------------
            // 创建文件字符输出流
            // 这种方式会将原文件内容情况再重新写入
            // writer = new FileWriter("src/temp3");

            //不清空原文件写法
            writer = new FileWriter("src/temp3",true);

            // 开始写入
            char[] chars1 = {'我','是','中','国','人'};
            writer.write(chars1);
            writer.write(chars1,2,3);
            // 字符串写入
            writer.write("我在学习java");
            // 写入换行符
            writer.write("\n");
            writer.write("我换行了");
            // 写入之后刷新
            writer.flush();

            // ------------------FileReader---And---FileWriter---------------------------------------
            // 使用FileReader和FileWriter进行拷贝,只能拷贝普通文本文件
            // 读
            readerCopy = new FileReader("src/temp3");
            // 写
            writerCopy = new FileWriter("src/com/javase/ioflow/temp3-copy");

            // 一边读一边写
            char[] chars2 = new char[1024 * 512]; // 1MB
            int readerCount = 0;
            while ((readerCount = readerCopy.read(chars2)) != -1){
                writerCopy.write(chars2,0,readerCount);
            }
            // 刷新
            writerCopy.flush();

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

    }
}

6,BufferedReader和InputStreamReader

  • BufferedReader:
    • 带有缓冲区的字符输入流。
    • 使用这个流的时候不需要自定义char数组、byte数组;自带缓冲。
  • InputStreamReader转换流:
    • 把字节流转换成字符流
代码示例
import java.io.*;

public class BufferedReaderTest {
    public static void main(String[] args) {
        FileReader reader = null;
        BufferedReader br = null;
        FileInputStream fin = null;
        InputStreamReader red = null;
        try {

            // 当一个流的构造方法中需要另一个流的时候,这个被传进来的流叫做:节点流。
            // 外部负责包装的这个流,叫做:包装流 或 处理流

            // --------------------------------------------------
            // 只能传字符流,不能传字节流。
            // reader = new FileReader("src/temp3");
            // BufferedReader只能传字符流,不能传字节流
            // red是节点流,br是包装流
            // br = new BufferedReader(reader);

            // ---------InputStreamReader转换流----------------------------------------
            // 字节流
            fin = new FileInputStream("src/temp3");
            // 把字节流转换成字符流
            red = new InputStreamReader(fin);
            br = new BufferedReader(red);

            // 读
            String sLine = null;
            // readLine方法读取一个文本行,但不带换行符。
            while ((sLine = br.readLine()) != null){
                System.out.println(sLine);
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭流
            // 对于包装流来说,只要关闭最外层流就行,里面的节点流会自动关闭。
            if (br != null){
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

7,BufferedWriter和OutputStreamWriter

  • BufferedWriter:
    • 带有缓冲的字符输出流
  • OutputStreamWriter转换流:
    • 把字节流转换成字符流
代码示例
import java.io.*;

public class BufferedWriterTest {
    public static void main(String[] args) {
        BufferedWriter bw = null;

        try {
            // 带有缓冲区的字符输出流
            // bw = new BufferedWriter(new FileWriter("temp"));

            // 使用OutputStreamWriter转换流的写法
            bw =  new BufferedWriter(new OutputStreamWriter(new FileOutputStream("temp",true)));

            // 写
            bw.write("hello java");
            bw.write("hello word");
            bw.write("\n");
            bw.write("hello kitty");

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

8,DataOutputStream和DataInputStream

  • DataOutputStream:数据专属输出流:

    • 这个流可以将数据连同数据类型一并写入文件
    • 注意:这个文件不是普通文本文档。(这个文件使用记事本打不开)
  • DataInputStream:数据专属输入流:

    • DataOutputStream写的文件,只能使用DataInputStream去读,并且读的时候需要提前知道写入的顺序。
    • 读的顺序需要和写的顺序一致,才能正常取出数据
代码示例
import java.io.*;
public class DataOutputStreamTest {
    public static void main(String[] args) {
        DataOutputStream dos = null;
        DataInputStream dis = null;
        try {
            // 创建数据专属的字符输出流
            dos = new DataOutputStream(new FileOutputStream("src/com/javase/ioflow/data"));

            // 写入数据
            byte b = 100;
            short s = 200;
            int i = 300;
            long l = 400L;
            float f = 3.0f;
            double d = 3.14;
            boolean sex = true;
            char c = 'a';
            // 写  把数据以及数据类型一并写入到文档当中
            dos.writeByte(b);
            dos.writeShort(s);
            dos.writeInt(i);
            dos.writeLong(l);
            dos.writeFloat(f);
            dos.writeDouble(d);
            dos.writeBoolean(sex);
            dos.writeChar(c);

            // 刷新
            dos.flush();

            //  -------------------------------------------------------------------------------------------
            // 创建数据专属的字符输入流
            dis = new DataInputStream(new FileInputStream("src/com/javase/ioflow/data"));
            // 读取数据
            byte bd = dis.readByte();
            short sd = dis.readShort();
            int id = dis.readInt();
            long ld = dis.readLong();
            float fd = dis.readFloat();
            double dd = dis.readDouble();
            boolean sexd = dis.readBoolean();
            char cd = dis.readChar();
            // 输出
            System.out.println(bd);
            System.out.println(sd);
            System.out.println(id + 1000); //1300
            System.out.println(ld);
            System.out.println(fd);
            System.out.println(dd);
            System.out.println(sexd);
            System.out.println(cd);

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

9,标准的字节输出流PrintStream

  • PrintStream标准的字节输出流:
    • 默认输出到控制台。
    • 标准输出流不需要手动close()关闭。
代码示例
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) throws FileNotFoundException {
        // 联合起来写
        System.out.println("hello PrintStream");

        // 分开写
        // 创建标准的字节输出流对象
        PrintStream ps = System.out;
        // 输出到控制台
        ps.println("hello Word");
        ps.println(123);
        ps.println(true);

        // 标准输出流不需要手动close()关闭

        //---------------------------------------------------------------------------------
        // 改变标准输出流的输出方向
        // 标准输出流不再指向控制台,指向"Log"文件
        PrintStream printStream = new PrintStream(new FileOutputStream("src/com/javase/ioflow/Log"));
        // 修改输出方向,将输出方向修改到"Log"文件
        System.setOut(printStream);

        // 再输出
        System.out.println("hello Word");
        System.out.println("hello Kitty");
        System.out.println("hello Java");

        //---------------------------------------------------------------------------------
        // 调用log工具类
        LogFileUtil.log("这里打印了一个log日志");
        LogFileUtil.log("这里打印了一个登录log日志");

    }
}

// 定义一个log工具类
class LogFileUtil{
    // 记录日志的方法
    public static void log(String msg){
        // 标准输出流不再指向控制台,指向一个日志文件
        PrintStream printStream = null;
        try {
            printStream = new PrintStream(new FileOutputStream("src/com/javase/ioflow/LogFile",true));
            // 改变输出方向
            System.setOut(printStream);
            // 获取当前时间
            Date nowTime = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
            String strTime = sdf.format(nowTime);

            System.out.println(strTime + ":" + msg);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        // 修改输出方向,将输出方向修改到"Log"文件
        System.setOut(printStream);
    }
}

上篇:JavaSE进阶八 集合二 Map接口

下篇:JavaSE进阶九 IO流二

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容