为跳槽面试做准备,今天开始进入 Java 基础的复习。希望基础不好的同学看完这篇文章,能掌握泛型,而基础好的同学权当复习,希望看完这篇文章能够起一点你的青涩记忆。

一、什么是 IO 流?

想象一个场景:我们在电脑上编辑文件,可以保存到硬盘上,也可以拷贝到 U 盘中。那这个看似简单的过程,背后其实是数据的传输。

数据的传输,也就是数据的流动。既然是流动也就会有方向,有入方向和出方向。举个上传文件的栗子,现在有三个对象,文件、应用程序、上传的目标地址(服务器)。简化的上传文件有两步:

  • 应用程序读文件(此为入方向,文件读入到应用程序)
  • 应用程序写文件(此为出方向,读完之后写到目标地址)

注意这个入和出是相对的,它相对于应用程序而言。如果相对于服务器而言,这个上传文件操作就是入方向,从应用程序读入。Java中I/O操作主要是指使用java.io包下的内容,进行输入、输出操作。输入也叫做读取数据,输出也叫做作写出数据。

二、IO 流的分类

我不认同网络上很多 IO 流的图,他们只是简单的把 io 流分成字节流和字符流。这样的分类也不是说不好,只是太臃肿、难记。

先上一张我自己总结的 IO 留的思维导图,我先把它分成了节点流处理流节点流是直接接触数据源的,而处理流是出于各种目的在节点流的基础上再套一层的 IO 流。再按照操作类型,分成 8 个小类,然后才是字节、字符分类,最后才是输入、输出的分类。具体可以看以下思维导图(可能不清晰,有需要的在后台回复IO流获取原思维导图)

根据数据的流向分为:输入流输出流

  • 输入流 :把数据从其他设备上读取到内存中的流。
  • 输出流 :把数据从内存 中写出到其他设备上的流。

根据数据的类型分为:字节流字符流

  • 字节流 :以字节为单位,读写数据的流。
  • 字符流 :以字符为单位,读写数据的流。

IO 流要说明白需要好几篇才行,今天我们先复习文件流。

2.1 一切皆字节

所有的文件(包括图片、音乐、视频),都是字节。所以字节流可以传输任意文件数据。在操作流的时时,无论使用什么样的流对象,底层传输的始终为二进制数据。

2.2 什么叫文件流?

文件流也就是直接操作文件的流,文件流又分为字节流 (FileInputStreamFileOutputStream)和字符流(FileReaderFileWriter)。其中字节流可用于操作一切文件,而字符流只能用于操作文本文件。

三、使用文件字节流

3.1 FileOutputStream

java.io.FileOutputStream 类继承于 OutputStream 是文件输出流,用于将数据写出到文件。

构造方法:可用文件路径构造,也可创建 File 对象之后构造。

写出数据示例:

/**
* Project Name:review_java <br/>
* Package Name:com.nasus.io.filestream <br/>
* Date:2020/1/5 19:24 <br/>
*
* @author <a href="turodog@foxmail.com">chenzy</a><br/>
*/
public class FOSWriterStream { public static void main(String[] args) throws IOException {
// 使用文件名称创建流对象,构造函数中的 true 表示在原有数据末尾追加续写
FileOutputStream fos = new FileOutputStream("fos.txt", true); // 1、逐个字节写出
fos.write(97); // 97 的 ascll 码是 a
fos.write(98); // 98 的 ascll 码是 b
fos.write(99); // 99 的 ascll 码是 c // 2、写出一个换行, 换行符号转成数组写出
fos.write("\r\n".getBytes()); // 字符串转换为字节数组
byte[] b = "一个优秀的废人".getBytes();
// 3、写出字节数组数据
fos.write(b); // 4、写出指定长度字节数组数据(不可超过 b 的长度,否则数组越界)
fos.write(b, 0, b.length); // 关闭资源
fos.close();
} }

3.2 FileInputStream

