zoukankan      html  css  js  c++  java
  • 理解Java中的IO字节流(File的输入输出理解)

    IO概念

    什么是IO

    Java中IO操作主要是指使用java.io包下的内容,进行输入、输出操作。输入也叫做读取数据,输岀也叫做作写出数据。

    IO的分类

    根据数据的流向分为:输入流和输出流。

    输入流:把数据从其他设备上读取到内存中的流。

    输出流:把数据从内存中写出到其他设备上的流。

    格局数据的类型分为:字节流和字符流。

    顶级父类们

     字节流

    一切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,都是一个ー个的字节,在传输时也是一样如此。所以,字节流可以传输任意文件数据。在操作流的时候,我们要时刻明确,无论使用什么样的流对象,底层传输的始终为二进制数据。

    字节输出流——OutputStream

    java.io.OutputStream抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到目的地。它定义了字节输出流的基本共性功能方法。

    java.io.OutputStream
    1、public abstract void write(int b) throws IOException;
    // 将指定的字节输出流。
    
    2、public void write(byte b[]) throws IOException{...};
    // 将b.length字节从指定的字节数组写入此输出流。
    
    3、public void write(byte b[], int off, int len) throws IOException{...};
    // 从指定的字节数组写入len字节,从偏移量off开始输出到此输出流。
    
    4、public void flush() throws IOException{};
    // 刷新此输出流并强制任何缓冲的输出字节被写出。
    
    5、public void close() throws IOException {};
    // 关闭此输出流并释放与此流相关联的任何系统资源。

    FileOutputStream类

    OutputStream抽象类,有很多的子类,其中FileOutputStream类是它其中一个简单的子类。

    java.io.FileOutputStream是文件输出流,用于将数据写出到文件。

    写出字节数据

    写出字节:write(int b)方法,每次可以写出一个字节数据

    字节输出流的使用步骤:

    1. 创建一个 FileOutputStream对象,构造方法中传递写入数据的目的地。
    2. 调用FileOutputStream对象中的方法write,把数据写入到文件中。
    3. 释放资源(流使用会占用一定的内存,使用完毕要把内存清空提供程序的效率)。
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class DemoFosWrite {
        public static void main(String[] args) throws IOException {
            // 使用文件名创建字节流对象
            FileOutputStream fos = new FileOutputStream("FOS.txt");
    
            // 写出数据
            // 写出第一个字节
            fos.write(97);
            // 写出第二个字节
            fos.write(98);
            // 写出第三个字节
            fos.write(99);
    
            // 关闭资源
            fos.close();
        }
    }

    运行结果:生成了一个"FOS.txt"文件

    FOS.txt文件大小是3个字节,内容是abc

    写入数据的原理(内存-->硬盘):

    Java程序 --> Java虚拟机 --> 操作系统 --> 操作系统调用写数据的方法 --> 把数据写到文件中

    写数据的时候,会把要写入的数据转换为二进制数。在打开文件的时候,都会查询编码表(例如:ASCII表),把字节转换为字符表示。

    write(byte b[])方法

    作用:将b.length字节从指定的字节数组写入此输出流。

    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class Demo01Write {
        public static void main(String[] args) throws IOException {
            FileOutputStream fos = new FileOutputStream("FOS1.txt");
    
            byte[] bytes = {97, 98, 99};
            // 将3个字节从bytes字节数组写入fos输出流。
            fos.write(bytes);
    
            fos.close();
        }
    }

    运行结果:生成了一个"FOS1.txt"文件

    write(byte b[], int off, int len)方法

    作用:从指定的字节数组写入len字节,从偏移量off开始输出到此输出流。

    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class Demo02Write {
        public static void main(String[] args) throws IOException {
            FileOutputStream fos = new FileOutputStream("FOS2.txt");
    
            byte[] bytes = {97, 98, 99, 100, 101, 102};
            // 将3个字节从bytes字节数组写入fos输出流。
            fos.write(bytes, 1, 4);
    
            fos.close();
        }
    }

    运行结果:生成了一个"FOS2.txt"文件

    write方法简单练习

    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.util.Arrays;
    
    public class Demo03Write {
        public static void main(String[] args) throws IOException {
            FileOutputStream fos = new FileOutputStream("FOS3.txt");
    
            // 调用String类中的getBytes()方法,把一串字符转换为byte数组
            byte[] bytes = "大佬,你好!".getBytes();
            // 将该数组转换为集合输出
            System.out.println(Arrays.toString(bytes));
    
            // 将多个字节从bytes字节数组写入fos输出流。
            fos.write(bytes);
    
            fos.close();
        }
    }

    控制台输出

    [-27, -92, -89, -28, -67, -84, -17, -68, -116, -28, -67, -96, -27, -91, -67, -17, -68, -127]

    运行结果:还生成了一个"FOS3.txt"文件

    字节输出流的续写和换行

    public FileOutputStream(File file, boolean append)
    // 创建文件输出流以写入由指定的File对象表示的文件。
    
    public FileOutputStream(String name, boolean append)
    // 创建文件输出流以指定的名称写入文件。

    这两个构造方法,参数中都需要传入一个 boolean类型的值,true表示追加数据,false表示清空原有数据这样创建的输出流对象,就可以指定是否追加续写了,代码使用演示:

    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class Demo01OutputAppend {
        public static void main(String[] args) throws IOException {
            FileOutputStream fos = new FileOutputStream("a.txt", true);
    
            // 往"a.txt"文件中写入"大佬,"内容
            byte[] bytes1 = "大佬,".getBytes();
            fos.write(bytes1);
    
            // 往"a.txt"文件中追加写入"你好!"内容
            byte[] bytes2 = "你好!".getBytes();
            fos.write(bytes2);
    
            fos.close();
        }
    }

    运行结果:生成了一个"a.txt"文件

    如果需要换行:

    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class Demo02OutputAppend {
        public static void main(String[] args) throws IOException {
            FileOutputStream fos = new FileOutputStream("b.txt", true);
    
            // 往"a.txt"文件中写入"大佬,"内容
            byte[] bytes1 = "大佬,".getBytes();
            fos.write(bytes1);
    
            // 换行 "
    " 或者 "
    "
            byte[] bytes = "
    ".getBytes();
            fos.write(bytes);
    
            // 往"a.txt"文件中追加写入"你好!"内容
            byte[] bytes2 = "你好!".getBytes();
            fos.write(bytes2);
    
            fos.close();
        }
    }

    运行结果:生成了一个"b.txt"文件

     

    字节输入流 —— InputStream

    java.io.InputStream抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中。它定义了字节输入流的基本共性功能方法。

    public void close()
    // 关闭此输入流并释放与此流相关联的任何系统资源。
    
    public abstract int read()
    // 从输入流读取数据的下一个字节。
    
    public int read(byte[] b)
    // 从输入流中读取一些字节数,并将它们存储到字节数组b中。

    FileInputStream类

    java.io.FileInputStream类是文件输入流,从文件中读取字节。

    构造方法

    public FileInputStream(String name) throws FileNotFoundException
    // 通过打开与实际文件的连接来创建一个 FileInputStream,该文件由文件系统中的路径名name命名。
    
    public FileInputStream(File file) throws FileNotFoundException
    // 通过打开与实际文件的连接来创建一个 FileInputStream,该文件由文件系统中的File对象file命名。

    当我们创建一个流对象时,必须传入一个文件路径。该路径下,如果没有该文件,会抛出FileNotFoundException异常。

    读取数据的原理(硬盘-->内存):
    Java程序 --> Java虚拟机 --> 操作系统 --> 操作系统调用读取数据的方法 --> 读取文件

    字节输入流的使用步骤:
    1.创建FileInputStream对象,构造方法中绑定要读取的数据源。
    2.使用FileInputStream对象中的方法read,读取文件。
    3.释放资源。

    下面这个例子中使用的read()方法是一个字节一个字节的读取的。

    import java.io.FileInputStream;
    import java.io.IOException;
    
    public class DemoInputRead {
        public static void main(String[] args) throws IOException {
            // 创建FileInputStream对象,构造方法中绑定要读取的数据源
            FileInputStream fis = new FileInputStream("/Users/liyihua/IdeaProjects/Study/A");
    
            // 使用FileInputStream对象中的方法read,读取文件
            // char=65 对应 A
            int lien0 = fis.read();
            char c0 = (char) lien0;
            System.out.println(lien0 + "对应" + c0);
    
            // char=10 对应 /n
            int lien1 = fis.read();
            char c1 = (char) lien1;
            System.out.println(lien1 + "对应" + c1);
    
            // char=66 对应 B
            int lien2 = fis.read();
            char c2 = (char) lien2;
            System.out.println(lien2 + "对应" + c2);
    
            // char=10 对应 /n
            int lien3 = fis.read();
            char c3 = (char) lien3;
            System.out.println(lien3 + "对应" + c3);
    
            // 释放资源
            fis.close();
        }
    }

    文件A的内容:

     如果已经将文件A的内容读取完了,那么再读取的话,会返回-1。

    FileInputStream类中的部分方法

    int available()
    // 返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。
    
    void close()
    // 关闭此输入流并释放与该流关联的所有系统资源。
    
    int read()
    // 从输入流中读取数据的下一个字节。
    
    int read(byte b[])
    // 从输入流中读取一定数量的字节,并将其存储在緩神区数组b中。
    
    int read(byte b[], int off, int len)
    // 将输入流中最多len个数据字节读入byte数组。
    
    long skip(long n)
    // 跳过和丢弃此输入流中数据的n个字节。

    read(byte b[])方法

    import java.io.FileInputStream;
    import java.io.IOException;
    
    public class Demo02InputRead {
        public static void main(String[] args) throws IOException {
            FileInputStream fis = new FileInputStream("/Users/liyihua/IdeaProjects/Study/B");
    
            // 创建一个byte数组,存储读取的字节
            byte[] bytes = new byte[2];
    
            // 开始读取,每次读取两个
            // 第一次读取: bytes = {97, 98},len1 = 2
            int len1 = fis.read(bytes);
            System.out.println(
                    "bytes = " + new String(bytes)
                    + "		"
                    + "len = " + len1
            );
    
            // 开始读取,每次读取两个
            // 第二次读取: bytes = {99, 100},len2 = 2
            int len2 = fis.read(bytes);
            System.out.println(
                    "bytes = " + new String(bytes)
                    + "		"
                    + "len = " + len2
            );
    
            // 开始读取,每次读取两个
            // 第三次读取: bytes = {101, 100},len3 = 2
            int len3 = fis.read(bytes);
            System.out.println(
                    "bytes = " + new String(bytes)
                    + "		"
                    + "len = " + len3
            );
    
            // 开始读取,每次读取两个
            // 第四次读取: bytes = {101, 100},len4 = 2
            int len4 = fis.read(bytes);
            System.out.println(
                    "bytes = " + new String(bytes)
                    + "		"
                    + "len = " + len4
            );
        }
    }

    文件B内容:

    控制台输出

    bytes = ab        len = 2
    bytes = cd        len = 2
    bytes = ed        len = 1
    bytes = ed        len = -1

    解析:

    第一次读取:读取第1个字节和第2个字节,将初始数组的{0, 0} 替换为 {a, b}

    第二次读取:读取第3个字节和第4个字节,将第一次读取后的数组的{a, b} 替换为 {c, d}

    第三次读取:读取第5个字节,发现没有可以读取的了,于是将第二次读取的数组的 {c, d}里面的c替换为e,而d没得替换,即{e, d}

    第四次读取:因为第三次读取的时候,已经读取完了,没有可以读取的了,依旧还是原来的数组{e, d}

    第一次读取两个字节(len1=2),第二次读取两个字节(len2=2),第三次读取1个字节(len3=2),第四次没得读取(len4=-1)。

    读取完后,再读取,返回值是-1。

    字节流练习:图片复制

    文件复制的步骤:

    1. 创建一个字节输入流对象,构造方法中绑定要读取的数据源。
    2. 创建一个字节输出流对象,构造方法中绑定要写入的目的地。
    3. 使用字节输入流对象中的方法read读取文件。
    4. 使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中。
    5. 释放资源。
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class DemoCopyFile {
        public static void main(String[] args) throws IOException {
            // 创建一个字节输入流对象,构造方法中绑定要读取的数据源。
            FileInputStream fis = new FileInputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo30/666.jpg");
    
            // 创建一个字节输出流对象,构造方法中绑定要写入的目的地。
            FileOutputStream fos = new FileOutputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo30/999.jpg");
    
            // 使用字节输入流对象中的方法read读取文件。
            int len = 0;
            while ((len = fis.read()) != -1) {
                // 使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中。
                fos.write(len);
            }
    
            // 释放资源。先关闭写的,再关闭读的。
            fis.close();
            fos.close();
        }
    }

    运行结果:


    程序优化:

    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class Demo02CopyFile {
        public static void main(String[] args) throws IOException {
            // 创建一个字节输入流对象,构造方法中绑定要读取的数据源。
            FileInputStream fis = new FileInputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo30/666.jpg");
    
            // 创建一个字节输出流对象,构造方法中绑定要写入的目的地。
            FileOutputStream fos = new FileOutputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo30/999.jpg");
    
            // 使用字节输入流对象中的方法read读取文件。
            int len = 0;
            byte[] bytes = new byte[1024];
            while ((len = fis.read(bytes)) != -1) {
                // 使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中。
                fos.write(bytes, 0, len);
            }
    
            // 释放资源。
            fis.close();
            fos.close();
        }
    }

     字符流

    当使用字节流读取文本文件时,可能会有一个小问题。就是遇到中文字符时,可能不会显示完整的字符,那是因为一个中文字符可能占用多个字节存储(如:"学生"两个字占用了四个字节)。所以Java提供一些字符流类,以字符为单位读写数据专门用于处理文本文件。

    字符输入流 —— Reader

    java.io.Reader抽象类是表示用于读取字符流的所有类的超类,可以读取字符信到内存中。它定义了字符输入流的基本共性功能方法。

    public void close()
    // 关闭此流并释放与此流相关联的任何系统资源。
    
    public int read()
    // 从输入流读取一个字符。
    
    public int read(char[] chars)
    // 从输入流中读取一些字符,并将它们存储到字符数组chars中。

    FileReader类

    java.io.FileReader类是读取字符文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。

             

  • 相关阅读:
    img[src*="same"]{}
    a[href$=".pdf"]解释
    ::selection{}
    a[href^=""]的解释
    who are you?
    天下武功唯快不破
    登录一下好吗??
    后台登录
    实验吧—简单的登录题
    hdu 1010
  • 原文地址:https://www.cnblogs.com/liyihua/p/12262136.html
Copyright © 2011-2022 走看看