Java进阶第八章——I/O流:常用流

I/O流

1.I/O流概述

  • 输入流:从硬盘读到内存中,或者叫输入,读(Read)、输入(Input)、输入流(InputStream)。

    输出流:从内存写到硬盘中,或者叫输出,写(Write)、输出(Output)、输出流(OutputStream)。

  • 字节流:按照字节读取数据,一次读取1个字节Byte,等同于一次读取8个二进制。这种流是万能的,什么类型文件都可以读取。包括:文本文件、图片、声音文件等。

    字符流:按照字符读取数据,一次读取一个字符,这种流方便读取普通文本。只能读取纯文本文件,无法读取word文件,因为word文件有格式。

  • Java中所有流都在:java.io.*;

  • Java中的IO流(都是抽象类):

    字节输入流(万能的):java.io.InputStream

    字节输出流(万能的):java.io.OutputStream

    字符输入流(只能处理纯文本文件):java.io.Reader

    字符输出流(只能处理纯文本文件):java.io.Writer

    类名以“Stream”结尾是字节流,以“Reader/Writer”结尾是字符流。

  • Java中所有流都实现了java.io.Closeable接口,都是可关闭的,都有close()方法。流是内存和硬盘之间的通道,用完之后要关闭,否则会占用资源。

    所有的输出流都实现了java.io.Flushable接口,都是可刷新的,都有flush()方法。输出流在最终输出后,一定要用flush()刷新一下,清空管道。如果没有flush可能会丢失数据。

  • 常用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

  • FileInputStream:文件字节输入流,万能的,任何类型的文件都可以采用这个流来读。

  • 字节方式:从硬盘到内存完成输入操作,完成读操作。

  • 在D/study路径下创建了temp.txt文件,文件中内容:abcdef

