理解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);

        // 换行 "\n" 或者 "\r"
        byte[] bytes = "\n".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)
                + "\t\t"
                + "len = " + len1
        );

        // 开始读取,每次读取两个
        // 第二次读取: bytes = {99, 100},len2 = 2
        int len2 = fis.read(bytes);
        System.out.println(
                "bytes = " + new String(bytes)
                + "\t\t"
                + "len = " + len2
        );

        // 开始读取,每次读取两个
        // 第三次读取: bytes = {101, 100},len3 = 2
        int len3 = fis.read(bytes);
        System.out.println(
                "bytes = " + new String(bytes)
                + "\t\t"
                + "len = " + len3
        );

        // 开始读取,每次读取两个
        // 第四次读取: bytes = {101, 100},len4 = 2
        int len4 = fis.read(bytes);
        System.out.println(
                "bytes = " + new String(bytes)
                + "\t\t"
                + "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类是读取字符文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。

原文地址:https://www.cnblogs.com/liyihua/p/12262136.html

时间: 2024-10-11 22:59:08

理解Java中的IO字节流(File的输入输出理解)的相关文章

深入理解Java中的IO

深入理解Java中的IO 引言:     对程序语言的设计者来说,创建一个好的输入/输出(I/O)系统是一项艰难的任务 < Thinking in Java >   本文的目录视图如下: Java IO概要 a.Java IO中常用的类 b.Java流类的类结构图 1.流的概念和作用 2.Java IO所采用的模型  : 3.IO流的分类 4.Java IO流对象 1.输入字节流InputStream 2.输出字节流OutputStream 3.字符输入流Reader 4.字符输出流Write

1,理解java中的IO

IO中的几种形式 基于字节:InputStream.OutputStream 基于字符:Writer.Reader 基于磁盘:File 基于网络Socket 最终都是字节操作,字符到字节要编码转换.耗时,容易乱码 1,磁盘IO 磁盘设置,应用程序只能系统调用,要内核空间和用户空间切换, 标准访问文件: 读取为例,先读到内核空间,再读到用户空间. 另外有直接IO,系统缓存一下,直接从缓存读 同步,异步,内存映射(内核空间映射到用户空间减少复制操作) 2,网络IO Socket是抽象概念,也是字节流

Java中的IO字节流

 关闭流的顺序: * 当A依赖B的时候先关闭A,再关闭B * 带缓冲的流最后关闭的时候会执行一次flush ByteArrayInputStream :是字节数组输入流,作用是把字节串(或叫字节数组)变成输入流的形式 1 package object.io; 2 3 import java.io.ByteArrayInputStream; 4 import java.io.ByteArrayOutputStream; 5 import java.io.FileOutputStream; 6 im

整理 JAVA中的IO流 (字符流和字节流两个大类)

java中的io流分为两类,字符和字节: OutputStream和InputStream字节流的父类,抽象.OutputStream有两个提供了实现的接口closable和flushable. Writer和Reader字符流的父类,抽象.实际上在流的操作中,底层与文件进行读写的都是字节流,因为即使是字符流的对象,其最终实现读写的也是用的字节流. 操作文件的字节子类FileOutputStream和FileInputStream.记住,这里面写出和读入的都是字节. class useByteS

Java中的IO流

Java中的IO流是实现输入/输出的基础. 按照流的方向不同:分为输入流和输出流. 按照处理数据单位的不同:分为字节流(8位)和字符流(16位). 按照功能不同:分为节点流和处理流 所有面向字节的流类都继承于InputStream类(输入流) 或OutputStream类(输出流),这两个类是抽象类,我们可以利用它的子类来完成不同的功能. InputStream.OutputStream都是抽象类 InputStream抽象了应用程序读取数据的方式 OutputStream抽象类应用程序写出数据

java中的io系统详解

java中的io系统详解 分类: JAVA开发应用 笔记(读书.心得)2009-03-04 11:26 46118人阅读 评论(37) 收藏 举报 javaiostreamconstructorstringbyte 相关读书笔记.心得文章列表 Java 流在处理上分为字符流和字节流.字符流处理的单元为 2 个字节的 Unicode 字符,分别操作字符.字符数组或字符串,而字节流处理单元为 1 个字节,操作字节和字节数组. Java 内用 Unicode 编码存储字符,字符流处理类负责将外部的其他

java中的IO基础总结

java中的I/O类库设计可谓是比较丰富的,在我们平时的编程中也经常接触到,往往大部分的系统都有对IO操作的一些封装代码,平时要用到往往翻翻api或者找个写好的方法复制就搞定,由此带来的是对java本身提供的这些方法不熟悉,平时不好好梳理下,对java的io包下面这些常用类也就比较凌乱了.所以这里通过api文档和java.io下面的源码去整理下. 1.表示字节输入输出流的所有类的超类(InputStream/OutputStream) 构造方法:InputStream() 创建一个输入的stre

深入理解 Java中的 流 (Stream)

首先,流是什么? 流是个抽象的概念,是对输入输出设备的抽象,Java程序中,对于数据的输入/输出操作都是以"流"的方式进行.设备可以是文件,网络,内存等. 流具有方向性,至于是输入流还是输出流则是一个相对的概念,一般以程序为参考,如果数据的流向是程序至设备,我们成为输出流,反之我们称为输入流. 可以将流想象成一个"水流管道",水流就在这管道中形成了,自然就出现了方向的概念. 当程序需要从某个数据源读入数据的时候,就会开启一个输入流,数据源可以是文件.内存或网络等等.

JAVA中各种IO的关系及说明

JAVA中的IO以前看着太混乱了,现在梳理一下 1.IO流分为两大类,一个是以stream结尾的,叫做字节流,顾名思义,按照byte为单位进行传输:另一种是以reader和writer结尾的叫做字符流,它貌似是封装了stream结尾的 IO流类,而产生的另一种功能类似,但是传输介质不再是byte,而是字符,也就是说,根据传说字符的不同,比如UTF-8,GBK等,它的传输单位也不是固定的. 2.输入输出,输入指的是从文件向内存中进行读入,输出指的是,内存中的内容写出到文件中 3.常见的Buffer