欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java IO流之字节流:OutputStream、FileOutputStream、InputStream、FileInputStream

程序员文章站 2024-03-04 21:02:12
...

JAVA IO流

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

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

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

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

Java IO流之字节流:OutputStream、FileOutputStream、InputStream、FileInputStream

输出流的原理(内存 --> 硬盘):

java程序 --> JVM --> OS(操作系统) --> OS调用写数据的方法 --> 把数据写到硬盘的文件中

输入流的原理(硬盘 --> 内存):

java程序 --> JVM --> OS(操作系统) --> OS调用读数据的方法 --> 把数据从硬盘文件中读取到内存中


一、字节流

一切都为字节,任何文件都是以二进制数字形式保存。在传输过程中都是以二进制数据形式传输。

字节输出流

1、OutputStream 抽象类 JDK 1.0

java.io.OutputStream这个抽象类是表示字节输出流的所有类的超类。 输出流接收输出字节并将其发送到某个接收器。它定义了字节输出流的基本共性功能方法。

已知直接子类:

ByteArrayOutputStreamFileOutputStreamFilterOutputStreamObjectOutputStreamOutputStreamPipedOutputStream

常用方法

  • public void close() 关闭此输出流并释放与此流相关的任何系统资源
  • public void flush() 刷新此输出流并强制任何缓冲的输出字节被写出
  • public void write(byte[] b) 将b.length字节从指定的字节数组写入此输出流
  • public void write(byte[] b, int off, int len) 从指定的字节数组写入 len节字,从偏移量off开始输出到此输出流
  • public abstract void write(int b) 将指定的字节输出流,只能传入一个字节大小的十进制整数。

注意:close方法必须在完成流之后调用,以此释放相关的系统资源。


2、FileOutputStream 类

该类是继承OutputStream抽象类的子类

java.io.FileOutputStream 类是文件输出流,将内存中的数据写到硬盘中的文件中。

异常:

IOException

构造方法( 共5个 )

  • public FileOutputStream(File file) throws FileNotFoundException 创建文件输出流以写入由指定的 File对象表示的文件。(如原来已经有该文件,会被覆盖重写新的数据)
  • public FileOutputStream(String name)throws FileNotFoundException 创建文件输出流以指定的名称写入文件。(name为文件的路径)。(如原来已经有该文件,会被覆盖重写新的数据)
  • public FileOutputStream(File file,boolean append) throws FileNotFoundException JDK1.4开始,向文件中写入数据,append为true就是在该文件的文末开始追加新的数据;为false会创建新文件覆盖原文件,并开始写入新数据。(文件不存在,则会自动创建)
  • public FileOutputStream(String name,boolean append) throws FileNotFoundException JDK1.1开始,向文件中写入数据,append为true就是在该文件的文末开始追加新的数据;为false会创建新文件覆盖原文件,并开始写入新数据。(文件不存在,则会自动创建)
public class FileOutputStreamConstructor{
    public static void main(String[] args) throws IOException{
        // 以File对象创建输出流
        File file = new File("a.txt");
        FileOutputStream fileOutputStream = new FileOutputStream(file);
        
        // 以文件名称创建输出流 当前文件的output文件夹下的a.txt文件
        FileOutputStream fileOutputStream = new FileOutputStream("output/a.txt");
        fileOutputStream.close();
    }
}

写出字节流

  1. 写出字节:write(int b) 方法,每次可以写出一个字节数据 IOException
public class DemonFileOutputStream{
    public static void main(String[] args) throws IOException{
        FileOutputStream fileOutputStream = new FileOutputStream("output/a.txt");
        fileOutputStream.write(97); // 像文件中写入的是小写字母a
        fileOutputStream.close();
    }
}

字节流写入文件的原理: 向a.txt文件写入了97,在程序运行的时候,因为是字节流,会将97转为二进制整数1100001写入到a.txt文件中,当打开a.txt文件时,这些文本编辑器,会自动将写入的二进制整数1100001通过编码解析。默认解析规则为:0-127的十进制整数会比对ASCII表,其他值会以系统默认码表查询。这里二进制转换为十进制数为97,则97在ASII表中对应的是小写字母a。那么打开a.txt显示的是 a 。

ASCII表

48为0 以此为0~9 9为57

65为A 以此为A~Z(26个字母)Z为90

97为a 以此为a~z(26个字母)z为122

当字节十进制在0-127时,会解析ASCII表。当第一个为负数,第二个为整数或负数,则会组合在一起,形成2个字节解析为中文。需要注意的是UTF-8编码一个中文字符占3个字节,GBK编码一个中文占2个字节。

public class DemonFileOutputStream{
    public static void main(String[] args) throws IOException{
        FileOutputStream fileOutputStream = new FileOutputStream("output/a.txt");
// write(byte[] b)
        byte[] a = {65,67,68,69};
        fileOutputStream.write(a); // 查看a.txt文件写入的是 ACDE
        byte[] b = {-65,-66,-67,68};
        fileOutputStream.write(b); // 查看a.txt文件写入的是 烤紻
        
// write(byte[] b, int off, int len)
        fileOutputStream.write(a, 1, 2); // 查看a.txt文件写入的是 CD
        // 写的是字节数组a的索引为1开始的2个长度的数据 67,68
        
// 把字符串转换成字节数组
        String str = "你好";
        byte[] c = str.getBytes();
        System.out.println(Arrays.toString(byte)); // [-28, -67, -96, -27, -91, -67]
        // 需要注意的是UTF-8编码一个中文字符占3个字节,GBK编码一个中文占2个字节
        fileOutputStream.write(c); // 就会把字符串以字节流的方式写入到a.txt文件中
    }
}

