流式 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的更多相关文章

  1. 简单聊下IO复用

    没图,不分析API Java中IO API的发展:Socket -> SocketChannel -> AsynchronousSocketChannelServerSocket -> ...

  2. 【repost】让你一句话理解闭包(简单易懂)

    接触javascript很久了,每次理解闭包都似是而非,最近在找Web前端的工作,所以需要把基础夯实一下. 本文是参照了joy_lee的博客 闭包 在她这篇博客的基础上以批注的形式力争把我的理解阐述出 ...

  3. 【转】JS回调函数--简单易懂有实例

    JS回调函数--简单易懂有实例 初学js的时候,被回调函数搞得很晕,现在回过头来总结一下什么是回调函数. 我们先来看看回调的英文定义:A callback is a function that is ...

  4. java生成RSA公私钥字符串,简单易懂

    java生成RSA公私钥字符串,简单易懂   解决方法: 1.下载bcprov-jdk16-140.jar包,参考:http://www.yayihouse.com/yayishuwu/chapter ...

  5. HashSet的实现原理,简单易懂

    HashSet的实现原理,简单易懂   答: HashSet实际上是一个HashMap实例,都是一个存放链表的数组.它不保证存储元素的迭代顺序:此类允许使用null元素.HashSet中不允许有重复元 ...

  6. Linux服务器评测脚本 中文IO脚本简单易懂

    中文版: wget -N --no-check-certificate https://raw.githubusercontent.com/FunctionClub/ZBench/master/ZBe ...

  7. MEF入门之不求甚解,但力求简单能讲明白(四)

    上一篇我们已经可以获取各种FileHandler的实例和对应的元数据.本篇,我们做一个稍微完整的文件管理器. 1.修改接口IFileHandler,传入文件名 namespace IPart { pu ...

  8. 简单易懂, JUnit 框架问答

    本文算是一个关于Junit4相关的知识分享,但是不同于网上大段的源码分析,模式学习文章,我想通过问答的形式,引出代码来简明阐述JUnit4是如何实现需要的功能的. 考虑到任何一个框架,都是为了解决问题 ...

  9. Http与协议TCP协议简单易懂

    于C#编写代码,很多时候会遇到Http协议或TCP合约,这里做一个简单的了解. TCP对应于该传送层协议,和HTTP对应于应用层协议,从本质上讲,两者是没有可比性.Http该协议是基于TCP之上的,当 ...

随机推荐

  1. 我爬取交通学博士付费的GIS资源,每年被动收入2w很简单?

    目录 1.背景介绍 2.技术路线 3.数据结果 4.数据分析 5.总结 6.后记 1.背景介绍 某周末闲来无事,顺手打开了CSDN,看到了一个人发布的收费GIS资源,售价是¥19.9,POI数据也有人 ...

  2. 一起搞懂PHP的错误和异常(三)

    关于错误与异常的最后一篇文章,我们来进行一些总结. PHP中错误和异常的区别 通过前面两篇文章的学习,我们来直接将错误和异常摆上来进行对比,看看他们的区别与联系: 错误的出现通常是语法或编译运行时错误 ...

  3. seo优化刷百度指数方法

    站长朋友们都听过"刷指数"这个概念,并且一直以来都有站长刷指数的现象.大家或为了提升网站数据,或为了满足排名的虚荣心,或为了与竞争对手抗衡,都或多或少研究过刷指数的原理和工具. 那 ...

  4. (转载)Select for update/lock in share mode 对事务并发性影响

    select for update/lock in share mode 对事务并发性影响 事务并发性理解 事务并发性,粗略的理解就是单位时间内能够执行的事务数量,常见的单位是 TPS( transa ...

  5. Windows下升级Python3.7.7后(原Python3.6.2版本)如何切换Python版本

    笔者:风起怨江南 出处:https://www.cnblogs.com/mengjinxiang 笔者原创,文章欢迎转载,如果喜欢请点赞+关注,谢谢! 问题:window系统下,如果升级了最新的Pyt ...

  6. 『GoLang』协程与通道

    作为一门 21 世纪的语言,Go 原生支持应用之间的通信(网络,客户端和服务端,分布式计算)和程序的并发.程序可以在不同的处理器和计算机上同时执行不同的代码段.Go 语言为构建并发程序的基本代码块是 ...

  7. 鸿蒙内核源码分析(字符设备篇) | 字节为单位读写的设备 | 百篇博客分析OpenHarmony源码 | v67.01

    百篇博客系列篇.本篇为: v67.xx 鸿蒙内核源码分析(字符设备篇) | 字节为单位读写的设备 | 51.c.h.o 文件系统相关篇为: v62.xx 鸿蒙内核源码分析(文件概念篇) | 为什么说一 ...

  8. P5591-小猪佩奇学数学【单位根反演】

    正题 题目链接:https://www.luogu.com.cn/problem/P5591 题目大意 给出\(n,p,k\)求 \[\left(\sum_{i=0}^n\binom{n}{i}p^i ...

  9. CF280C-Game on Tree【数学期望】

    正题 题目链接:https://www.luogu.com.cn/problem/CF280C 题目大意 \(n\)个点的一棵树,每次选择一个没有染色的点把它和它的子树染黑,求期望全部染黑的步数. 解 ...

  10. python爬虫抓取中国最好大学排名1 清华大学 北京 94.0 100.0 97.70% 清华大学 2 北京大学

    import requests from bs4 import BeautifulSoup import bs4.element r=requests.get("http://www.zui ...