大聪明教你学Java | 深入浅出聊基础 Java IO流(从此不在怕 IO)

2024-03-07 06:40

本文主要是介绍大聪明教你学Java | 深入浅出聊基础 Java IO流(从此不在怕 IO),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

我们在开发软件的过程中可以发现,几乎所有的应用软件都离不开信息的输入和输出,比如从键盘读取数据、从文件中获取数据、向文件中存入数据等等,这些情况下都会涉及有关输入、输出的处理,也就是涉及到了 Java 的 IO 流。可能很多小伙伴对 IO 流都不太了解(有的小伙伴甚至看到 IO 流就会主动逃避),那么今天就来聊聊基础的 Java IO 流,让各位小伙伴从此不在怕 IO。

基础 Java IO 流

首先咱们先看看 IO 流的概念(以下内容来自百度👇)

流是一种抽象概念,它代表了数据的无结构化传递。按照流的方式进行输入输出,数据被当成无结构的字节序或字符序列。从流中取得数据的操作称为提取操作,而向流中添加数据的操作称为插入操作。用来进行输入输出操作的流就称为IO流。换句话说,IO流就是以流的方式进行输入输出 。

百度给出的基本概念可能有些难理解,那么大聪明依然是秉承着“繁琐问题必有猥琐解法”的宗旨来给各位小伙伴用大白话讲讲 IO 流。

咱们先举个简单的例子:我们用水壶往杯子里倒水的时候,水壶里的水不可能一下子就跑到杯子里,而是需要一个倒水的过程。这个过程是一个连续的过程,源源不断进行着。回到计算机上来,我们需要将硬盘里的数据传到内存中以便处理,但是由于传输带宽等方面的限制,硬盘中的数据不可能立马就传到内存中,而是需要一点点进行的,就像从水壶里往杯子里倒水一样。流这个词,生动形象说明了数据传输的过程。

在前言中我们提到了“几乎所有的应用软件都离不开信息的输入和输出”,那么我们输入或者输出的是什么东西呢?没错,我们输入或输出的就是数据(也就是一组有顺序的、有起点和终点的字节集合),我们将这些数据称作为数据流(Data Stream),下面我们再看看关于流的分类👇。

① 按照数据流的流向,我们可以将其分为输入流和输出流(需要注意的是:这里的输入、输出是针对程序来说的),把数据从其他设备上读取到内存中的流就是输入流,把数据从内存中写出到其他设备上的流就是输出流。
② 按照所处理的数据的单位,我们可以将其分为字节流和字符流,字节流的含义就是每次读取(或写入)一个字节,此时如果传输的资源文件有中文,那么就会出现乱码;字符流的含义就是每次读取(写入)两个字节,使用字符流可以正确的显示中文(1字符 = 2字节, 一个汉字占两个字节长度)。字节流一般用来处理图像、视频、音频、PPT、Word等类型的文件;字符流一般用于处理纯文本类型的文件,如 txt 文件等,但不能处理图像或者视频之类的非文本文件。用一句话总结一下就是:字节流可以处理一切文件,而字符流只能处理纯文本文件。
③ 按照流的角色进行划分,我们还可以将其分为节点流和处理流,节点流指的是可以从(向)一个特定的 IO 设备(如磁盘,网络)读取(写入)数据的流(与“数据源”和“目的地”直接相连);处理流则是用于对一个已存在的流进行连接和封装,通过封装后的流来实现数据的读/写功能(不直接连接到“数据源”和“目的地”上,而是连接在已存在的流上)。如下图所示👇

在这里插入图片描述
④ 缓冲流,缓冲流是诸多流中尤为重要的一员。程序与磁盘的交互的速度相对于内存运算的速度是很慢的,也就说程序与磁盘的交互效率的高低直接影响到了程序性能的高低,为了提高程序与磁盘的交互的效率,缓冲流也就应运而生了,缓冲流在内存中设置一个缓冲区,普通流每读取一个子节,就将该子节先存入缓冲区,当缓冲区存储了足够的子节后再与磁盘进行交互,也就是在保证了在总数据量不变的情况下,通过提高每次交互的数据量,减少了交互次数,从而提高了交互效率。举个例子,我们在搬家的时候总会找个小货车来帮我们搬家,我们把需要搬走的行李先放到小货车上,等小货车装满了以后再开车往新家运送,我们借助小货车减少了我们往返旧家和新家的次数,从而提升了搬家的效率,这里的小货车就是缓冲区,我们自己就普通流,自己的行李就是普通流读取的子节。(这要是靠两条腿搬着行李往返新家和旧家,估计搬三天都搬不完😂)
P.S. 使用缓冲流不一定会提升程序运行效率,是否使用缓冲流就需要具体情况具体分析了

