流式 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. spark相关介绍-提取hive表(一)

    本文环境说明 centos服务器 jupyter的scala核spylon-kernel spark-2.4.0 scala-2.11.12 hadoop-2.6.0 本文主要内容 spark读取hi ...

  2. PHP的那些魔术方法(一)

    在PHP中,有一堆魔术方法,服务于类和对象.PHP虽然也是纯种的面向对象语言,但是之前的PHP还真不是,所以有一些面向对象的标准实现并不完善,比如重载.但是,我们可以通过一些魔术方法来弥补,例如__c ...

  3. 如何创建 Office LTSC 2021 VL(批量许可)版本的安装 ISO

    Office LTSC 2021 发布 2021 年 9 月 16 日,微软正式发布了支持 Office 2021 的部署工具(Office Deployment Tool),这意味着 Office ...

  4. 创建一个 Orchard Core CMS 站点

    本文通过引用项目模板的方式创建Orchard CMS站点. 创建项目有不同的方式可以为Orchard Core创建站点和模块.你可以在这里了解更多关于它们的信息.在本指南中,我们将使用我们的" ...

  5. Docker系列(9)- 常用其他命令(2) | 进入容器和拷贝的命令

    进入当前正在运行的容器 #我们通常容器都是使用后台方式运行的,需要进入容器,修改一些配置#方法一 命令docker exec -it 容器ID bashShell#测试[root@localhost ...

  6. 超详细的VMware安装Centos7教程

    下载centos镜像 https://wiki.centos.org/Download 注:真正生产环境的oracle数据库一般是一整台服务器只用作数据库,不会安装其他应用,也不会安装xwindow图 ...

  7. 接口管理工具swagger

    swagger,一款致力于解决接口规范化.标准化.文档化的开源库,一款真正的开发神器. swagger三大部分 Editor https://swagger.io/tools/swagger-edit ...

  8. django 高级扩展-中间件-上传图片-分页-富文本-celery

    """ django 高级扩展 一.静态文件 1.css,js,json,图片,字体等 2.配置setting,在最底下设置静态文件目录,写入下面代码 #配置静态文件目录 ...

  9. Spring Security 学习+实践

    Spring Security是Spring为解决应用安全所提供的一个全面的安全性解决方案.基于Spring AOP和Servlet过滤器,启动时在Spring上下文中注入了一组安全应用的Bean,并 ...

  10. Kettle学习笔记(二)— 基本操作

    目录 Kettle学习笔记(一)- 环境部署及运行 Kettle学习笔记(二)- 基本操作 kettle学习笔记(三)- 定时任务的脚本执行 Kettle学习笔记(四)- 总结 打开Kettle 打开 ...