美文网首页
JavaSE进阶-06-IO流

JavaSE进阶-06-IO流

作者: 努力学习的lfk | 来源:发表于2021-11-16 15:55 被阅读0次

    1.什么是IO流?

    答:文件的输入和输出
      将文件放入内存的过程叫输入(Input)也称为读(Read),
    输入过程产生的数据的流动叫输入流(InputStream)。

      将文件从内存 存放到硬盘的过程叫输出(Output)也称为写(Write),
    输出过程产生的数据的流动叫输出流(OutputStream)。

    通过IO可以完成硬盘文件的读和写。

    2.IO流的分类

    2.1按照流的方向进行分类:

    以内存作为参照物
     往内存中去,叫做输入(Input),或者叫做读(Read)
     从内存出来,叫做输出(Output),或者叫做写(Write)

    2.2按照读取数据方式不同:

     按照字节的方式读取数据,一次读取1个字节byte,等同于一次读取8个二进制位。这种流是万能的,什么类型都可以读取。包括:文本文件、图片、音频文件、视频文件......
    这种流叫字节流
      假设文件filel.txt,采用字节流的话是这样读的:
    a中国bc张三fe
    第一次读:一个字节,正好读到‘a’
    第二次读:一个字节,正好读到‘中’字符的一半
    第三次读:一个字节,正好读到‘中’字符的另一半

     按照字符的方式读取数据,一次读取一个字符。这种流是为了方便读取普通的文本文件而存在的,不能读取:图片、音频、视频等文件。只能读取纯文本文件。(work文件有格式,不是普通文件.txt,故word文件也无法读取。注意能用记事本编辑的都是文本文件
    这种流叫字符流
      假设文件filel.txt,采用字节流的话是这样读的:
    a中国bc张三fe
    第一次读:一个字符,正好读到‘a’
    第二次读:一个字符,正好读到‘中’字符
    第三次读:一个字符,正好读到‘国’字符

    ‘a’英文字母,在Windows操作系统中占1个字节;但是‘a’字符在java中占用2个字节。
    ‘中’字符在Windows系统中占用2个字节。

    综上所述

    流的分类:
    输入流、输出流
    字节流、字符流

    3.Java IO流

    java中所有流都是在java.io.*
    主要研究如何new流对象,调用流对象的哪个方法是读,哪个方法是写。

    Java IO四大家族(都是抽象类)
    java.io.InputStream:字节输入流
    java.io.OutputStream:字节输出流
    java.io.Reader:字符输入流
    java.io.Writer:字符输出流
    在java中只要类名以Stream结尾都是字节流,以Reader/Writer结尾的都是字符流

    所有流都实现了:java.io.Closeable接口,都是可关闭的,都有close()方法。
    养成好习惯:流是内存和硬盘之间的通道,用完后一定要关闭,不然会占用很多内存。

    所有输出流都实现了:java.io.Flushable接口,都是可刷新的,都有flush()方法。
    养成好习惯:输出流在最终输出之后,一定能更要flush()刷新一下。(表示将通道/管道当中剩余未输出的数据强行输出完,即清空管道。)

    4.Java 需要掌握的16个IO流

    文件专属
    java.io.FileInputStream掌握
    java.io.FileOutputStream掌握
    java.io.FileReader
    java.io.FileWriter

    转换流(将字节流转换成字符流)
    java.io.InputStreamReader
    java.io.OutputStreamWriter

    缓冲流
    java.io.BufferedInputStream
    java.io.BufferedOutputStream
    java.io.BufferedReader
    java.io.BufferedWriter

    数据流
    java.io.DataInputStream
    java.io.DataOutputStream

    标准输出流
    java.io.PrinfWriter
    java.io.PrintStream掌握

    对象专属流
    java.io.ObjectInputStream掌握
    java.io.ObjectOutputStream掌握

    文件专属流

    4.1 java.io.FileInputStream(重点掌握)

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

    4.1.1 read()
    package com.bjpowernode.java.io;
    
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    
    public class FileInputStreamTest01 {
        public static void main(String[] args) {
            FileInputStream fileInputStream=null;
            try {
                //创建文件字节流输入流对象
                //文件路径:G:\大4上学期\实习\JavaSE\temp(IDEA会自动把\变成\\,因为java中\表示转译,把\\替换成/也可以。)
                fileInputStream=new FileInputStream("G:\\大4上学期\\实习\\JavaSE\\temp");
    
                //开始读
                int read = fileInputStream.read();//这个方法的返回值是:读取到的“字节”本身
                System.out.println(read);//97
    
                read = fileInputStream.read();//98
                System.out.println(read);
    
                read = fileInputStream.read();//99
                System.out.println(read);
    
                read = fileInputStream.read();//100
                System.out.println(read);
    
                read = fileInputStream.read();//101
                System.out.println(read);
    
                read = fileInputStream.read();//102
                System.out.println(read);
    
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                //关闭字节数入流对象
                if (fileInputStream != null) {
                    //关闭流的前提是:流不是空,流是null没必要关闭
                    try {
                        fileInputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
    
            }
        }
    }
    


    问题:该例中使用read(),存在代码冗余,可采用循环的方式读取:

    package com.bjpowernode.java.io;
    
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    
    public class FileInputStreamTest02 {
        public static void main(String[] args) {
            FileInputStream fileInputStream=null;
    
            try {
                //创建字节输出流对象
                fileInputStream=new FileInputStream("G:\\大4上学期\\实习\\JavaSE\\temp");
                //读
                /*while (true){
                    int read=fileInputStream.read();
                    if (read == -1) {
                        break;
                    }
                    System.out.println(read);
                }*/
                //改造while循环
                int read=0;
                while((read=fileInputStream.read()) != -1){
                    System.out.println(read);
                }
    
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                //释放字节输出流对象
                if (fileInputStream != null) {
                    try {
                        fileInputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    
        }
    }
    

    4.1.2 read(byte[] b)

    问题read()使用循环读取后,存在效率低的问题。一次才读一个字节,硬盘与内存交互太频繁。改进方案:使用read(byte[] b)


    将数组转换成String

    注意
     开始读,采用byte数组,一次读取多个字节。最多读取“数组.length”个字节
     这个方法的返回值:读到的字节数量,不是字节本身。

    package com.bjpowernode.java.io;
    
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    
    /*
    int read(byte[] b)
        一次最多读取b.length个字节。
        减少硬盘和内存的交互,提高程序的执行效率。
    */
    public class FileInputStreamTest03 {
        public static void main(String[] args) {
            FileInputStream fileInputStream=null;
            try {
                //创建字节输出流对象
                //使用相对路径,一定是当前所在的位置作为起点开始找!
                //IDEA默认的当前路径:工程Project的根
                fileInputStream=new FileInputStream("temp");
                //开始读,采用byte数组,一次读取多个字节。最多读取“数组.length”个字节
                byte[] bytes=new byte[4];
                //这个方法的返回值:读到的字节数量,不是字节本身。
                int read = fileInputStream.read(bytes);//第一次读到了4个字节
                System.out.println(new String(bytes,0,read));//abcd
    
                read = fileInputStream.read(bytes);//第二次读到了2个字节
                System.out.println(new String(bytes,0,read));//ef
    
                read = fileInputStream.read(bytes);//第三次读到了0个字节
                System.out.println(read);//返回-1。
    
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (fileInputStream != null) {
                    try {
                        fileInputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    
        }
    }
    

    注意
     使用相对路径,一定是当前所在的位置作为起点开始找!
     IDEA默认的当前路径:工程Project的根



    问题:该例中使用String(byte[] bytes, int offset, int length),既减少了硬盘和内存的交互,也可以读多少就转多少,但未采用循环的方式读取。改进后:

    package com.bjpowernode.java.io;
    
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    
    public class FileInputStreamTest04 {
        public static void main(String[] args) {
            FileInputStream fileInputStream=null;
            try {
                //声明字节输出流对象
                fileInputStream=new FileInputStream("temp");
                //准备一个byte数组
                byte[] bytes=new byte[4];
                int read=0;
                while ((read = fileInputStream.read(bytes)) != -1){
                    System.out.print(new String(bytes,0,read));
                }
    
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (fileInputStream != null) {
                    try {
                        fileInputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    



    FileInputStream类的其他常用方法:

    4.1.3 int available():

    返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取(或跳过)的估计剩余字节数。
     即返回流当中剩余的没有读到的字节数量。
    作用:创建数组时使用,不再需要循环。但不适合大文件,因为byte数组不能太大。

    package com.bjpowernode.java.io;
    
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    
    public class FileInputStreamTest05 {
        public static void main(String[] args) {
            FileInputStream fileInputStream=null;
            try {
                fileInputStream=new FileInputStream("temp");
                System.out.println("剩余未读字节:"+fileInputStream.available());
                //直接获得剩余未读字节数,不再需要循环了
                byte[] bytes=new byte[fileInputStream.available()];
                int read = fileInputStream.read(bytes);
                System.out.println(new String(bytes,0,read));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (fileInputStream != null) {
                    try {
                        fileInputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    


    4.1.4 long skip(long n)

    从输入流中跳过并丢弃 n个字节的数据
     即跳过几个字节不读。

    package com.bjpowernode.java.io;
    
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    
    public class FileInputStreamTest05 {
        public static void main(String[] args) {
            FileInputStream fileInputStream=null;
            try {
                fileInputStream=new FileInputStream("temp");
                fileInputStream.skip(42);
                System.out.println("剩余未读字节:"+fileInputStream.available());
                //直接获得剩余未读字节数,不再需要循环了
                byte[] bytes=new byte[fileInputStream.available()];
                int read = fileInputStream.read(bytes);
                System.out.println(new String(bytes,0,read));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (fileInputStream != null) {
                    try {
                        fileInputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    


    4.2 java.io.FileOutputStream(重点掌握

     1.文件字节输出流。
     2.字节的方式,完成输出的操作,完成写的操作(内存-->硬盘)

    4.2.1 write(byte[] b)

     将 b.length 个字节从指定 byte 数组写入此文件输出流中。 |
    注意:文件不存在会自动新建,存在则把原文件清空再写。

    package com.bjpowernode.java.io;
    
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class FileOutputStreamTest01 {
        public static void main(String[] args) {
            FileOutputStream fileOutputStream=null;
            try {
                fileOutputStream=new FileOutputStream("myfile");
                //开始写
                byte[] bytes=new byte[]{97,98,99,100};
                fileOutputStream.write(bytes);
                //写完要刷新
                fileOutputStream.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (fileOutputStream != null) {
                    try {
                        fileOutputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    

    4.2.2 write(byte[] b,int off,int len)

     将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。
    注意:文件不存在会自动新建,存在则把原文件清空再写。

    package com.bjpowernode.java.io;
    
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class FileOutputStreamTest01 {
        public static void main(String[] args) {
            FileOutputStream fileOutputStream=null;
            try {
                fileOutputStream=new FileOutputStream("myfile");
                //开始写
                byte[] bytes=new byte[]{97,98,99,100};
                fileOutputStream.write(bytes,0,2);
                //写完要刷新
                fileOutputStream.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (fileOutputStream != null) {
                    try {
                        fileOutputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    


    4.2.3 FileOutputStream(String name, boolean append)

     创建一个向具有指定 name 的文件中写入数据的输出文件流。如果第二个参数为 true,则将字节写入文件末尾处,而不是写入文件开始处。创建一个新 FileDescriptor 对象来表示此文件连接。
    注意:这个方法可以以追加的方式在文件末尾写入,不会清空原文件内容。

    package com.bjpowernode.java.io;
    
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class FileOutputStreamTest01 {
        public static void main(String[] args) {
            FileOutputStream fileOutputStream=null;
            try {
                //以追加的方式写,不会清空源文件内容
                fileOutputStream=new FileOutputStream("myfile",true);
                //开始写
                byte[] bytes=new byte[]{97,98,99,100};
                fileOutputStream.write(bytes);
                //写完要刷新
                fileOutputStream.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (fileOutputStream != null) {
                    try {
                        fileOutputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    

    写字符串
    要点:
     1.定义一个字符串。String s= “内容”;
     2.将字符串转成byte数组。s.getBytes()

    package com.bjpowernode.java.io;
    
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class FileOutputStreamTest01 {
        public static void main(String[] args) {
            FileOutputStream fileOutputStream=null;
            try {
                fileOutputStream=new FileOutputStream("myfile",true);
                String s="今天天气真不错!";
                //将字符串转换成byte数组
                byte[] bytes = s.getBytes();
                //开始写
                fileOutputStream.write(bytes);
                //写完要刷新
                fileOutputStream.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (fileOutputStream != null) {
                    try {
                        fileOutputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    

    文件拷贝
    使用FileInputStream+FileOutputStream完成文件的拷贝。
    拷贝的过程是一边读一边写。
    使用以上字节流可拷贝任意类型的文件。

    文件复制流程图
    package com.bjpowernode.java.io;
    
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    /*
    使用FileInputStream+FileOutputStream完成文件的拷贝。
    拷贝的过程是一边读一边写。
    使用以上字节流可拷贝任意类型的文件。
    */
    public class Copy01 {
        public static void main(String[] args) {
            FileInputStream fileInputStream=null;
            FileOutputStream fileOutputStream=null;
    
            try {
                //创建一个字节输入流对象
                fileInputStream=new FileInputStream("temp");
                //创建一个字节输出流对象
                fileOutputStream=new FileOutputStream("tempCopy");
    
                //一边读一边写
                byte[] bytes=new byte[1024 * 1024];// 一次最多拷贝1MB
                int read=0;
                //while条件里开始读
                while ((read=fileInputStream.read(bytes)) != -1){
                    //while方法体内写
                    fileOutputStream.write(bytes,0,read);
                }
    
                //输出流最后要刷新
                fileOutputStream.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                //分开try,一起try时,其中一个出异常会影响另一个流的关闭。
                if (fileInputStream != null) {
                    try {
                        fileInputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (fileOutputStream != null) {
                    try {
                        fileOutputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    
        }
    }
    


    4.3 java.io.FileReader

     文件字符输入流,只能读取普通文本。
     读取文本内容时,比较方便快捷。

    package com.bjpowernode.java.io;
    
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.IOException;
    
    public class FileReaderTest {
        public static void main(String[] args) {
            FileReader fileReader=null;
            try {
                //创建字符输入流
                fileReader=new FileReader("temp");
                //开始读
                char[] chars=new char[4];//一次读取4个字符
                int readCount=0;
                while ((readCount=fileReader.read(chars))!= -1){
                    System.out.print(new String(chars,0,readCount));
                }
    
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (fileReader != null) {
                    try {
                        fileReader.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    


    4.4 java.io.FileOutputStream

     文件字符输出流,写。
     只能输出普通文本。

    package com.bjpowernode.java.io;
    
    import java.io.FileWriter;
    import java.io.IOException;
    
    /*
        文件字符输出流,写
        只能输出普通文本。
    */
    public class FileWriterTest {
        public static void main(String[] args) {
            FileWriter fileWriter=null;
            try {
                //创建字符输出流对象
                fileWriter=new FileWriter("temp",true);
                //开始写
                char[] chars={'我','爱','你','中','国'};
                fileWriter.write(chars);//可写数组、字符、字符串
                fileWriter.write(chars,2,3);
                fileWriter.write("\n");//换行符
                fileWriter.write('善');//可写数组、字符、字符串
                fileWriter.write("我是一个java软件工程师");//可写数组、字符、字符串
                //刷新
                fileWriter.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                if (fileWriter != null) {
                    try {
                        fileWriter.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    


    复制文件
     使用FileReader FileWriter进行拷贝的话,只能拷贝“普通文本”文件。

    package com.bjpowernode.java.io;
    
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    
    /*
    使用FileReader FileWriter进行拷贝的话,只能拷贝“普通文本”文件。
    */
    public class Copy02 {
        public static void main(String[] args) {
            FileReader fileReader=null;
            FileWriter fileWriter=null;
    
            try {
                //创建字符输入流对象,负责读的
                fileReader=new FileReader("temp");
                //创建字符输出流对象,负责写的
                fileWriter=new FileWriter("tempCopy2");
                //一边读一边写
                char[] chars=new char[1024 * 512];//每次最多读1MB
                int readCount=0;
                while ((readCount=fileReader.read(chars))!= -1){
                    fileWriter.write(chars);
                }
                //刷新
                fileWriter.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                if (fileReader != null) {
                    try {
                        fileReader.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (fileWriter != null) {
                    try {
                        fileWriter.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    


    缓冲流

    4.5 java.io.BufferedReader:

     1.带有缓冲区的字符输入流
     2.使用这个流的时候不需要自定义char数组或byte数组,自带缓冲。

    注意:
     1. 当一个流的构造方法中需要传一个流时,这个被传进来的流被称为“节点流
     2. 外部负责包装的流,叫做“包装流”或“处理流
     3. 对于包装流来说,只需要关闭最外层包装流就行,里面的节点流会自动关闭。

    利用readLine方法循环遍历
    package com.bjpowernode.java.io;
    
    import java.io.BufferedReader;
    import java.io.FileReader;
    
    /*
    BufferedReader
        带有缓冲区的字符输入流
        使用这个流的时候不需要自定义char数组或byte数组,自带缓冲。
    */
    public class BufferedReaderTest01 {
        public static void main(String[] args) throws Exception{
            FileReader fr=new FileReader("temp");
            //当一个流的构造方法中需要传一个流时,这个被传进来的流被称为“节点流”
            //外部负责包装的流,叫做“包装流”或“处理流”
            //像当前这个程序来说:节点流是FileReader,包装流是BufferedReader
            BufferedReader br=new BufferedReader(fr);
    
            //利用readLine循环读
            String firstLine2=null;
            while ( (firstLine2=br.readLine()) != null ){
                System.out.println(firstLine2);
            }
    
            //对于包装流来说,只需要关闭最外层流就行,里面的节点流会自动关闭。
            br.close();
        }
    }
    

    4.6 java.io.BufferedWriter:

     1.带有缓冲区的字符输出流
     2.使用这个流的时候不需要自定义char数组或byte数组,自带缓冲。

    package com.bjpowernode.java.io;
    
    import java.io.BufferedWriter;
    import java.io.FileWriter;
    import java.io.IOException;
    
    public class BufferedWriterTest {
        public static void main(String[] args) {
            try {
                //创建带有缓冲区的字符输出流对象
                BufferedWriter bufferedWriter=new BufferedWriter(new FileWriter("temp"));
                //写
                bufferedWriter.write("hello world!");
                bufferedWriter.write("\n");
                bufferedWriter.write("hello kitty!");
                //刷新
                bufferedWriter.flush();
                //关闭
                bufferedWriter.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    


    转换流

    4.7 java.io.InputStreamReader

    package com.bjpowernode.java.io;
    
    import java.io.*;
    
    public class BufferedReaderTest02 {
        public static void main(String[] args) {
            try {
                //创建字节输入流对象
                FileInputStream in=new FileInputStream("temp");
    
                //使用转换流将字节流转换成字符流再传入BufferedReader中。
                //这里in是“节点流”,reader是“包装流”
                InputStreamReader reader=new InputStreamReader(in);
    
                //因为BufferedReader只能传字符流对象,不能传字节流对象,故需要用转换流先转换一下。
                //这里reader是“节点流”,br是“包装流”
                BufferedReader br=new BufferedReader(reader);
    
                //开始读
                String line=null;
                while( (line = br.readLine()) != null){
                    System.out.println(line);
                }
    
                //关闭最外层
                br.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    简化代码后
    package com.bjpowernode.java.io;
    
    import java.io.*;
    
    public class BufferedReaderTest02 {
        public static void main(String[] args) {
            try {
            
                BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream("temp")));
    
                //开始读
                String line=null;
                while( (line = br.readLine()) != null){
                    System.out.println(line);
                }
    
                //关闭最外层
                br.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    

    4.8 java.io.OutputStreamWriter

    package com.bjpowernode.java.io;
    
    import java.io.*;
    
    public class BufferedWriterTest {
        public static void main(String[] args) {
            try {
                //先创建字节输出流,再使用转换流创建带有缓冲区的字符输出流对象
                BufferedWriter bufferedWriter=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("temp",true)));
                //写
                bufferedWriter.write("大家好!");
                bufferedWriter.write("\n");
                bufferedWriter.write("新年快乐!");
                //刷新
                bufferedWriter.flush();
                //关闭
                bufferedWriter.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    


    数据流

    4.9 java.io.DataInputStream

     DataOutputStream写的文件,只能使用DataInputStream去读。
     注意:读顺序需要和写的顺序一致,才能正常取出数据。

    package com.bjpowernode.java.io;
    
    import java.io.DataInputStream;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    
    /*
    DataInputStream:数据字节输入流
    DataOutputStream写的文件,只能使用DataInputStream去读。并且读顺序需要和写的顺序一致,才能正常取出数据。
    */
    public class DataInputStreamTest01 {
        public static void main(String[] args) {
            DataInputStream dataInputStream=null;
            try {
                //创建数据专属的字节输入流对象
                dataInputStream=new DataInputStream(new FileInputStream("temp"));
                //读
                byte b=dataInputStream.readByte();
                short s=dataInputStream.readShort();
                int i =dataInputStream.readInt();
                long l=dataInputStream.readLong();
                float f=dataInputStream.readFloat();
                double d =dataInputStream.readDouble();
                boolean sex =dataInputStream.readBoolean();
                char c=dataInputStream.readChar();
    
                System.out.println(b);
                System.out.println(s);
                System.out.println(i);
                System.out.println(l);
                System.out.println(f);
                System.out.println(d);
                System.out.println(sex);
                System.out.println(c);
    
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (dataInputStream != null) {
                    try {
                        dataInputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    

    4.10 java.io.DataOutputStream

      这个流可以将数据连同数据的类型一并写入文件
      注意:这个文件不是普通文本文档。(用记事本打不开,要去数据得用DataInputStream)

    package com.bjpowernode.java.io;
    
    import java.io.DataOutputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    /*
     java.io.DataInputStream:数据专属的流
     这个流可以将数据连同数据的类型一并写入文件
     注意:这个文件不是普通文本文档。(用记事本打不开)
    */
    public class DataOutputStreamTest {
        public static void main(String[] args) {
            DataOutputStream dos=null;
            try {
                //创建数据专属的字节输出流
                dos=new DataOutputStream(new FileOutputStream("temp"));
                //写数据
                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();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                //关闭最外层
                if (dos != null) {
                    try {
                        dos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    


    标准输出流

    4.11 java.io.PrinfWriter

    4.12 java.io.PrintStream(重点掌握)

     标准的字节输出流,默认输出到控制台。
     标准输出流不需要手动close()关闭。

    package com.bjpowernode.java.io;
    
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.PrintStream;
    
    public class PrintStreamTest {
        public static void main(String[] args) throws Exception {
            //联合起来写
            System.out.println("hello world!");
    
            //分开写
            PrintStream ps=System.out;
            ps.print("hello zhangsan");
    
            //标准输出流不再指向控制台,指向temp文件
            PrintStream printStream=new PrintStream(new FileOutputStream("tempCopy"));
            //修改输出方向,将输出方向修改到“temp”文件
            System.setOut(printStream);
            //再输出
            System.out.println("hello world!");
            System.out.println("hello kitty");
            System.out.println("hello zhangsan");
    
        }
    }
    




    日志工具

    package com.bjpowernode.java.io;
    
    import javax.xml.crypto.Data;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.PrintStream;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    /*
    日志工具
    */
    public class LogUtil {
        /*
        记录日志的方法
        */
        public static void  log(String msg){
            try {
                //指向一个日志文件
                PrintStream out = new PrintStream(new FileOutputStream("log.txt",true));
                //改变输出方向
                System.setOut(out);
                //日期当前时间
                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();
            }
        }
    }
    
    package com.bjpowernode.java.io;
    
    public class logTest {
        public static void main(String[] args) {
            //测试工具类是否好用
            LogUtil.log("调用了System类的gc()方法,建议启动垃圾回收");
            LogUtil.log("调用了UserService的doSome()方法");
            LogUtil.log("用户尝试进行登录,验证失败");
            LogUtil.log("我非常喜欢这个记录日志的工具哦!");
        }
    }
    


    对象专属流

    序列化和反序列化

    4.13java.io.ObjectInputStream(重点掌握)

    序列化:

    package com.bjpowernode.java.bean;
    
    public class Student {
        private int no;
        private String name;
        //省略构造方法、setter和getter方法、toString方法
    
    package com.bjpowernode.java.io;
    
    import com.bjpowernode.java.bean.Student;
    
    import java.io.FileOutputStream;
    import java.io.ObjectOutputStream;
    
    public class ObjectOutputStreamTest01 {
        public static void main(String[] args) throws Exception{
            //创建java对象
            Student s=new Student(1111,"zhangsan");
            //序列化
            ObjectOutputStream oos= new ObjectOutputStream(new FileOutputStream("student"));
            //序列化对象
            oos.writeObject(s);
            //刷新
            oos.flush();
            //关闭
            oos.close();
        }
    }
    
    不支持序列化

    分析:直接创建一个Student类,不支持序列化。Student类需要继承Serializable可序列化接口

    package com.bjpowernode.java.bean;
    
    public class Student implements Serializable  {
        private int no;
        private String name;
        //省略构造方法、setter和getter方法、toString方法
    
    序列化成功

    总结(重要):参与序列化和反序列化的对象需要实现Serializable可序列化接口
    (Serializable接口什么代码都没有,但它起标识的作用。java虚拟机看到这个类实现了这个接口,会为该类自动生成一个序列化版本号。)

    序列化版本号:
     Java虚拟机看到Serializable接口之后,会自动生成一个序列化版本号。

    Java语言中通过什么机制来区分类的?
     第一:首先通过类名进行比对,如果类名不一样,肯定不是同一个类;
     第二:如果类名一样,靠序列化版本号进行区分。

    好处
     因为类只要实现了Serializable接口,就能自动生成序列化版本号,Java虚拟机可以根据序列化版本号的不同,区分类。

    缺陷
     一个类在序列化后,会生成一个序列化版本号。若未来这个类有修改,会生成一个新的序列化版本号。虽然从业务逻辑角度上还是同一个类,但前后序列化版本号不一致,Java虚拟机会认为是两个类。
     一旦代码确定之后,不能进行后续的修改。因为只要修改必然会重新编译,此时会生成全新的序列化版本号,Java虚拟机会认为这是一个全新的类。

    总结
     凡是一个类实现了Serializable接口,建议给该类提供一个固定不变的序列化版本号(即不使用自动生成序列化版本号)。
    例如:private static final long seralVersionUID =11;

    IDEA快捷生成序列化版本号:

    IDEA快捷生成序列化版本号1 IDEA快捷生成序列化版本号2 IDEA快捷生成序列化版本号3 IDEA快捷生成序列化版本号4

    一次性序列化多个对象:
    将对象放到集合中,序列化集合
    直接存储多个对象,第二个就会报错

    package com.bjpowernode.java.io;
    
    import com.bjpowernode.java.bean.User;
    
    import java.io.FileOutputStream;
    import java.io.ObjectOutputStream;
    import java.util.ArrayList;
    import java.util.List;
    //参与序列化的ArrayList集合以及集合中的元素User都需要实现java.io.Serializable接口
    public class ObjectOutputStreamTest02 {
        public static void main(String[] args) throws Exception{
            //准备一个List集合
            List<User> userList=new ArrayList<>();
            userList.add(new User(1,"zhangsan"));
            userList.add(new User(2,"lisi"));
            userList.add(new User(3,"wangwu"));
            //序列化
            ObjectOutputStream oos= new ObjectOutputStream(new FileOutputStream("users"));
            //一次序列化一个集合对象,这个集合对象中存放了很多其他对象
            oos.writeObject(userList);
            //关闭
            oos.close();
    
        }
    }
    
    package com.bjpowernode.java.io;
    
    import com.bjpowernode.java.bean.User;
    
    import java.io.FileInputStream;
    import java.io.ObjectInputStream;
    import java.util.List;
    
    /*
    反序列化集合
    */
    public class ObjectInputStreamTest02 {
        public static void main(String[] args) throws Exception{
            //反序列化
            ObjectInputStream ois=new ObjectInputStream(new FileInputStream("users"));
            //反序列化对象
            List<User> userList = (List<User>) ois.readObject();
            for (User user:userList
                 ) {
                System.out.println(user);
            }
            //关闭
            ois.close();
        }
    }
    
    序列化集合



    若想指定某个属性不参与序列化,使用transient关键字修饰指定属性。👇

    package com.bjpowernode.java.bean;
    
    import java.io.Serializable;
    
    public class User implements Serializable {
        private int no;
        //transient关键字标识游离的,不参与序列化
        private transient String name;
        //省略setter和getter、toString、构造方法。
    }
    
    transient关键字


    4.14 java.io.ObjectOutputStream(重点掌握)

    反序列化

    package com.bjpowernode.java.io;
    
    import java.io.FileInputStream;
    import java.io.ObjectInputStream;
    
    public class ObjectInputStreamTest01 {
        public static void main(String[] args) throws Exception{
            ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream("student"));
            //开始反序列化,读
            Object o = objectInputStream.readObject();
            //反序列化回来是一个学生对象,所以会调用学生对象的toString方法
            System.out.println(o);
            //关闭
            objectInputStream.close();
        }
    }
    
    反序列化结果


    4.15 java.io.File类

     1.File类和四大家族没有关系,所以FIle类不能完成文件的读和写
     2.File对象代表什么?
      :文件和目录路径名的抽象表示形式
      C:\fitnesse-src-20161106 是一个File对象
      C:\fitnesse-src-20161106\gradlew.bat 也是File对象
      一个File对象有可能对应的是目录,也可能是文件。
      3.需要掌握File类的常用方法
      exists():测试此抽象路径名表示的文件或目录是否存在。
      createNewFile():当且仅当不存在具有此抽象路径名指定名称的文件时,不可分地创建一个新的空文件。
      mkdir():创建此抽象路径名指定的目录。
      mkdirs():创建此抽象路径名指定的目录,包括所有必需但不存在的父目录。
      getParent():返回此抽象路径名父目录的路径名字符串;如果此路径名没有指定父目录,则返回 null。(返回String类型)
      getParentFile():返回此抽象路径名父目录的抽象路径名;如果此路径名没有指定父目录,则返回 null。(返回File类型)
      getAbsolutePath():返回此抽象路径名的绝对路径名字符串。
      getName():返回由此抽象路径名表示的文件或目录的名称。
      isDirectory():测试此抽象路径名表示的文件是否是一个目录。
      isFile():测试此抽象路径名表示的文件是否是一个标准文件。
      lastModified():返回此抽象路径名表示的文件最后一次被修改的时间。(返回值是long类型,表示从1970年到现在的总毫秒数。)
      length():返回由此抽象路径名表示的文件的长度(即文件的大小)。
      length():返回由此抽象路径名表示的文件的长度(即文件的大小)。
      listFiles():返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。

    package com.bjpowernode.java.io;
    
    import java.io.File;
    import java.io.IOException;
    
    public class FileTest01 {
        public static void main(String[] args) throws Exception {
    
            /*File file=new File(("G:\\大4上学期\\实习\\JavaSE\\chapter23\\src\\com\\bjpowernode\\java\\io\\file"));
            //判断文件是否存在
            System.out.println(file.exists());*/
    
            /*//如果G:\大4上学期\实习\JavaSE\chapter23\src\com\bjpowernode\java\io\file不存在,则以文件的形式创建出来
            if (!file.exists()) {
                file.createNewFile();
            }*/
    
           /* //如果G:\大4上学期\实习\JavaSE\chapter23\src\com\bjpowernode\java\io\file不存在,则以目录的形式创建出来
            if (!file.exists()) {
                file.mkdir();
            }*/
    
            /*File file2=new File(("G:\\大4上学期\\实习\\JavaSE\\chapter23\\src\\com\\bjpowernode\\java\\io\\file\\a\\b\\c\\d"));
            if (!file2.exists()) {
                //以多重目录的形式新建
                file2.mkdirs();
            }*/
    
            File file3=new File(("G:\\大4上学期\\实习\\JavaSE\\chapter23\\src\\com\\bjpowernode\\java\\io\\file"));
            //获取文件的父路径
            String parentPath=file3.getPath();
            System.out.println(parentPath);
            File parentFile=file3.getParentFile();
            System.out.println("获取绝对路劲:"+parentFile.getAbsolutePath());
    
            File file4=new File("temp");
            System.out.println("获取绝对路径:"+file4.getAbsolutePath());
        }
    }
    
    package com.bjpowernode.java.io;
    
    import java.io.File;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    /*
    File类的常用方法
    */
    public class FileTest02 {
        public static void main(String[] args) {
            File f1=new File("G:\\大4上学期\\实习\\JavaSE\\chapter23\\src\\com\\bjpowernode\\java\\io\\BufferedReaderTest01.java");
            //获取文件名
            System.out.println("文件名:"+f1.getName());
            //判断是是否是一个目录
            System.out.println(f1.isDirectory());//false
            //判断是否是一个文件
            System.out.println(f1.isFile());//true
    
            //获取文件最后一次修改时间
            long haoMiao=f1.lastModified();//这个毫秒是从1970年到现在的总毫秒数。
            Date time=new Date(haoMiao);
            SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
            String strTime=sdf.format(time);
            System.out.println(strTime);
    
            //获取文件大小
            System.out.println(f1.length());//1054
        }
    }
    
    package com.bjpowernode.java.io;
    
    import java.io.File;
    
    /*
    File中的listFIles方法
    */
    public class FileTest03 {
        public static void main(String[] args) {
            //File[] listFiles()
            //获取当前目录下所有的子文件
            File f=new File("G:\\大4上学期\\实习\\JavaSE\\chapter23\\src\\com\\bjpowernode\\java\\io");
            File[] files = f.listFiles();
            //foreach
            for (File file :files) {
                System.out.println(file.getAbsolutePath());
                System.out.println(file.getName());
            }
        }
    }
    


    目录拷贝(非常具有代表性)

    题目:拷贝一个目录到一个地方

    解题思路:
     递归
     FileInputStream
     FileOutputStream
     字符串拼接

     boolean endsWith(String suffix):
    测试此字符串是否以指定的后缀结束。

    package com.bjpowernode.java.io;
    
    import java.io.File;
    /*
    测试:拷贝一个目录到一个地方
    */
    public class work {
        public static void main(String[] args) {
            CopyUtil copyUtil=new CopyUtil();
            //指定拷贝源
            File srcFile=new File("G:\\大4上学期\\实习\\JavaSE\\chapter23\\src\\com");
            //拷贝目标
            File destFile=new File("G:\\a\\");
            //调用方法拷贝
            copyUtil.copy(srcFile,destFile);
        }
    }
    
    package com.bjpowernode.java.io;
    
    import java.io.*;
    /*
    inPath:拷贝源
    outPatch: 拷贝目标
    */
    public class CopyUtil {
        private static FileInputStream fi=null;
        private static FileOutputStream fo=null;
    
        public void copy(File inPath, File outPath) {
            if (inPath.isFile()){
                //是文件的时候需要拷贝,一边读一边写
                try {
                    //读文件
                    fi=new FileInputStream(inPath);
                    //写文件
                    String path=(outPath.getAbsolutePath().endsWith("\\") ? outPath.getAbsolutePath(): outPath.getAbsolutePath()+"\\") +inPath.getAbsolutePath().substring(12);
                    fo=new FileOutputStream(path);
    
                    //一边读一边写
                    byte[] bytes=new byte[1024*1024];
                    int readCount=0;
                    while ( (readCount=fi.read()) !=-1){
                        fo.write(bytes,0,readCount);
                    }
                    //刷新
                    fo.flush();
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    if (fi != null) {
                        try {
                            fi.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (fo != null) {
                        try {
                            fo.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
                //inPath如果是一个文件的话,递归结束
                return;
            }
            //获取源下面的子目录
            File[] files=inPath.listFiles();
            for (File file:files
                 ) {
                //是目录的时候创建目录
                if (file.isDirectory()) {
                    String srcDir=file.getAbsolutePath();
                    /*System.out.println(srcDir.substring(12));*/
                    String desDir= (outPath.getAbsolutePath().endsWith("\\") ? outPath.getAbsolutePath(): outPath.getAbsolutePath()+"\\") +srcDir.substring(12);
                    /*System.out.println(desDir);*/
    
                    File newFile=new File(desDir);
                    if (!newFile.exists()) {
                        newFile.mkdirs();
                    }
                }
                //递归调用
                copy(file,outPath);
            }
        }
    }
    


    5. IO流+Properties集合的联合使用

    IO流:文件的读和写。
    Properties:是一个Map集合,key和value都是String类型。

    userinfo
    package com.bjpowernode.java.io;
    
    import java.io.FileReader;
    import java.util.Properties;
    /*
    IO+Properties的联合应用
    非常好的设计理念:
        以后要是经常改变的数据,可以单独写到一个文件中,使用程序动态读取。
        将来只要修改这个文件的内容,java代码不需要改动,不需要重新编译。
        服务器也不需要重启,就可以拿到动态的信息。
    */
    public class IoPropertiesTest {
        public static void main(String[] args) throws Exception{
            /*
            Properties是一个Map集合,key和value都是String类型。
            想将userinfo文件中的数据加载到Properties对象当中。
            */
    
            //新建输入流对象
            FileReader reader=new FileReader("userinfo");
            //新建一个Map集合
            Properties pro=new Properties();
            //调用Properties对象的load方法将文件的数据加载到Map集合中。
            pro.load(reader);//文件中的数据顺着管道加载到Map集合中
    
            //通过key来获取value呢?
            String username = pro.getProperty("username");
            System.out.println(username);
    
            String password = pro.getProperty("password");
            System.out.println(password);
        }
    }
    
    IO流+properties程序运行结果



    笔记来源:B站动力节点Java零基础教程视频

    视频链接:https://www.bilibili.com/video/BV1Rx411876f

    相关文章

      网友评论

          本文标题:JavaSE进阶-06-IO流

          本文链接:https://www.haomeiwen.com/subject/pfcvaltx.html