Java——I/O流(一):字节流(概念理解+应用举例)

简介: Java——I/O流(一):字节流(概念理解+应用举例)

1.I/O流概述


定义:I/OInput/Output)流,即输入/输出流,是Java 中实现输入/输出的基础,它可以方便地实现数据的输入/输出操作。

可分为如下几类:👇👇👇 

结构:Java 中的 I/O 流主要定义在 java.io 包中,该包下定义了很多类,其中有4个类为流的顶级类,分别为 InputStream OutputStreamReader Writer 

说明:InputStream OutPutStream 是字节流,而 Reader Writer 是字符流。

          InputStreamReader是输入流,而OutPutStreamWriter是输出流。

          下图中的4个顶级类都是抽象类,并且是所有流类型的父类。

 

2.字节流概述


定义:在计算机中,无论是文本、图片、音频还是视频,所有文件都是以二进制(字节)形式存在的,I/O流中针对字节的输入/输出提供了一系列的流,统称为字节流。 

说明:字节流是程序中最常用的流。

          JDK中,所有的字节输入流都继承自InputStream,所有的字节输出流都继承自 OutputStream

2.1 字节输入流InputStream常用的方法


2.2 字节输出流OutputStream常用的方法

2.3 InputStreamOutputStream的继承体系

 

3.字节流读写文件


说明:针对文件的读写操作,JDK专门提供了两个类,分别是FileInputStream FileOutputStream

          FileInputStream InputStream 的子类,它是操作文件的字节输入流,专门用于读取文件中的数据。 

          从文件读取数据是重复的操作,因此需要通过循环语句来实现数据的持续读取。


3.1 字节输出流读写文件


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

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

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

import java.io.*;
public class IODemo01 {
  public static void main(String[] args) throws IOException {
    //使用文件名创建字节流对象
    FileOutputStream fos1=new FileOutputStream("FOS1.txt");
    fos1.write(65);//依次写出三个字节的数据
    fos1.write(66);
    fos1.write(67);
    fos1.close();//关闭字节输出流,并释放资源
    FileOutputStream fos2=new FileOutputStream("FOS2.txt");
    byte[] bytes2={97,98,99};//创建一个byte数组
    fos2.write(bytes2);//将bytes2字节数组中的所有字节写入fos2输出流
    fos2.close();//关闭字节输出流,并释放资源
    FileOutputStream fos3=new FileOutputStream("FOS3.txt");
    byte[] bytes3={97,98,99,100,101,102};
    //将bytes3数组中从1开始往后的4个字节写入fos3输出流
    fos3.write(bytes3,1,4);//即字节98,99,100,101
    fos3.close();//关闭字节输出流,并释放资源
    FileOutputStream fos4=new FileOutputStream("FOS4.txt");
    String str1="大佬,你好!";//创建一个字符串
    byte[] bytes4=str1.getBytes();//调用String类的getBytes()方法将该字符串转为byte数组
    fos4.write(bytes4);//将bytes4字节数组中的所有字节写入fos4输出流
    fos4.close();//关闭字节输出流,并释放资源
    /**字节输出流的续写,有如下两个构造方法
     * public FileOutputStream(File file, boolean append)
     * 创建文件输出流以写入,由指定的File对象表示的文件
     * 
     * public FileOutputStream(String name, boolean append)
     * 创建文件输出流以指定的名称写入文件
     * 参数中有一个boolean类型的值:true表示追加数据,false表示清空原有数据 
     */
    FileOutputStream fos5=new FileOutputStream("FOS5.txt",true);
    String str2="一路相遇,";
    byte[] bytes5=str2.getBytes();
    fos5.write(bytes5);//第一次向"FOS5.txt"文件中写入相应的内容
    String str3="感谢有你!";
    byte[] bytes6=str3.getBytes();
    fos5.write(bytes6);//第二次向"FOS5.txt"文件中追加写入相应的内容
    fos5.close();//关闭字节输出流,并释放资源
    FileOutputStream fos6=new FileOutputStream("FOS6.txt",true);
    String str4="天行健,君子以自强不息!";
    byte[] bytes7=str4.getBytes();
    fos6.write(bytes7);//第一次向"FOS6.txt"文件中写入相应内容
    String str5="\n";
    byte[] bytes8=str5.getBytes();
    fos6.write(bytes8);//第二次向"FOS5.txt"文件中写入一个换行
    String str6="地势坤,君子以厚德载物!";
    byte[] bytes9=str6.getBytes();
    fos6.write(bytes9);//第三次向"FOS5.txt"文件中写入相应内容
    fos6.close();//关闭字节输出流,并释放资源
  }
}