public class FileInputStreamTest {
    public static void main(String[] args) {
        FileInputStream fis = null;
        //创建文件字节输入流对象
        try {
            //采用绝对路径方式
             fis = new FileInputStream("D:\\study\\temp.txt");
            //FileInputStream有抛出异常,所以要try/catch
            //FileInputStream fis = new FileInputStream("D:/study/temp");  写成"/"也可以
            int readData = -1;
            while ((readData = fis.read()) != -1){
                //读取一次指针指向下一个字符
                System.out.printf(readData + " "); //97 98 99 100 101 102
            }
            System.out.println();
            System.out.println(fis.read());  //读取不到字符返回-1
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            //在finally语句块中,确保流一定关闭
            if (fis != null) {
                //流是null时没必要关闭。
                try {
                    fis.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
  • 为了减少硬盘和内存的交互,提高程序的执行效率,在byte[]数组当中读:int read(byte[] b)
public class FileInputStreamTest {
    public static void main(String[] args) {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("D:\\study\\temp.txt");

            //开始读,采取byte数组,一次读取多个字节,最多读取“数组.length”个字节
            byte[] bytes = new byte[4];//准备一个4个长度的byte数组
            //int read(byte[] b) 返回的是读取到的字节数量,不是字节本身。
            int readCount = fis.read(bytes);
            System.out.println(readCount);  //第一次读到了4个字节,返回:4
            //String(byte[] bytes) 能够将byte数组转成字符串
            System.out.println(new String(bytes));  //abcd
            //String(byte[] bytes,int offset,int length)  能够将byte数组中起始位置为offset,长度为length转为字符串
            System.out.println(new String(bytes,0,readCount));  //abcd

            readCount = fis.read(bytes);
            System.out.println(readCount);  //第二次继续读,只读到2个字节,返回:2
            //第二次读取的时候,读取到两个字节,只覆盖了前面两个字节
            System.out.println(new String(bytes));  //efcd
            System.out.println(new String(bytes,0,readCount));//ef

            readCount = fis.read(bytes);
            System.out.println(readCount);  //第三次继续读,没读到字节,返回:-1
            //第三次读取的时候,没有覆盖任何字节
            System.out.println(new String(bytes));  //efcd

        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
  • 一次性读取所有字符
public class FileInputStreamTest {
    public static void main(String[] args) {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("D:\\study\\temp.txt");
            //开始读,采取byte数组,一次读取多个字节,最多读取“数组.length”个字节
            byte[] bytes = new byte[4];//准备一个4个长度的byte数组
            int readCount = 0;
            while ((readCount= fis.read(bytes)) != -1){
                System.out.print(new String(bytes,0,readCount));  //abcdef
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
  • FileInputStream其他常用方法:

    返回流当中剩余还没读到的字节数:int avaiable()

    跳过几个字节不读:long skip(long n)

public class FileInputStreamTest03 {
    public static void main(String[] args) {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("D:\\study\\study4\\study4\\tempfile");
            //总字节数量
            System.out.println("总字节数量:" + fis.available());  //总字节数量:6
            //读一个字节
            //int readCount = fis.read();
            //System.out.println("剩下多少个字节没有读:" + fis.available()); 剩下多少个字节没有读:5

            //byte[] bytes = new byte[fis.available()]; //这种方式不适用于大文件,因为byte数组不能太大。
            //int readCount = fis.read(bytes);//6
            //System.out.println(new String(bytes));  //abcdef

            fis.skip(3);  //跳过3个字节
            System.out.println(fis.read());  //100
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

3.文件专属FileOutputStream

  • 文件字节输出流,负责写,从内存到硬盘。
  • 使用write写入文件,并且在new文件时会清空文件。
public class FileOutputStreamTest {
    public static void main(String[] args) {
        FileOutputStream fos = null;
        try {
            //temptest文件不存在时会新建,有文件时会清空文件重新写。
            fos = new FileOutputStream("D:\\study\\study4\\study4\\temptest");
            //开始写
            byte[] bytes = {97,98,99,100};
            //将byte数组全部写出
            fos.write(bytes);  //abcd
            fos.write(bytes,0,2); //在写入ab

            //写完之后一定要刷新
            fos.flush();
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
  • 若不想清空文件想直接在文件结尾插入,在new文件时候需要加true。并且需要加入String字符串时,需要将String字符串转成byte数组。
public class FileOutputStreamTest01 {
    public static void main(String[] args) {
        FileOutputStream fos = null;
        try {
            //在路径后面加true表示在文件末尾写入数据
            fos = new FileOutputStream("D:\\study\\study4\\study4\\temptest",true);
            //开始写
            //写入一个String字符串
            String s = "来杯冰美式";
            byte[] bs = s.getBytes();
            fos.write(bs);

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

4.字节输入/输出流实现文件复制

  • 文件复制:一个文件复制到另一个路径,需要经过内存。内存通过输入流读入数据,通过输出流输出数据。
public class CopyTest {
    public static void main(String[] args) {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            //新建一个字节输入流
            fis = new FileInputStream("C:\\Users\\Administrator\\Desktop\\谢沛民\\JAVA零基础\\2面向对象—匿名内部类.md");
            //新建一个字节输出流
            fos = new FileOutputStream("C:\\Users\\Administrator\\Desktop\\2面向对象—匿名内部类.md");

            //核心的一边读一边写
            byte[] bytes = new byte[1024 * 1024];  //1024字节=1KB  1024*1024字节=1MB
            int readCount = 0;
            while ((readCount= fis.read(bytes)) != -1){
                fos.write(bytes,0,readCount);
            }

            //输出流最后要刷新
            fos.flush();
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            //两个try/catch分开,否则有一个出现异常会影响另一个流关闭
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            if(fos != null){
                try {
                    fos.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

5.文件专属FileReader

  • 文件字符输入流,只能读取普通文本,读取文本内容时,比较方便快捷。无法读取其他文件格式,包括word文件。
  • FileReader调用方法与FileInputStream类似,只需要将byte数组换成char数组。
public class FileReaderTest01 {
    public static void main(String[] args) {
        FileReader reader = null;
        try {
            //创建文件字符输入流
            reader = new FileReader("D:\\study\\study4\\study4\\tempfile");
            //开始读
            char[] chars = new char[4]; //一次读取4个字符
            int readCount = 0;
            while((readCount=reader.read(chars)) !=-1){
                System.out.printf(new String(chars,0,readCount) + " ");   //abcd ef 
            }

        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

6.文件专属FileWriter

  • 文件字符输出流,只能写出普通文本,写出文本内容时,比较方便快捷。无法读取其他文件格式,包括word文件。
  • FileReader调用方法与FileOutputStream类似,只需要将byte数组换成char数组。
public class FileWriterTest {
    public static void main(String[] args) {
        FileWriter out = null;
        try {
            //创建文件字符输出流对象
            out = new FileWriter("D:\\study\\study4\\study4\\file");
            //开始写
            char[] chars = {'来','杯','冰','美','式'};
            out.write(chars);
            out.write(chars,2,3);
            out.write("\n"); //这是插入一个换行符“\n”
            out.write("这是咖啡加点ice的学习笔记");

            out.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

7.纯文本的文件拷贝

  • 纯文件复制:一个文件复制到另一个路径,需要经过内存。内存通过字符输入流读入数据,通过字符输出流输出数据。
public class CopyTest {
    public static void main(String[] args) {
        FileReader frer = null;
        FileWriter fwer = null;
        try {
            frer = new FileReader("D:\\study\\study4\\study4\\file");
            fwer = new FileWriter("C:\\Users\\Administrator\\Desktop\\file");

            int readCount = 0;
            char[] chars = new char[1024];
            while((readCount= frer.read(chars))!=-1){
                fwer.write(chars,0,readCount);
            }

            fwer.flush();
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (frer != null) {
                try {
                    frer.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            if (fwer != null){
                try {
                    fwer.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }

        }
    }
}

8.缓冲流专属BufferedReader

  • BufferedReader:带有缓冲区的字符输入流。使用这个流不需要自定义char数组或byte数组,自带缓冲。

  • BufferedReader构造方法:BufferedReader(Reader in)

    这个构造方法需要一个流,被传递进来的流叫做:节点流。

    外部负责包装的流叫做:包装流/处理流。

  • 读一行方法(不带换行符):readLine()

public class BufferedReaderTest {
    public static void main(String[] args) throws IOException {
        //这里的FileReader作为一个节点流
        FileReader reader = new FileReader("D:\\study\\study4\\study4\\file");
        //BufferedReader作为包装流/处理流
        BufferedReader br = new BufferedReader(reader);

        //读一行方法(不带换行符):readLine()
        String s = null;
        while ((s=br.readLine()) != null){
            System.out.println(s);
        }
        
        //关闭流只需要关闭外边的包装流,里边的节点流会自动关闭
        br.close();
    }
}
  • BufferedReader只能传入一个字符流,不能传入一个字节流。需要用到java.io.InputStreamReader进行流转换。
public class BufferedReaderTest {
    public static void main(String[] args) throws IOException {
        //字节流
        //FileInputStream in = new FileInputStream("D:\\study\\study4\\study4\\file");
        //通过转换流将字符流转换为字符流
        // InputStreamReader reader = new InputStreamReader(in);
        //BufferedReader只能传一个字符流,不能传字节流。
        // BufferedReader br = new BufferedReader(reader);

        //将以上合并
        BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("D:\\study\\study4\\study4\\file")));

        String line = null;
        while((line=br.readLine())!=null){
            System.out.println(line);
        }

        //只需要关闭最外层
        br.close();
    }
}

9.缓冲流专属BufferedWriter

  • BufferedWriter:带有缓冲区的字符输出流。
public class BufferedWriterTest {
    public static void main(String[] args) throws IOException {
        //BufferedWriter out = new BufferedWriter(new FileWriter("D:\\study\\study4\\study4\\file"));
        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("D:\\study\\study4\\study4\\file")));
        out.write("咖啡哪有生活苦");
        out.write("\n");
        out.write("来杯冰美式");
        out.write("\n");
        out.write("这是咖啡加点ice的学习笔记");
        //刷新
        out.flush();
        //关闭最外层流
        out.close();
    }
}

10.数据流专属DataOutputStream

  • DataOutputStream:数据专属得流,这个流可以将数据连同数据类型一并写入文件。

    注意:这个文件不是普通的文本文档,用记事本打不开

public class DataOutputStreamTest {
    public static void main(String[] args) throws Exception{
        //创建数据专属字节输出流
        DataOutputStream dos = new DataOutputStream(new FileOutputStream("D:\\study\\study4\\study4\\dataout"));
        //写数据
        byte b = 100;
        short s = 200;
        int i = 300;
        long l = 400l;
        float f = 3.0f;
        double d = 3.14;
        boolean sex = false;
        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();
        //关闭流
        dos.close();
    }
}

11.数据流专属DataInputStream

  • 通过DataOutputStream写入的文件,只能使用DataInputStream读,并且需要知道写入的顺序,读的顺序需要与写入顺序一致才能正常取出数据。
public class DataInputStreamTest {
    public static void main(String[] args) throws Exception{
        DataInputStream dis = new DataInputStream(new FileInputStream("D:\\study\\study4\\study4\\dataout"));
        //开始读
        //如果读的顺序不一样,会发生乱码
        System.out.println(dis.readByte());
        System.out.println(dis.readShort());
        System.out.println(dis.readInt() + 1000);
        System.out.println(dis.readLong());
        System.out.println(dis.readFloat());
        System.out.println(dis.readDouble());
        System.out.println(dis.readBoolean());
        System.out.println(dis.readChar());
    }
}

12.标准流PrintStream

  • PrintStream:标准的字节输出流,默认输出到控制台。
public class PrintStreamTest {
    public static void main(String[] args) throws Exception{
        //联合起来写
        System.out.println("咖啡加ice");  //咖啡加ice
        //分开写
        PrintStream ps = System.out;
        ps.println("生活哪有咖啡苦");  //生活哪有咖啡苦

        //标准输出流不需要手动close关闭
        //改变标准输出流的输出方向
        //标准输出流不再指向控制台,指向log文件,修改输出方向为log文件。
        System.setOut(new PrintStream(new FileOutputStream("log",true)));
        System.out.println("来杯冰美式");
        System.out.println("咖啡哪有生活苦");
    }
}
  • 编写日志工具类
public class logger {
    public static void log(String msg){

        try {
            PrintStream out = new PrintStream(new FileOutputStream("log.txt",true));
            //改变输出方向
            System.setOut(out);
            //设置日期
            Date now = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
            String strTime = sdf.format(now);
            //打印日志
            System.out.println(strTime + ":" +msg);

        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
}
  • 测试日志工具类
public class LogTest {
    public static void main(String[] args) {
        logger.log("测试一下打印日志工具类");
    }
}

//log.txt文件下内容:
//2024-01-18 11:00:05 644:测试一下打印日志工具类

——本章节为个人学习笔记。学习视频为动力节点Java零基础教程视频:动力节点—JAVA零基础教程视频

你可能感兴趣的:(咖啡ice的Java学习记录,java,开发语言)