翠花~ 上代码!

上面说了那么多理论性的东西,我们还是通过代码来看看如何使用 Java IO流。

字节流

import java.io.*;/*** IO流的应用* @description: IODemo* @author: 庄霸.liziye* @create: 2022-01-19 15:44**/
public class IODemo {// 要写入的字符串private static String text = "我在人民广场吃着炸鸡~";public static void main(String[] args) throws IOException {File file = new File("G:/IODemo.txt");write(file);String result = read(file);System.out.println("result = " + result);}public static void write(File file) throws IOException {OutputStream os = new FileOutputStream(file, true);// 写入文件os.write(text.getBytes());// 关闭流os.close();}public static String read(File file) throws IOException {InputStream in = new FileInputStream(file);// 一次性取多少个字节byte[] bytes = new byte[1024];// 用来接收读取的字节数组StringBuilder sb = new StringBuilder();// 读取到的字节数组长度,为-1时表示没有数据int length = 0;// 循环取数据while ((length = in.read(bytes)) != -1) {// 将读取的内容转换成字符串sb.append(new String(bytes, 0, length));}// 关闭流in.close();return sb.toString();}
}

在这里插入图片描述

缓冲字节流

import java.io.*;/*** IO流的应用* @description: IODemo* @author: 庄霸.liziye* @create: 2022-01-19 15:44**/
public class IODemo {/*** 待写入的文本*/private static String text = "又买了一只炸鸡~我在人民广场吃着炸鸡~";public static void main(String[] args) throws IOException {File file = new File("G:/IODemo.txt");write(file);String result = read(file);System.out.println("result = " + result);}public static void write(File file) throws IOException {// 缓冲字节流,提高了效率BufferedOutputStream bis = new BufferedOutputStream(new FileOutputStream(file, true));// 写入文件bis.write(text.getBytes());// 关闭流bis.close();}public static String read(File file) throws IOException {BufferedInputStream fis = new BufferedInputStream(new FileInputStream(file));// 一次性取多少个字节byte[] bytes = new byte[1024];// 用来接收读取的字节数组StringBuilder sb = new StringBuilder();// 读取到的字节数组长度,为-1时表示没有数据int length = 0;// 循环取数据while ((length = fis.read(bytes)) != -1) {// 将读取的内容转换成字符串sb.append(new String(bytes, 0, length));}// 关闭流fis.close();return sb.toString();}
}

在这里插入图片描述

字符流

import java.io.*;/*** IO流的应用* @description: IODemo* @author: 庄霸.liziye* @create: 2022-01-19 15:44**/
public class IODemo {/*** 待写入的文本*/private static String text = "买了第三只炸鸡~我在人民广场吃着炸鸡~";public static void main(String[] args) throws IOException {File file = new File("G:/IODemo.txt");write(file);String result = read(file);System.out.println("result = " + result);}public static void write(File file) throws IOException {// OutputStreamWriter可以显示指定字符集,否则使用默认字符集OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(file, true), "UTF-8");osw.write(text);osw.close();}public static String read(File file) throws IOException {InputStreamReader isr = new InputStreamReader(new FileInputStream(file), "UTF-8");// 字符数组:一次读取多少个字符char[] chars = new char[1024];// 每次读取的字符数组先append到StringBuilder中StringBuilder sb = new StringBuilder();// 读取到的字符数组长度,为-1时表示没有数据int length = 0;// 循环取数据while ((length = isr.read(chars)) != -1) {// 将读取的内容转换成字符串sb.append(chars, 0, length);}// 关闭流isr.close();return sb.toString();}
}

在这里插入图片描述

缓冲字符流

import java.io.*;/*** IO流的应用* @description: IODemo* @author: 庄霸.liziye* @create: 2022-01-19 15:44**/
public class IODemo {/*** 待写入的文本*/private static String text = "买了第四只炸鸡~我在人民广场吃着炸鸡~";public static void main(String[] args) throws IOException {File file = new File("G:/IODemo.txt");write(file);String result = read(file);System.out.println("result = " + result);}public static void write(File file) throws IOException {BufferedWriter bw = new BufferedWriter(new FileWriter(file, true));bw.write(text);bw.close();}public static String read(File file) throws IOException {BufferedReader br = new BufferedReader(new FileReader(file));// 用来接收读取的字节数组StringBuilder sb = new StringBuilder();// 按行读数据String line;// 循环取数据while ((line = br.readLine()) != null) {// 将读取的内容转换成字符串sb.append(line);}// 关闭流br.close();return sb.toString();}
}

在这里插入图片描述

IO流中常用的方法

IO 流中的方法有很多,想把所有的方法都学个遍还是有点难度的,最后给大家整理出了 IO 流的常用方法,供大家参考和学习👇

字节输入流 InputStream

int read():读取单个子节。
int read(byte[] b):将多个字节读到数组中。
int read(byte[] b, int off, int len):读取长度为 len 的数据,从数组 b 中下标为 off 的位置开始放置读取的数据,读完返回读取的字节数。
void close():关闭数据流。
int available():返回目前可以从数据流中读取的字节数。
long skip(long l):跳过数据流中指定数量的字节,返回值代表实际跳过的字节数。

字节输出流 OutputStream

void write(int i):将字节 i 写入到数据流中,它只输出所读入参数的最低 8 位,该方法是抽象方法,需要在其输出流子类中加以实现,然后才能使用。
void write(byte[] b):将数组 b 中的全部字节写入数据流。
void write(byte[] b, int off, int len):将数组 b 中从下标 off 开始的 len 个字节写入数据流。从 b[off] 开始,到 b[off + len - 1] 结束。
void close():关闭输出流,关闭前需要刷新流。
void flush():刷新流并强制写出所有缓冲的输出字节。

字符输入流 InputStreamReader

int read():读取单个字符。
int read(char[] cbuf):将字符读入数组
abstract int read(char[] cbuf, int off, int len):读取长度为 len 的数据,从数组 cbuf 中下标为 off 的位置开始放置读取的数据,读完返回读取的字节数。
long skip(long n):跳过数据流中指定数量的字节,返回值代表实际跳过的字节数。
abstract void close():关闭数据流。

字符输出流 OutputStreamWriter

void write(char[] cbuf):将字符数组写入数据流
abstract void write(char[] cbuf, int off, int len):将字符数组 cbuf 中从下标 off 开始的 len 个字节写入数据流。从 b[off] 开始,到 b[off + len - 1] 结束
void write(int c):写入单个字符
void write(String str):写入字符串
void write(String str, int off, int len):写入字符串的某一部分
Writer append(char c):将指定字符添加到此 writer
Writer append(CharSequence csq):将指定字符序列添加到此 writer
Writer append(CharSequence csq, int start, int end): 将指定字符序列的子序列添加到此 writer.Appendable
abstract void close(): 关闭此流,但要先刷新它
abstract void flush():刷新该流的缓冲

小结

本人经验有限,有些地方可能讲的没有特别到位,如果您在阅读的时候想到了什么问题,欢迎在评论区留言,我们后续再一一探讨🙇‍

希望各位小伙伴动动自己可爱的小手,来一波点赞+关注 (✿◡‿◡) 让更多小伙伴看到这篇文章~ 蟹蟹呦(●’◡’●)

如果文章中有错误,欢迎大家留言指正;若您有更好、更独到的理解,欢迎您在留言区留下您的宝贵想法。

你在被打击时,记起你的珍贵,抵抗恶意;
你在迷茫时,坚信你的珍贵,抛开蜚语;
爱你所爱 行你所行 听从你心 无问东西

这篇关于大聪明教你学Java | 深入浅出聊基础 Java IO流(从此不在怕 IO)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/782659

相关文章

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Java判断多个时间段是否重合的方法小结

《Java判断多个时间段是否重合的方法小结》这篇文章主要为大家详细介绍了Java中判断多个时间段是否重合的方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录判断多个时间段是否有间隔判断时间段集合是否与某时间段重合判断多个时间段是否有间隔实体类内容public class D

IDEA编译报错“java: 常量字符串过长”的原因及解决方法

《IDEA编译报错“java:常量字符串过长”的原因及解决方法》今天在开发过程中,由于尝试将一个文件的Base64字符串设置为常量,结果导致IDEA编译的时候出现了如下报错java:常量字符串过长,... 目录一、问题描述二、问题原因2.1 理论角度2.2 源码角度三、解决方案解决方案①:StringBui

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

Java中ArrayList和LinkedList有什么区别举例详解

《Java中ArrayList和LinkedList有什么区别举例详解》:本文主要介绍Java中ArrayList和LinkedList区别的相关资料,包括数据结构特性、核心操作性能、内存与GC影... 目录一、底层数据结构二、核心操作性能对比三、内存与 GC 影响四、扩容机制五、线程安全与并发方案六、工程

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.

Spring AI集成DeepSeek的详细步骤

《SpringAI集成DeepSeek的详细步骤》DeepSeek作为一款卓越的国产AI模型,越来越多的公司考虑在自己的应用中集成,对于Java应用来说,我们可以借助SpringAI集成DeepSe... 目录DeepSeek 介绍Spring AI 是什么?1、环境准备2、构建项目2.1、pom依赖2.2