在运行上述代码之后,我们就可以在指定的文件路径下,找到我们所写的文件以及相应的内容。如下图:👇👇👇 

3.2 字节输入流读写文件


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

1.  构造方法:

2.  //通过打开与实际文件的连接来创建一个FileInputStream,该文件由文件系统中的路径名name命名

3.  public FileInputStream(String name) throws FileNotFoundException

4.   

5.  //通过打开与实际文件的连接来创建一个FileInputStream,该文件由文件系统中的File对象file命名

6.  public FileInputSt

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


import java.io.*;
public class IODemo02 {
  public static void main(String[] args) throws IOException {
    //创建FileInputStream对象,构造方法中绑定要读取的数据源
    FileInputStream fis1=new FileInputStream("E:/Eclipse/Java Project/Love/FOS1.txt");
    System.out.println("读取文件FOS1中的内容:");
    int len=0;
    //read()方法是一个字节一个字节的进行读取
    while((len=fis1.read())!=-1) {
      System.out.print((char)len + " ");
    }
    /*int byte0=fis1.read();
    char ch0=(char)byte0;//65 对应字符 A
    System.out.println(byte0 + " 对应:" + ch0);
    int byte1=fis1.read();
    char ch1=(char)byte1;//66 对应字符 B
    System.out.println(byte1 + " 对应:" + ch1);
    int byte2=fis1.read();
    char ch2=(char)byte2;//67 对应字符 C
    System.out.println(byte2 + " 对应:" + ch2);
    int byte3=fis1.read();
    char ch3=(char)byte3;
    System.out.println(byte3 + " 对应:" + ch3);
    此时已将FOS1文件中的内容全部读完,再进行读取,将输出-1*/
    fis1.close();//关闭字节输入流,并释放资源
                System.out.print();
    FileInputStream fis2=new FileInputStream("E:/Eclipse/Java Project/Love/FOS2.txt");
    System.out.println("读取文件FOS2中的内容:");
    byte[] bytes1=new byte[3];
    int len1=fis2.read(bytes1);
    for(int i=0;i<len1;i++) {
      char ch3=(char)bytes1[i];
      System.out.print(ch3 + " ");
    }
    fis2.close();//关闭字节输入流,并释放资源
    System.out.println();
    FileInputStream fis3=new FileInputStream("E:/Eclipse/Java Project/Love/FOS3.txt");
    System.out.println("读取文件FOS3中的内容:");
    byte[] bytes2=new byte[5];
    int len2=fis3.read(bytes2,1,4);//len2=4
    for(int i=1;i<=4;i++) {
      char ch4=(char)bytes2[i];
      System.out.print(ch4 + " ");
    }
    fis3.close();//关闭字节输入流,并释放资源
    System.out.println();
  }
}

在运行上述代码之后,可以看到下面的运行结果,以及我们拷贝文件的结果。如下图:👇👇👇


3.3 字节缓冲流的效率测试


缓冲流,也叫高效流。能够高效读写缓冲流,能够转换编码的转换流,能够持久化存储对象的序列化对象等等。它是四个基本File流的增强,所以也是4个流,按照数据类型分类。