java.io.FileInputStream 类继承于 InputStream 是文件输入流,用于将数据从文件读出。

构造方法:可用文件路径构造,也可创建 File 对象之后构造。

读取数据示例:

/**
* Project Name:review_java <br/>
* Package Name:com.nasus.io.filestream <br/>
* Date:2020/1/5 19:31 <br/>
*
* @author <a href="turodog@foxmail.com">chenzy</a><br/>
*/
public class FISReadStream { public static void main(String[] args) throws IOException {
// 1、逐个读取字节
int b;
FileInputStream fis1 = new FileInputStream("fis.txt");
// 循环读取
while ((b = fis1.read())!=-1) {
System.out.println((char)b);
}
// 关闭资源
fis1.close(); System.out.println("----华丽丽的分割线----"); // 2、定义字节数组读取
int length;
FileInputStream fis2 = new FileInputStream("fis.txt");
// 定义字节数组,作为装字节数据的容器
byte[] bytes = new byte[1024];
// 循环读取
while ((length = fis2.read(bytes))!=-1) {
// 每次读取后,把数组变成字符串打印
System.out.println(new String(bytes, 0, length));
}
// 关闭资源
fis2.close();
} }

复制文件示例:

/**
* Project Name:review_java <br/>
* Package Name:com.nasus.io.filestream <br/>
* Date:2020/1/5 19:43 <br/>
*
* @author <a href="turodog@foxmail.com">chenzy</a><br/>
*/
public class FileCopyStream { public static void main(String[] args) throws IOException { // 指定数据源
FileInputStream fis = new FileInputStream("Java IO 流.png");
// 指定目的地
FileOutputStream fos = new FileOutputStream("流.png"); // 定义数组
byte[] b = new byte[1024];
// 定义长度
int len;
// 循环读取
while ((len = fis.read(b))!=-1) {
// 写出数据
fos.write(b, 0 , len);
} // 关闭资源,后开先关,后开先关
fos.close();
fis.close();
} }

3.3 为什么字节流处理中文字符时会出现乱码?