数据追加续写与换行

构造方法:

  • public FileOutputStream(File file,boolean append) throws FileNotFoundException JDK1.4开始,向文件中写入数据,append为true就是在该文件的文末开始追加新的数据;为false会创建新文件覆盖原文件,并开始写入新数据。(文件不存在,则会自动创建)
  • public FileOutputStream(String name,boolean append) throws FileNotFoundException JDK1.1开始,向文件中写入数据,append为true就是在该文件的文末开始追加新的数据;为false会创建新文件覆盖原文件,并开始写入新数据。(文件不存在,则会自动创建)

写入换行字符串:

  • win:\r\n
  • mac:/r
  • Linux:/n
public class FileOutputStreamTest {
    public static void main(String[] args) throws IOException {

        FileOutputStream fileOutputStream = new FileOutputStream("b.txt",true);
        for (int i = 0; i < 10; i++) {
            fileOutputStream.write("你好".getBytes());
            fileOutputStream.write("\r\n".getBytes()); // win 下的换行符
        }

        fileOutputStream.close();
    }
}

字节输入流


1、InputStream 抽象类 JDK 1.0

java.io.InputStream这个抽象类是表示字节输出流的所有类的超类。 输出流接收输出字节并将其发送到某个接收器。它定义了字节输出流的基本共性功能方法。

已知直接子类:

AudioInputStreamByteArrayInputStreamFileInputStreamFilterInputStreamInputStreamObjectInputStreamPipedInputStreamSequenceInputStreamStringBufferInputStream

常用方法

  • public void close() 关闭此输入流并释放与此流相关的系统资源
  • public abstract int read() 从输入流中读取数据的下一个字节。
  • public int read(byte[] b) 从该输入流读取最多 byte.length个字节的数据到字节数组。 返回读取文件中有效字节个数,并且会将有效字节存放在byte数组中。如果读到文末,则返回-1
  • public int read(byte[] b, int off, int len) 从该输入流读取从off索引开始到最多 len字节的数据到字节数组。如果读到文末,则返回-1

注意:close方法必须在完成流之后调用,以此释放相关的系统资源。


2、FileInputStream 类

该类是继承InputStream抽象类的子类

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

异常:

FileNotFoundException

构造方法

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

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

public int read(byte[] b) 中byte[]数组的作用,以及返回值是什么?

起到缓冲作用,返回值为读取字节数的有效个数,当读到文末时,没有有效字节数了就会返回-1。一般数组的长度定义为1024(1kb)

byte[] bytes = new byte[1024];

读取字节流

public class FileInputStreamTest {
    public static void main(String[] args) throws IOException {
        InputStream inputStream = new FileInputStream("a.txt");

        // read() 只读取一个字节的数据并返回该数据,如果读到文末,则返回-1
        /*int read = 0;
        while ( (read = inputStream.read()) != -1){
            // read = inputStream.read(); // 读取了一个字节,指针会自动向后移一位
                System.out.print( read+":" );
                System.out.print((char) read +" ");
        }*/

        int read1 = 0;
        byte[] bytes = new byte[1024];
        while ((read1 = inputStream.read(bytes)) != -1){
            // System.out.println(read1); // 输出读取有效字节个数
            // System.out.println(Arrays.toString(bytes)); // 输出由二进制数据转换成十进制的数
            // System.out.println(new String(bytes)); // 使用String的该构造方法,会将1024个字节全部输出,空格也会输出
            System.out.println(new String(bytes,0, read1)); // 该方法就是从字节数组索引为0开始到有效个数的长度截至,转为字符
        }

        inputStream.close();

    }
}


练习:文件复制

可复制任何文件

public class CopyFile {
    public static void main(String[] args) throws IOException {

        // 1)复制文本
        /*FileInputStream fileInputStream = new FileInputStream("a.txt");
        byte[] bytes = new byte[1024];
        int read = 0;
        while((read = fileInputStream.read(bytes))! = -1){
            FileOutputStream fileOutputStream = new FileOutputStream("b.txt");
            fileOutputStream.write(bytes,0, read);
        }
        fileOutputStream.close();
        fileInputStream.close();*/

        // 2)复制图片
        /*FileInputStream fileInputStream = new FileInputStream("D:/IMG_20191127_181018.jpg");
        FileOutputStream fileOutputStream = new FileOutputStream("E:/IMG.jpg");
        byte[] bytes = new byte[1024];
        int read = 0;
        while ( (read = fileInputStream.read(bytes)) != -1){
            fileOutputStream.write(bytes,0, read);
        }
        fileOutputStream.close();
        fileInputStream.close();*/
        
        // 3)复制音频
        FileInputStream fileInputStream = new FileInputStream("D:\\媒体\\音乐\\勇气.mp3");
        FileOutputStream fileOutputStream = new FileOutputStream("E:/勇气.mp3");
        byte[] bytes = new byte[1024];
        int read = 0;
        while ( (read = fileInputStream.read(bytes)) != -1){
            fileOutputStream.write(bytes,0, read);
        }
        fileOutputStream.close();
        fileInputStream.close();
    }
}

注意:

  1. 先关闭写文件的数据流,再关闭读取文件的数据流。(因为写数据,已经写完了,读取的数据肯定就已经读完了)
  2. 当复制文件或读取写入的文件数据字节数小的话,建议使用单个读取字节的方法;当复制文件或读取写入文件的数据字节数大的话,建议使用new byte[1024]的整数倍。少使用数组,浪费空间,因为数组中每一位都会占去一定的空间。
相关标签: Java学习 java