·       字节缓冲流:BufferedInputStreamBufferedOutputStream

·       字符缓冲流:BufferedReaderBufferedWriter

缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO读取次数,从而提高读写的效率。

说明:除了定义字节缓冲区来提高文件拷贝效率外,IO中还提供了两个字节缓冲流来提高文件拷贝效率:BufferedInputStream BufferedOutputStream。它们的构造方法中分别接收 InputStream OutputStream 类型的参数作为对象,在读写数据时提供缓冲功能。 

构造方法:
//创建一个新的字节缓冲输入流
BufferedInputStream(InputStream in)
BufferedInputStream(InputStream in, int size)
//创建一个新的字节缓冲输出流
BufferedOutputStream(OutputStream out)//将数据写入指定的底层输出流
BufferedOutputStream(OutputStream out, int size)//将具有指定缓冲区大小的数据写入指定的底层输出流
//参数:
InputStream in:字节输入流
OutputStream out:字节输出流
int size:缓冲区大小,不写的话,默认
import java.io.*;
public class IODemo03 {
  public static void main(String[] args) throws IOException {
    //普通的文件拷贝
    long beginTime1=System.currentTimeMillis();
    FileInputStream FIS1=new FileInputStream("E:/Eclipse/Java Project/Love/集合.jpg");
    FileOutputStream FOS1=new FileOutputStream("E:/Eclipse/Java Project/Love/集合1.jpg");
    System.out.print("普通的文件拷贝");
    int length1=0;
    while((length1=FIS1.read())!=-1) {
      FOS1.write(length1);
    }
    FIS1.close();//关闭字节输入流,并释放资源
    FOS1.close();//关闭字节输出流,并释放资源
    long endTime1=System.currentTimeMillis();
    System.out.println("花费的时间为:" + (endTime1-beginTime1) + "ms");
    //使用字节流的缓冲区进行文件拷贝
    long beginTime2=System.currentTimeMillis();
    FileInputStream FIS2=new FileInputStream("E:/Eclipse/Java Project/Love/集合.jpg");
    FileOutputStream FOS2=new FileOutputStream("E:/Eclipse/Java Project/Love/集合2.jpg");
    System.out.print("使用字节流的缓冲区进行文件拷贝");
    int length2=0;
    byte[] bytes1=new byte[1024];
    while((length2=FIS2.read(bytes1))!=-1) {
      FOS2.write(bytes1,0,length2);
    }
    FIS2.close();//关闭字节输入流,并释放资源
    FOS2.close();//关闭字节输出流,并释放资源
    long endTime2=System.currentTimeMillis();
    System.out.println("花费的时间为:" + (endTime2-beginTime2) + "ms");
    //使用字节缓冲流进行文件拷贝
    long beginTime3=System.currentTimeMillis();
    BufferedInputStream BIS=new BufferedInputStream(new FileInputStream("E:/Eclipse/Java Project/Love/集合.jpg"));
    BufferedOutputStream BOS=new BufferedOutputStream(new FileOutputStream("E:/Eclipse/Java Project/Love/集合3.jpg"));
    System.out.print("使用字节缓冲流进行文件拷贝");
    int length3=0;
    byte[] bytes2=new byte[1024];
    while((length3=BIS.read(bytes2))!=-1) {
      BOS.write(bytes2,0,length3);
    }
    BIS.close();//关闭字节缓冲输入流,并释放资源
    BOS.close();//关闭字节缓冲输出流,并释放资源
    long endTime3=System.currentTimeMillis();
    System.out.println("花费的时间为:" + (endTime3-beginTime3) + "ms");
  }
}


从图中可以看出拷贝文件所消耗的时间明显减少了很多,这说明使用字节缓冲流同样可以有效的提高程序的传输效率。

这种方式与字节流的缓冲区类似,都对数据进行了缓冲,从而有效的提高了数据的读写效率。 