首先明确一点:一个英文字母占一个字节,一个汉字占两个字节,所以当字节流读取字符流就会出现乱码或者显示不全。所以用字节流操作含有中文字符的文件时,要转换成字符流并指定编码格式才能防止乱码。(这点,后面转换流会复习到

四、使用文件字符流

当使用字节流读取文本文件时,可能会有一个小问题。就是遇到中文字符时,可能不会显示完整的字符,那是因为一个中文字符可能占用多个字节存储。所以 Java 提供一些字符流类,以字符为单位读写数据,专门用于处理文本文件。

4.1 FileReader

java.io.FileReader 类继承于 Reader 类,是读取字符文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。

构造方法:可用文件路径构造,也可创建 File 对象之后构造。

  • 字符编码:字节与字符的对应规则。Windows 系统的中文编码默认是 GBK 编码表
  • 字节缓冲区:一个字节数组,用来临时存储字节数据。

PS:有时候出现乱码,多考虑下是不是编码的原因:字节与字符的规则对不上。

读取数据示例:

/**
* Project Name:review_java <br/>
* Package Name:com.nasus.io.filereadwrite <br/>
* Date:2020/1/5 20:19 <br/>
*
* @author <a href="turodog@foxmail.com">chenzy</a><br/>
*/
public class FileRead { public static void main(String[] args) throws IOException { // 1、逐个字符读取
int b = 0;
FileReader fileReader1 = new FileReader("read.txt");
// 循环读取
while ((b = fileReader1.read())!=-1) {
// 自动提升类型提升为 int 类型,所以用 char 强转
System.out.println((char)b);
}
// 关闭流
fileReader1.close(); System.out.println("----华丽丽的分割线----"); // 2、利用字符数组,每次读取两个字符
int length = 0;
FileReader fileReader2 = new FileReader("read.txt");
char[] charArray = new char[2];
// 读取数据
while ((length = fileReader2.read(charArray)) != -1) {
System.out.println(new String(charArray, 0, length));
}
// 关闭流
fileReader2.close();
} }

4.2 FileWriter

java.io.FileWriter 类是写出字符到文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。

构造方法:可用文件路径构造,也可创建 File 对象之后构造。

写出数据示例:

public static void main(String[] args) throws IOException {
// 使用文件名称创建流对象,true 表示在原有数据末尾追加续写
FileWriter fileWriter = new FileWriter("fw.txt", true); // 1、逐个写出字符
fileWriter.write(97);
fileWriter.write('C');
fileWriter.write('Z');
fileWriter.write('Y');
// 中文编码表中30000对应一个汉字。
fileWriter.write(30000); // 2、写出字符串
fileWriter.write("是一个"); // 3、写出 Windows 换行
fileWriter.write("\r\n"); // 4、写出字符串数组
// 字符串转换为字节数组
char[] chars = "优秀的废人".toCharArray();
fileWriter.write(chars, 0, chars.length); // 关闭资源,close方法调用之前,数据只是保存到了缓冲区,并未写出到文件中。
fileWriter.close();
}

刷新与关闭:

因为内置缓冲区的原因,如果不关闭输出流,无法写出字符到文件中。但是关闭的流对象,是无法继续写出数据的。如果我们既想写出数据,又想继续使用流,就需要flush 方法了。

  • flush :刷新缓冲区,流对象可以继续使用。
  • close :先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。
/**
* Project Name:review_java <br/>
* Package Name:com.nasus.io.filereadwrite <br/>
* Date:2020/1/5 22:25 <br/>
*
* @author <a href="turodog@foxmail.com">chenzy</a><br/>
*/
public class FileFlushClose { public static void main(String[] args) throws IOException {
// 使用文件名称创建流对象
FileWriter fw = new FileWriter("fw.txt");
// 1、通过 flush 写出数据
// 写出第 1 个字符
fw.write('刷');
fw.flush(); // 继续写出第 2 个字符,写出成功
fw.write('新');
fw.flush(); // 2、通过 close 写出数据,流关闭后不可用
// 写出第 1 个字符
fw.write('关');
fw.close(); // 继续写出第 2 个字符,【报错】java.io.IOException: Stream closed
fw.write('闭');
fw.close();
}
}

五、源码地址

如果看到这里,喜欢这篇文章的话,帮忙 " 转发 "或者点个" 在看 ",行吗?祝你们 2020 暴富。微信搜索「一个优秀的废人」,欢迎关注。

回复「1024」送你一套完整的 java、python、c++、go、前端、linux、算法、大数据、人工智能、小程序以及英语教程。

回复「电子书」送你 50+ 本 java 电子书。

Java 基础(四)| IO 流之使用文件流的正确姿势的更多相关文章

  1. java基础之IO流(二)之字符流

    java基础之IO流(二)之字符流 字符流,顾名思义,它是以字符为数据处理单元的流对象,那么字符流和字节流之间的关系又是如何呢? 字符流可以理解为是字节流+字符编码集额一种封装与抽象,专门设计用来读写 ...

  2. java基础之IO流(一)字节流

    java基础之IO流(一)之字节流 IO流体系太大,涉及到的各种流对象,我觉得很有必要总结一下. 那什么是IO流,IO代表Input.Output,而流就是原始数据源与目标媒介的数据传输的一种抽象.典 ...

  3. Java基础之IO流整理

    Java基础之IO流 Java IO流使用装饰器设计模式,因此如果不能理清其中的关系的话很容易把各种流搞混,此文将简单的几个流进行梳理,后序遇见新的流会继续更新(本文下方还附有xmind文件链接) 抽 ...

  4. 【Java基础】IO 流

    IO 流 File 类 java.io.File 类是文件和文件目录路径的抽象表示形式,与平台无关. File 能新建.删除.重命名文件和目录,但 File 不能访问文件内容本身. 如果需要访问文件内 ...

  5. Java IO流之普通文件流和随机读写流区别

    普通文件流和随机读写流区别 普通文件流:http://blog.csdn.net/baidu_37107022/article/details/71056011 FileInputStream和Fil ...

  6. java基础之io流总结四:字符流读写

    字符流读写只适用于字符文件. 基本字符流(转换流)读写文件 转换流本身是字符流,但是实例化的时候传进去的是一个字节流,所以叫做转换流 InputStreamReader isr = new Input ...

  7. java基础之 IO流

    javaIO流   IO流 : (input  output) 输入输出流 :输入 :将文件读到内存中 输出:将文件从内存输出到其他地方.   IO技术的作用:主要就是解决设备和设备之间的数据传输问题 ...

  8. 【java基础】]IO流

    IO流 概念: 流的概念源于unix中管道(pipe)的概念,在unix中,管道是一条不间断的字节流,用来实现程序或进程间的通信,或读写外围设备,外部文件等 一个流,一定能够会有源和去向(目的地),他 ...

  9. java基础06 IO流

    IO用于在设备间进行数据传输的操作. Java IO流类图结构:   IO流分类 字节流: InputStream FileInputStream BufferedInputStream Output ...

