• JavaSE基础day17 IO操作01



    一. IO流

    (一) IO流概述

    1.IO流介绍:

            I和O,分别是Input和Output两个单词的缩写,Input是输入,Output是输出。

            流:是一种抽象概念,是对数据传输的总称.也就是说数据在设备间的传输称为流

            常见的应用: 文件复制、文件上传、文件下载等。

    2.IO流分类:

            按照数据的流向:

                     输入流:读数据

                     输出流:写数据

            按照数据类型:

                     字节流:

                             字节输入流和字节输出流

                     字符流:

                             字符输入流和字符输出流

      字节流和字符流的使用场景:

           如果操作的是纯文本文件,优先使用字符流

           如果操作的是图片、视频、音频等二进制文件,优先使用字节流

           如果不确定文件类型,优先使用字节流.字节流是万能的流

    3.IO流程序书写流程:

            (1) 在操作之前,要导包,java.io包

            (2) 在操作流对象的时候,要处理解决异常(IOException)

            (3) 在操作完流对象之后,必须关闭资源, 所有流资源的关闭 close();

     

    (二) 字节流

    2.1字节流概述

    1. 字节流抽象基类:

            (1) InputStream:这个抽象类是表示字节输入流所有类的超类

            (2) OutputStream:这个抽象类是表示字节输出流所有类的超类

    根据交互设备的不同,有不同的具体子类

    2.2字节输入流FileInputStream

    1、FileInputStream是InputStream一个具体子类,用于和磁盘上的文件进行交互

    2、FileInputStream不仅可以一次读取一个字节,也可以一次读取很多个字节;不仅可以读取纯文本文件,也可以读取图片、视频、音频等非纯文本文件。一切数据在计算机中都是以字节的形式在存储和计算

    3、构造方法:

           FileInputStream(File f):将一个File对象所表示的文件路径封装在一个字节输入流中       FileInputStream(String path):将一个字符串所表示的文件路径封装在一个字节输入流中  

           注意事项:无论是哪个构造方法,都只能封装文件的路径,封装文件夹路径没有任何意义,因为文件夹本身作为容器不是作为文件数据,所以不能使用流对象进行读写

     

    4. 读取文件的方法:

    1) int read():从当前的字节输入流中,读取并返回一个字节,返回值结果int类型, 表示读取到的字节对应的整数结果, 如果返回-1表示证明文件读取完毕(每一个文件都有结束标志,当流资源读取到结束标志,返回-1证明文件读取完毕)

     

    2) int read(byte[] arr):从当前的字节输入流中最多读取arr.length个字节,读取到的字节放置到参数arr数组中,返回值结果int类型, 表示本次读取到的字节个数, 如果读到-1,证明文件读取完毕

    注意 : 数组读取效率优于单个字节读取效能

     

    3) void close():关闭该流对象

    字节输入流单个字节读取代码

    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    
    public class FileInputStreamDemo {
        public static void main(String[] args) throws IOException {
            // 1. 封装出一个字节输入流: 相当于绑定一个数据源
            FileInputStream fis = new FileInputStream("D:\\newFile.txt");
            // FileInputStream fis2 = new FileInputStream(new File("D:\\newFile.txt"));
            /*int first = fis.read();
            System.out.println(first);// 97
            int second = fis.read();
            System.out.println(second);// 98
            int thrid = fis.read();
            System.out.println((char)thrid);// c
            int four = fis.read();
            System.out.println((char)four);// d
            int test1 = fis.read();
            System.out.println(test1);// -1
            int test2 = fis.read();
            System.out.println(test2);*/
    
            // len表示每次读取到的字节结果
            int len;
            // 优化: 循环读取文件内容
            while((len = fis.read()) != -1){
                System.out.print((char)len);
            }
            fis.close();
        }
    }

    字节数组读取

    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    
    public class FileInputStreamReadArray {
        public static void main(String[] args) throws IOException {
            FileInputStream fis = new FileInputStream("D:\\newFile.txt");
            byte[] b = new byte[4];
    
            /*int i = fis.read(b);
            System.out.println(i);// 4
            System.out.println(new String(b));// abcd
    
            int i2 = fis.read(b);
            System.out.println(i2);// 4
            System.out.println(new String(b));// 123?
    
            int i3 = fis.read(b);
            System.out.println(i3);// 4
            System.out.println(new String(b));// ?>qq
    
            int i4 = fis.read(b);
            System.out.println(i4);// 1
            System.out.println(new String(b));// 6>qq
    
            int i5 = fis.read(b);
            System.out.println(i5);// -1
            System.out.println(new String(b));// 6>qq*/
    
            // len表示每次读取到的字节的个数
            int len;
            // 优化成循环读取
            while((len = fis.read(b)) != -1){
                // new String(b,0,len) : 将字节数组的一部分转换成字符串; 将字节数组中的数值参考平台编码表,转换成符
                // 拼接字符成字符串
                // 将b数组从0索引位置开始,截取len个字节转换成目标字符串
                System.out.print(new String(b,0,len));
            }
    
            fis.close();
        }
    }

    2.3字节输出流FileOutputStream

    1. FileOutputStream和磁盘做交互的一个字节输出流对象,用于把内存当中的字节输出到磁盘当中去

    2. 构造方法:

           FileOutputStream(File f):将f描述的路径文件封装在字节输出流对象中

           FileOutputStream(String path):将path描述的文件路径封装在字节输出流对象中

      FileOutputStream(String path,boolean append):如果第二个参数为true,则字节将写入参数path对应文件的末尾而不是开头(追加写入)

      FileOutputStream(File path,boolean append):如果第二个参数为true,则字节将写入参数path对应文件的末尾而不是开头(追加写入)

     

    3. 字节流写数据的方式:

      1) void write(int b): 将指定的字节写入此文件输出流一次写一个字节数据

      2) void write(byte[] b): 将b.length字节从指定的字节数组写入此文件输出流

      3) void write(byte[] b, int off, int len): 把b数组的off索引开始的len个字节通过字节输出流写出

     

    4. 字节流写数据实现换行

        (1)windows:\r\n

        (2)linux:\n

        (3)mac:\r

    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class FileOutputStreamDemo {
        public static void main(String[] args) throws IOException {
            // 注意: 使用输出流资源: 如果只提供文件名称,表示数据覆盖式写入
           /* FileOutputStream fos = new FileOutputStream("D:\\0222Java系统班\\test.txt");
            //FileOutputStream fos1 = new FileOutputStream(new File("D:\\0222Java系统班\\test.txt"));
            // 1. 写入单个字节
            fos.write(97);// a
            // 2. 写入字节数组
            byte[] b = {65,66,67,68,69};
            fos.write(b);// ABCDE
            // 3. 写入字节数组的一部分: 从指定索引位置开始,写入一定个数
            fos.write(b,0,2);// AB
            // 4. 写入字符串
            fos.write("今天下雪了!".getBytes());
    
            fos.close();*/
    
            // 输出流资源,构造方法第二个参数,设计true数值,那么表示未来写入的数据是追加写入
            FileOutputStream fos1 = new FileOutputStream("D:\\0222Java系统班\\test.txt",true);
            fos1.write("\r\n".getBytes());
            fos1.write("添加".getBytes());
            fos1.close();
        }
    }

    2.4文件拷贝

    1. 案例 : 复制一张图片或一个视频

      例如: 把“D:\1.jpg”复制到“D:\copy.jpg”。(文件可以是任意类型文件)

      实现步骤:

        复制文件,其实就把文件的内容从一个文件中读取出来(数据源),然后写入到另一个文件中(数据目的)

      数据源:

        D:\1.jpg --- 读数据 --- InputStream --- FileInputStream

      目的地:

        D:\copy.jpg --- 写数据 --- OutputStream --- FileOutputStream 

    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    public class CopyPicture {
        public static void main(String[] args) throws IOException {
            // 1. 定义出字节输入流: 绑定一个数据源
            FileInputStream fis = new FileInputStream("D:\\0222Java系统班\\day17\\斗地主分析.png");
            // 2. 定义出字节输出流: 绑定数据目的
            FileOutputStream fos = new FileOutputStream("D:\\copy.png");
            // 3. 复制图片
             int len;
             while((len = fis.read()) != -1){
                 fos.write(len);
             }
             fis.close();
             fos.close();
        }
    }

    1. 字节流拷贝效率提升

      (1) 使用一个字节一个字节拷贝的方式,效率非常低:IO的次数过多,有多少个字节,就要IO两倍的次数。

     

      (2) 提升的思路:一次多读一些数据,一次多写出一些数据

        使用FileInputStream中的read(byte[] arr)和 FileOutputStream中的write(byte[] arr)。数组的大小可以准备成和文件一样大。配合InputStream中 的available方法可以获取源文件的字节个数,用于创建数组的大小。

     

      (3) 数组是存储于内存的,内存的大小是有限的,如果文件过大,就无法创建大小相同的数组。

        只能考虑使用小一些的数组,每次拷贝源文件的一部分,多拷贝几次。涉及方法:                a: InputStream中的read(byte[] arr):将数据读取到数组中,返回本次读到的有效字节的个数,如果返回值为-1,表示本次读到的有效字节个数为0,表示到达了文件末尾

        b: OutputStream中的write(byte[] arr):将数组中的所有数据,都写出到了目标文件中

        c: OutputStream中的write(byte[] arr, int offset, int len):将数组中的指定部分的数据,写出 到目标文件中(在读取的时候,读到了多少有效字节,就将这么多有效字节写出到目标文件中),一般offset都选择0

     

    (4) 注意事项:最终拷贝方案就是小数组

      a: 数组的大小可以任意选择,数组越大,拷贝次数越少,拷贝的效率越高

      b: 一般情况,数组的大小使用1024的整数倍,在jdk中喜欢使用1024*8大小作为缓冲区的大小。

    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class CopyPictureUseArray {
        public static void main(String[] args) throws IOException {
            // 1. 定义出字节输入流: 绑定一个数据源
            FileInputStream fis = new FileInputStream("D:\\0222Java系统班\\day17\\斗地主分析.png");
            // 2. 定义出字节输出流: 绑定数据目的
            FileOutputStream fos = new FileOutputStream("D:\\copy1.png");
            byte[] b = new byte[1024];
            long begin = System.currentTimeMillis();
            // len表示每次读取到的字节个数
            int len;
            // 3. 图片复制
            while((len = fis.read(b)) != -1){
                fos.write(b,0,len);
            }
            long end = System.currentTimeMillis();
            System.out.println(end - begin);// 2
            fis.close();
            fos.close();
        }
    }

    2.5缓冲字节流

    1. 字节缓冲流介绍:

            BufferedOutputStream:是OutputStream的子类, 表示高效字节输出流。流资源在创建时, 提供默认的数组缓冲区, 按照缓冲区数组大小进行写入, 实现效率

            BufferedInputStream:是InputStream的子类, 表示高效字节输入流。资源在创建时, 提供默认的数组缓冲区, 按照缓冲区数组大小进行读取, 实现效率

     

            注意:这两个流是包装类型:本身不具备读写的功能,只是在某个具体的流对象的基础上,对其进行加强,例如FileInputStream和FileOutputStream,原本效率较低,加强之后,就效率较高。

     

     

    2. 构造方法

      1) BufferedOutputStream(OutputStream out): 创建字节缓冲输出流对象

      2) BufferedInputStream(InputStream in): 创建字节缓冲输入流对象

     

    2.6缓冲字节流实现原理

    1. BufferedOutputStream原理分析:

       BufferedOutputStream高效的原理:在该类型中准备了一个数组,存储字节信息,当外界调用write方法想写出一个字节的时候,该对象直接将这个字节存储到了自己的数组中,而不刷新到文件中。一直到该数组所有8192个位置全都占满,该对象才把这个数组中的所有数据一次性写出到目标文件中。如果最后一次循环过程中,没有将数组写满,最终在关闭流对象的时候,也会将该数组中的数据刷新到文件中。

     

    2. BufferedInputStream原理分析:

       BufferedInputStream高效的原理:在该类型中准备了一个数组,存储字节信息,当外界调用read()方法想获取一个字节的时候,该对象从文件中一次性读取了8192个字节到数组中,只返回了第一个字节给调用者。将来调用者再次调用read方法时,当前对象就不需要再次访问磁盘,只需要从数组中取出一个字节返回给调用者即可,由于读取的是数组,所以速度非常快。当8192个字节全都读取完成之后,再需要读取一个字节,就得让该对象到文件中读取下一个8192个字节了。

    import java.io.*;
    public class BufferedStream {
        public static void main(String[] args) throws IOException {
            BufferedInputStream bis = new BufferedInputStream(
    new FileInputStream("D:\\0222Java系统班\\day17\\视频\\01.day16内容回顾.mp4"));
    
            BufferedOutputStream bos = new BufferedOutputStream(
                    new FileOutputStream("D:\\copyday16.mp4")
            );
            long begin = System.currentTimeMillis();
            // len表示每次读取到的字节的结果
            int len;
            while((len = bis.read()) != -1){
                  bos.write(len);
            }
            long end = System.currentTimeMillis();
            System.out.println(end - begin);
    
            bis.close();
            bos.close();
        }
    }

    2.7flush()方法和close()方法区别

    1. close方法会先调用flush方法

    2. close方法用于流对象的关闭,一旦调用了close方法,那么这个流对象就不能继续使用了

    3. flush只是将缓冲区中的数据,刷新到相应文件中,而不会将流对象关闭,可以继续使用这个流对象。但是如果flush方法使用过于频繁,那么丧失了缓冲区的作用。

    import java.io.BufferedOutputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class TestFlushAndClose {
        public static void main(String[] args) throws IOException {
            BufferedOutputStream bos = new BufferedOutputStream(
                    new FileOutputStream("abc.txt")
            );
    
            // BufferedOutputStream底层是带8192大小字节数组,写数据时候,没有达到8192,存储在
            // 底层数组缓冲区,没有向文件中自动同步
            bos.write("abcdef".getBytes());
            // 1. flush() : 刷新的效果就是将数组缓冲区中的数据, 同步到文件中
            // bos.flush();
            // 2. close() : 表示流资源关闭,在关闭资源之前,先调用一次flush方法,将缓冲区中的数据进行同步,
            // 后关闭资源
            bos.close();
        }
    }

    2.8IO中保证流对象关闭的标准格式

    1. 捕获异常和声明异常的原则

      1) 如果知道如何处理异常,那么就使用try...catch来进行处理;如果不知道如何处理异常,那么就使用throws来对异常进行声明,或者将当前的异常包装成其他的异常类型,进行声明,因为越到代码的高层,拥有更多的资源、更高的位置和权力,知道如何处理,底层被调用的方法,虽然是出现异常的位置,但是并不知道如何处理。

     

      2) 如果你希望程序出现异常之后,继续运行下去,那么就使用try...catch;如果出现异常之后,希望当前方法的代码停止运行,那么就使用throws

     

    2. IO中保证流对象关闭的格式(jdk1.7之前)

           try{

      流对象的使用;

      }catch(异常类名 变量名){

      异常的处理代码;

      }finally{

      关闭流资源;

      }

     

     

    3. IO中保证流对象关闭的格式(jdk1.7之后)

          try (

                流对象的创建;

      ) {

      流对象的使用;

      }catch(IOException e){

           异常处理方式;

      }

    特点:

            流对象使用之后,不需要手动关闭,因为这个格式会在流资源使用完毕后,自动关闭了流对象.

     

    JDK1.7之前异常处理

    mport java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class IOExceptionDeal {
        public static void main(String[] args) {
            byte[] b = new byte[1024];
            FileInputStream fis = null;
            FileOutputStream fos = null;
            try{
                fis = new FileInputStream("D:\\0222Java系统班\\day17\\斗地主分.png");
                fos = new FileOutputStream("D:\\copy1.png");
                // len表示每次读取到的字节个数
                int len;
                // 3. 图片复制
                while((len = fis.read(b)) != -1){
                    fos.write(b,0,len);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }finally{
                try {
                    if(fis != null){
                        fis.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }finally{
                    try {
                        if(fos != null){
                            fos.close();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    JDK1.7之后异常处理

    import java.io.*;
    public class JDK7_IOException {
        public static void main(String[] args) {
            /*
                try(
                   流资源创建;
                ){
                   可能会发生异常代码;
                }catch(预计发生异常类型 变量名){
                    异常解决方案;
                }
    
                在JDK1.7版本时, 推出了针对于IO流资源处理新的格式,try小括号中进行资源创建,同时在资源使用完毕之后会自动关闭流资源
             */
             try(
                     FileInputStream fis = new FileInputStream("abc.txt");
                     BufferedInputStream bis = new BufferedInputStream(fis);
                     FileOutputStream fos = new FileOutputStream("abcCopy.txt");
                     BufferedOutputStream bos = new BufferedOutputStream(fos);
    
                     ){
                 // len表示每次读取到的字节个数
                 int len;
                 // 3. 图片复制
                 while((len = bis.read()) != -1){
                     bos.write(len);
                 }
             } catch (IOException e) {
                 e.printStackTrace();
             }
        }
    }

    3.2编码表

    1. 什么是字符集:

      是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等

      计算机要准确的存储和识别各种字符集符号,就需要进行字符编码,一套字符集必然至少有一套字符编码。

    2. 常见字符集有: ASCII字符集、GBXXX字符集、Unicode字符集等。 

      (1) ASCII字符集:

        ASCII:是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要包括控制字符(回车键、退格、换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号)

    基本的ASCII字符集,使用7位表示一个字符,共128字符。ASCII的扩展字符集使用8位表示一个字符,共256字符,方便支持欧洲常用字符。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等

      (2) GBXXX字符集:

        GBK:最常用的中文码表。是在GB2312标准基础上的扩展规范,使用了双字节编码方案,共收录了21003个汉字,完 全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等

      (3) Unicode字符集:是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转 换、处理的要求。

      (4) UTF-8编码:可以用来表示Unicode标准中任意字符,它是电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。它使用一至四个字节为每个字符编码.

     

     

    3.3字符输出流

    1. 字符流输出流介绍:

            Writer: 用于写入字符流的抽象父类

            FileWriter: 用于写入字符流的常用子类

     

    2. FileWriter构造方法

      1) FileWriter(File file): 根据给定的 File 对象构造一个 FileWriter 对象

      2) FileWriter(File file, boolean append): 根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象

      3) FileWriter(String fileName): 根据给定的文件名构造一个 FileWriter 对象

      4) FileWriter(String fileName, boolean append)

            根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象

     

    3. 写的方法:

      1) void write(int c): 写一个字符

      2) void write(char[] cbuf): 写入一个字符数组

      3) void write(char[] cbuf, int off, int len): 写入字符数组的一部分

      4) void write(String str): 写一个字符串

      5) void write(String str, int off, int len): 写一个字符串的一部分

    import java.io.FileWriter;
    import java.io.IOException;
    
    public class FileWriterDemo {
        public static void main(String[] args) throws IOException {
            FileWriter fw = new FileWriter("chinese.txt");
    
            //P天a金天下天ok的,我很好k的,我
            // 1)void write(int c): 写一个字符
            fw.write('P');
            fw.write('天');
            fw.write(97);
    
            // 2)void write(char[] cbuf): 写入一个字符数组
            char[] ch = {'金','天','下'};
            fw.write(ch);
    
            // 3) void write(char[] cbuf, int off, int len): 写入字符数组的一部分
            fw.write(ch,1,1);//// 4)void write(String str): 写一个字符串
            String s = "ok的,我很好";
            fw.write(s);
    
            // 5) void write(String str, int off, int len): 写一个字符串的一部分
            fw.write(s,1,4);// k的,我
            fw.close();
        }
    }

    练习:

      将键盘录入的用户名和密码保存到本地实现持久化存储

    实现步骤:

      1.获取用户输入的用户名和密码

      2.将用户输入的用户名和密码写入到本地文件中

      username = ?

      password = ?

      3.关流,释放资源

    import java.io.FileWriter;
    import java.io.IOException;
    import java.util.Scanner;
    
    public class FileWriterTest {
        public static void main(String[] args) throws IOException {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入用户名:");
            String name = sc.next();
            System.out.println("请输入密码:");
            String pssword = sc.next();
            FileWriter fw = new FileWriter("userMessage.txt");
            fw.write("username = " + name);
            fw.write("\r\n");
            fw.write("psssword = " + pssword);
            fw.close();
        }
    }
  • 相关阅读:
    Linux系统(Centos)下安装Java环境配置步骤详述
    Linux系统(Centos)下安装nodejs并配置环境
    js中!~什么意思
    java jmap
    java jstat
    java jps
    JVM-GC日志分析
    JVM垃圾回收
    JVM垃圾回收--年轻代、年老点和持久代
    auth_basic 认证
  • 原文地址:https://www.cnblogs.com/lw1095950124/p/16018606.html
Copyright © 2020-2023  润新知