相关文章
|
2月前
|
人工智能 算法 Java
Java与AI驱动区块链:构建智能合约与去中心化AI应用
区块链技术和人工智能的融合正在开创去中心化智能应用的新纪元。本文深入探讨如何使用Java构建AI驱动的区块链应用,涵盖智能合约开发、去中心化AI模型训练与推理、数据隐私保护以及通证经济激励等核心主题。我们将完整展示从区块链基础集成、智能合约编写、AI模型上链到去中心化应用(DApp)开发的全流程,为构建下一代可信、透明的智能去中心化系统提供完整技术方案。
293 3
|
2月前
|
Java 编译器 Go
【Java】(5)方法的概念、方法的调用、方法重载、构造方法的创建
Java方法是语句的集合,它们在一起执行一个功能。方法是解决一类问题的步骤的有序组合方法包含于类或对象中方法在程序中被创建,在其他地方被引用方法的优点使程序变得更简短而清晰。有利于程序维护。可以提高程序开发的效率。提高了代码的重用性。方法的名字的第一个单词应以小写字母作为开头,后面的单词则用大写字母开头写,不使用连接符。例如:addPerson。这种就属于驼峰写法下划线可能出现在 JUnit 测试方法名称中用以分隔名称的逻辑组件。
222 4
|
2月前
|
消息中间件 缓存 Java
Spring框架优化:提高Java应用的性能与适应性
以上方法均旨在综合考虑Java Spring 应该程序设计原则, 数据库交互, 编码实践和系统架构布局等多角度因素, 旨在达到高效稳定运转目标同时也易于未来扩展.
150 8
|
3月前
|
人工智能 Java API
Java与大模型集成实战:构建智能Java应用的新范式
随着大型语言模型(LLM)的API化,将其强大的自然语言处理能力集成到现有Java应用中已成为提升应用智能水平的关键路径。本文旨在为Java开发者提供一份实用的集成指南。我们将深入探讨如何使用Spring Boot 3框架,通过HTTP客户端与OpenAI GPT(或兼容API)进行高效、安全的交互。内容涵盖项目依赖配置、异步非阻塞的API调用、请求与响应的结构化处理、异常管理以及一些面向生产环境的最佳实践,并附带完整的代码示例,助您快速将AI能力融入Java生态。
586 12
|
3月前
|
安全 Java API
Java SE 与 Java EE 区别解析及应用场景对比
在Java编程世界中,Java SE(Java Standard Edition)和Java EE(Java Enterprise Edition)是两个重要的平台版本,它们各自有着独特的定位和应用场景。理解它们之间的差异,对于开发者选择合适的技术栈进行项目开发至关重要。
469 1
|
4月前
|
设计模式 XML 安全
Java枚举(Enum)与设计模式应用
Java枚举不仅是类型安全的常量,还具备面向对象能力,可添加属性与方法,实现接口。通过枚举能优雅实现单例、策略、状态等设计模式,具备线程安全、序列化安全等特性,是编写高效、安全代码的利器。
|
4月前
|
机器学习/深度学习 人工智能 自然语言处理
Java 大视界 -- Java 大数据机器学习模型在自然语言生成中的可控性研究与应用(229)
本文深入探讨Java大数据与机器学习在自然语言生成(NLG)中的可控性研究,分析当前生成模型面临的“失控”挑战,如数据噪声、标注偏差及黑盒模型信任问题,提出Java技术在数据清洗、异构框架融合与生态工具链中的关键作用。通过条件注入、强化学习与模型融合等策略,实现文本生成的精准控制,并结合网易新闻与蚂蚁集团的实战案例,展示Java在提升生成效率与合规性方面的卓越能力,为金融、法律等强监管领域提供技术参考。
|
2月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
196 1
|
2月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
221 1
|
3月前
|
数据采集 存储 弹性计算
高并发Java爬虫的瓶颈分析与动态线程优化方案
高并发Java爬虫的瓶颈分析与动态线程优化方案