随机推荐

  1. Vue 列表动画实现

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. java TreeSet的排序之自然排序

    TreeSet会调用元素的compareTo(Object o)方法来比较元素之间的大小关系,然后将集合里的元素按升序排列.此时需要排序元素的类必须实现Compareble接口,并覆写其int com ...

  3. P1093 铺地毯

    题目描述 为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯.一共有 \(n\) 张地毯,编号从 \(1\) 到 \(n\) .现在将这些地毯按 ...

  4. JS的防抖与节流学习笔记

    防抖(debounce):当持续触发事件时,在一定的时间段内,只有最后一次触发的事件才会执行. 例: function debounce(fn, wait) { var timer = null; r ...

  5. <sUbjeCt>Reverse aAlignment SemInaR

    翻译过来就是有关逆序对问题的专题. 因为大胆报名担任学校专题讲师所以跪着也要准备好课件...那什么是逆序对? 逆序对就是序列中ai>aj且i<j的有序对 举个栗子: 其中,5>4,但 ...

  6. The Preliminary Contest for ICPC Asia Shanghai 2019 C Triple(FFT+暴力)

    The Preliminary Contest for ICPC Asia Shanghai 2019 C Triple(FFT+暴力) 传送门:https://nanti.jisuanke.com/ ...

  7. Linux 操作虚拟机、数据库

    1.打开虚拟机,输入命令:ifconfig 查看iP和端口号,端口号一般为:22 2.打开Xshell(先安装好),连接虚拟机(根据iP和端口号) 若连接成功,Xshell则会显示虚拟机的ip和端口号 ...

  8. 记录我的 python 学习历程-Day11 两个被忽视的坑、补充知识点、函数名的应用、新版格式化输出、迭代器

    补充知识点 函数形参中默认参数的陷阱 针对不可变数据类型,它是没有陷阱的 def func(name, sex='男'): print(name) print(sex) func('Dylan') # ...

  9. 开发板免费领!腾讯云IoT应用创新大赛正式启动!

    大赛简介 腾讯云IoT应用创新大赛是腾讯云面向物联网领域举办的大型竞赛,通过腾讯云IoT全链路产品能力,开放平台和服务,与广大开发者共同创新,孵化优秀的IoT产品和解决方案,共同构建IoT应用生态. ...

  10. 洛谷$P5446\ [THUPC2018]$绿绿和串串 $manacher$

    正解:$manacher$ 解题报告: 传送门$QwQ$ 考虑这个操作的实质是啥$QwQ$?其实就,变成以最后一个节点为回文中心的回文子串嘛$QwQ$.显然就先跑个马拉车再说呗$QwQ$. 然后接着考 ...