简单易懂讲IO
流式 IO 是传统 IO,通过构造输入输出流,讲信息从一个地方读取,输出到另一个地方。常见的有读取文件以及写入文件。
基本 API
流失 IO 基本可以分为两个门派,一个以 InputStream 和 OutputStream 为代表的老牌 IO,一个以 Reader 和 Writer 为代表的新派 IO。
这里仅仅展示最常用 API,其余 API 可以查阅jdk API
输入
基本输入
InputStream | Reader |
---|---|
InputStream 面向字节流 IO 不能很好的支持 Unicode 字符 | Reader 面向字符流 IO 能很好的支持 Unicode 字符 |
FileInputStream 文件读取流 | FileReader 文件读取 |
ByteArrayInputStream | CharArrayReader |
装饰器输入
基本输入中的流对象,都可以作为装饰器对象的构造器参数
InputStream | Reader | 功能 |
---|---|---|
DataInputStream | 包含用于读取基本数据类型的全部接口 | |
BufferedInputStream | BufferedReader | 本质上不提供接口,只是向进程添加缓冲功能。与接口对象搭配 |
输出
基本输出
OutputStream | Writer |
---|---|
FileOutputStream | FileWriter |
ByteArrayOutputStream | CharArrayWriter |
装饰器输出
OutputStream | Writer | 功能 |
---|---|---|
DataOutputStream | 包含用于写入基本数据类型的全部接口 | |
PrintStream | PrintWriter | 用于产生格式化输出 |
BufferedOutputStream | BufferedWriter | 本质上并不提供接口,只是向进程添加缓冲功能。与接口对象搭配 |
常见用法
读取文件
使用 FileInputStream 读取
下面例子将输入流放入 try-with-resource 块中,以实现资源的自动关闭,本文下面例子都将采用这种形式。
这里可以看到,是一个字节一个字节的读,所以要将其转为 char 才能正常展示,否则展示的都是字节。 由于 InputStream 是字节流,因此,这里读取到的中文展示乱码。
public class Read {
/**
* 使用 FileInputStream 直接读取
* 由于 InputStream 不支持 Unicode 编码,所以中文显示会乱码
*/
public static void fileInputStream() {
try (
FileInputStream input = new FileInputStream("Read.java")
) {
int n = 0;
while (n != -1) {
n = input.read();
char c = (char) n;
System.out.print(c);
}
} catch (Exception e) {
}
}
public static void main(String[] args) {
Read.fileInputStream();
}
}
输出:
package cyrus.file_io.iostream;
import java.io.FileInputStream;
public class Read {
/**
* ä½¿ç¨ FileInputStream ç´æ¥è¯»å
* ç±äº InputStream ä¸æ¯æ Unicode ç¼ç ï¼æ以ä¸ææ¾ç¤ºä¼ä¹±ç
*/
public static void fileInputStream() {
try (
FileInputStream input = new FileInputStream("Read.java")
) {
int n = 0;
while (n != -1) {
n = input.read();
char c = (char) n;
System.out.print(c);
}
} catch (Exception e) {
}
}
public static void main(String[] args) {
Read.fileInputStream();
}
}
使用 BufferedInputStream 装饰器读取
以下例子使用 FileInputStream 构造一个 BufferedInputStream 装饰器,该适配器的主要作用是会将读取到的内容填充进缓冲区,其余用法和 FileInputStream 一样。InputStream 是字节流,因此,这里读取到的中文展示乱码。
public class Read {
/**
* 使用 FileInputStream 构造一个 BufferedInputStream 装饰器,读取,该读取会使用缓冲区
* 由于 InputStream 不支持 Unicode 编码,所以中文会乱码
*/
public static void fileInputStreamWithBuffer() {
try (
BufferedInputStream input = new BufferedInputStream(new FileInputStream("Read.java"))
) {
int n = 0;
while (n != -1) {
n = input.read();
char c = (char) n;
System.out.print(c);
}
} catch (Exception e) {
}
}
public static void main(String[] args) {
Read.fileInputStreamWithBuffer();
}
}
输出:
package cyrus.file_io.iostream;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
public class Read {
/**
* ä½¿ç¨ FileInputStream æé ä¸ä¸ª BufferedInputStream è£ é¥°å¨ï¼è¯»åï¼è¯¥è¯»åä¼ä½¿ç¨ç¼å²åº
* ç±äº InputStream ä¸æ¯æ Unicode ç¼ç ï¼æ以ä¸æä¼ä¹±ç
*/
public static void fileInputStreamWithBuffer() {
try (
BufferedInputStream input = new BufferedInputStream(new FileInputStream("Read.java"))
) {
int n = 0;
while (n != -1) {
n = input.read();
char c = (char) n;
System.out.print(c);
}
} catch (Exception e) {
}
}
public static void main(String[] args) {
Read.fileInputStreamWithBuffer();
}
}
使用 FileReader 进行读取
使用 FileReader 直接读取,这里 Reader 支持 Unicode 编码,因此中文不会乱码,正常显示
public class Read {
/**
* 使用 FileReader 直接读取
* 由于 Reader 支持 Unicode 编码,因此中文不会乱码,正常显示
*/
public static void fileReader() {
try (
FileReader reader = new FileReader("Read.java")
) {
int n = 0;
while (n != -1) {
n = reader.read();
char c = (char) n;
System.out.print(c);
}
} catch (Exception e) {
}
}
public static void main(String[] args) {
Read.fileReader();
}
}
输出:
package cyrus.file_io.iostream;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileReader;
public class Read {
/**
* 使用 FileReader 直接读取
* 由于 Reader 支持 Unicode 编码,因此中文不会乱码,正常显示
*/
public static void fileReader() {
try (
FileReader reader = new FileReader("Read.java")
) {
int n = 0;
while (n != -1) {
n = reader.read();
char c = (char) n;
System.out.print(c);
}
} catch (Exception e) {
}
}
public static void main(String[] args) {
Read.fileReader();
}
}
使用 BufferedReader 装饰器读取
这里使用 FileReader 构造一个 BufferedReader 装饰器,BufferedReader 的主要作用是会将读取到的内容填入缓冲区,并且 BufferedReader 的 lines() 方法将返回一个 stream 流,操作更方便。
public class Read {
/**
* 使用 FileReader 构造一个 BufferedReader 装饰器,读取,该读取会使用缓冲区
* 由于 Reader 支持 Unicode 编码,因此中文不会乱码,正常显示
*/
public static void fileReaderWithBuffer() {
try (BufferedReader reader = new BufferedReader(new FileReader("Read.java"))) {
reader.lines().forEach(System.out::println);
} catch (Exception e) {
}
}
public static void main(String[] args) {
Read.fileReaderWithBuffer();
}
}
输出:
package cyrus.file_io.iostream;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileReader;
public class Read {
/**
* 使用 FileReader 构造一个 BufferedReader 装饰器,读取,该读取会使用缓冲区
* 由于 Reader 支持 Unicode 编码,因此中文不会乱码,正常显示
*/
public static void fileReaderWithBuffer() {
try (BufferedReader reader = new BufferedReader(new FileReader("Read.java"))) {
reader.lines().forEach(System.out::println);
} catch (Exception e) {
}
}
public static void main(String[] args) {
Read.fileReaderWithBuffer();
}
}
使用 DataInputStream 适配器读取字符串
这里 buildString() 方法读取当前文件,将其拼装为字符串输出,ByteArrayInputStream 读取该字符串的 byte 数组,然后转化为 DataInputStream 适配器进行读取字符串内容。
DataInputStream 主要用于读取基本数据类型
public class Read {
/**
* 使用 ByteArrayInputStream 构造 DataInputStream 装饰器,输出字符串信息
*/
public static void dataInputStream() {
try (
DataInputStream inputStream = new DataInputStream(new ByteArrayInputStream(buildString().getBytes()))
) {
while (inputStream.available() != 0) {
System.out.print((char) inputStream.readByte());
}
} catch (Exception e) {
}
}
/**
* 通过目前 java 文件构建一个字符串
*
* @return
*/
public static String buildString() {
try (BufferedReader reader = new BufferedReader(new FileReader("Read.java"))) {
return reader.lines().collect(Collectors.joining("\n"));
} catch (Exception e) {
}
return "ok";
}
public static void main(String[] args) {
Read.dataInputStream();
}
}
写入文件
使用 FileOutputStream 写入
这里直接使用 FileOutputStream 读取 buildString() 方法构造的字符串并将其写入 Read.txt 文件
public class Read {
/**
* 使用 FileOutputStream 直接写入字符串
*/
public static void fileOutputStream() {
try (
FileOutputStream output = new FileOutputStream("Read.txt")
) {
output.write(buildString().getBytes());
} catch (Exception e) {
}
}
/**
* 通过目前 java 文件构建一个字符串
*
* @return
*/
public static String buildString() {
try (BufferedReader reader = new BufferedReader(new FileReader("Read.java"))) {
return reader.lines().collect(Collectors.joining("\n"));
} catch (Exception e) {
}
return "ok";
}
public static void main(String[] args) {
Read.fileOutputStream();
}
}
输出:实例截图一部分
使用 BufferedOutputStream 适配器写入
这里使用 FileOutputStream 构造一个 BufferedOutputStream 适配器,BufferedOutputStream 会使用到缓冲区,加快读取写入速度。
public class Read {
/**
* 使用 FileOutputStream 构造一个 BufferedOutputStream 装饰器,读取,该写入会使用缓冲区
*/
public static void fileOutputStreamWithBuffer() {
try (
BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream("Read.txt"));
) {
output.write(buildString().getBytes());
} catch (Exception e) {
}
}
/**
* 通过目前 java 文件构建一个字符串
*
* @return
*/
public static String buildString() {
try (BufferedReader reader = new BufferedReader(new FileReader("Read.java"))) {
return reader.lines().collect(Collectors.joining("\n"));
} catch (Exception e) {
}
return "ok";
}
public static void main(String[] args) {
Read.fileOutputStreamWithBuffer();
}
}
后面就不展示输出了,所有的输出都是输出到当前工作目录的Read.txt文件夹下,并且文件内容都是当前 .java 文件的内容
使用 FileWriter 写入
public class Read {
/**
* 使用 FileWriter 直接写入
*/
public static void fileWriter() {
try (
FileWriter writer = new FileWriter("Read.txt");
) {
writer.write(buildString());
} catch (Exception e) {
}
}
/**
* 通过目前 java 文件构建一个字符串
*
* @return
*/
public static String buildString() {
try (BufferedReader reader = new BufferedReader(new FileReader("Read.java"))) {
return reader.lines().collect(Collectors.joining("\n"));
} catch (Exception e) {
}
return "ok";
}
public static void main(String[] args) {
Read.fileWriter();
}
}
使用 PrintWriter 进行输出
这里使用了两层适配器,第一层是使用 FileWriter 构造一个 BufferedWriter,该适配器会使用缓冲区进行写入,然后再使用 BufferedWriter 构造一个PrintWriter 适配器,使用该适配器的println()方法直接输出到指定文件。
public class Read {
/**
* 使用 FileWriter 构造一个 BufferedWriter 装饰器,该装饰器会使用缓冲区,然后再使用 BufferedWriter 构造一个 PrintWriter装饰器,使用 println 输出到文件
*/
public static void fileWriterWithBuffer() {
try (
PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter("Read.txt")))
) {
writer.println(buildString());
} catch (Exception e) {
}
}
/**
* 通过目前 java 文件构建一个字符串
*
* @return
*/
public static String buildString() {
try (BufferedReader reader = new BufferedReader(new FileReader("Read.java"))) {
return reader.lines().collect(Collectors.joining("\n"));
} catch (Exception e) {
}
return "ok";
}
public static void main(String[] args) {
Read.fileWriterWithBuffer();
}
}
总结
流式IO 其实挺好理解的,一共分为两套,InputStream、OutputStream 为一套,Reader 和 Writer 为一套,其中各自都有基本输入输出类和使用基本输入输出类构造的装饰器输入输出类,装饰器还能构造装饰器,无限套娃。
如 new PrintWriter(new BufferedWriter(new FileWriter("Read.txt"))),这里就将 BufferedWriter 装饰器装配成了 PrintWriter 装饰器,这样这个 PrintWriter 就拥有了 BufferedWriter 的特性(使用缓冲区),以及他自己的特性。
文章为本人学习过程中的一些个人见解,漏洞是必不可少的,希望各位大佬多多指教,帮忙修复修复漏洞!!!
参考资料:java 编程思想
欢迎进入本人语雀文档阅读,格式更清晰哦:
https://www.yuque.com/docs/share/26bf2f91-b3d3-4b28-a43e-302a1e650d57?# 《流式 IO》
简单易懂讲IO的更多相关文章
- 简单聊下IO复用
没图,不分析API Java中IO API的发展:Socket -> SocketChannel -> AsynchronousSocketChannelServerSocket -> ...
- 【repost】让你一句话理解闭包(简单易懂)
接触javascript很久了,每次理解闭包都似是而非,最近在找Web前端的工作,所以需要把基础夯实一下. 本文是参照了joy_lee的博客 闭包 在她这篇博客的基础上以批注的形式力争把我的理解阐述出 ...
- 【转】JS回调函数--简单易懂有实例
JS回调函数--简单易懂有实例 初学js的时候,被回调函数搞得很晕,现在回过头来总结一下什么是回调函数. 我们先来看看回调的英文定义:A callback is a function that is ...
- java生成RSA公私钥字符串,简单易懂
java生成RSA公私钥字符串,简单易懂 解决方法: 1.下载bcprov-jdk16-140.jar包,参考:http://www.yayihouse.com/yayishuwu/chapter ...
- HashSet的实现原理,简单易懂
HashSet的实现原理,简单易懂 答: HashSet实际上是一个HashMap实例,都是一个存放链表的数组.它不保证存储元素的迭代顺序:此类允许使用null元素.HashSet中不允许有重复元 ...
- Linux服务器评测脚本 中文IO脚本简单易懂
中文版: wget -N --no-check-certificate https://raw.githubusercontent.com/FunctionClub/ZBench/master/ZBe ...
- MEF入门之不求甚解,但力求简单能讲明白(四)
上一篇我们已经可以获取各种FileHandler的实例和对应的元数据.本篇,我们做一个稍微完整的文件管理器. 1.修改接口IFileHandler,传入文件名 namespace IPart { pu ...
- 简单易懂, JUnit 框架问答
本文算是一个关于Junit4相关的知识分享,但是不同于网上大段的源码分析,模式学习文章,我想通过问答的形式,引出代码来简明阐述JUnit4是如何实现需要的功能的. 考虑到任何一个框架,都是为了解决问题 ...
- Http与协议TCP协议简单易懂
于C#编写代码,很多时候会遇到Http协议或TCP合约,这里做一个简单的了解. TCP对应于该传送层协议,和HTTP对应于应用层协议,从本质上讲,两者是没有可比性.Http该协议是基于TCP之上的,当 ...
随机推荐
- 痞子衡嵌入式:嵌入式Cortex-M中断向量表对齐原则的深入研究
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是Cortex-M中断向量表对齐原则. 今天这篇文章的内容主要来自于五年前做 Kinetis K32W 系列双核启动时的发现,最近正好有同 ...
- 使用Git上传项目到GitHub仓库
GitHub账号注册很长时间了,但是没怎么上传过东西.今天学习如何利用Git工具将代码上传到GitHub,了解了一些常用命令 $ git config --global user.name " ...
- HTML音乐悬浮播放器
话不多说先上代码 <link rel="stylesheet" href="http://47.102.203.92/css/APlayer.min.css&quo ...
- Docker系列(21)- DockerFile介绍
DockerFile介绍 dockerfile是用来构建docker镜像的文件!命令参数脚本! 构建步骤 编写一个dockerfile文件 docker build构建成为一个镜像 docker ru ...
- vue 改变路由参数
更改路由传递的参数: const query = JSON.parse(JSON.stringify(this.$route.query)) // 获取路由参数信息 query.id = Name / ...
- Consul+Ocelot+Polly在.NetCore中使用(.NET5)-Ocelot+Polly缓存、限流、熔断、降级
相关文章 Consul+Ocelot+Polly在.NetCore中使用(.NET5)-Consul服务注册,服务发现 Consul+Ocelot+Polly在.NetCore中使用(.NET5)-网 ...
- sessionId在小程序中的妙用
前言:小程序发送短信验证码需要在后台储存生成的code,一次会话应放入session中,请求头部发送sessionId验证为同一session 1.页面一加载就从后台获取sessionId,储存在本地 ...
- Docker入门系列之五:15个 Docker 命令
在这篇文章中,我们将学习15个Dockers CLI命令.如果你还不了解Docker,请查看这个系列的其他部分进行学习,Docker概念,生态系统,Dockerfile,Docker镜像. Docke ...
- FastAPI(56)- 使用 Websocket 打造一个迷你聊天室
背景 在实际项目中,可能会通过前端框架使用 WebSocket 和后端进行通信 这里就来详细讲解下 FastAPI 是如何操作 WebSocket 的 模拟 WebSocket 客户端 #!usr/b ...
- window.postMessage 在iframe父子页面数据传输
介绍 https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage window.postMessage 发送方 接收方 示例 ...