为跳槽面试做准备,今天开始进入 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. H3C 公有地址和私有地址

  2. C# 使用转换语义版本号

    本文告诉大家如何转换语义版本号,那么什么是语义版本号,语义版本号(semantic version)就是版本号带 alpha 等的版本号 在以前的版本号都是这样 1.2.1 的格式,这个格式可以使用微 ...

  3. H3C 计算子网内可用主机地址数

  4. H3C配置Header进入用户视图的提示信息--系统视图

                      incoming:登录终端用户界面时的提示信息. Header 3种类型     login:登录验证时的提示信息.    Vty模式                ...

  5. Linux 内核 回顾: ISA

    设计上 ISA 总线非常老了, 并且是非常地低能, 但是它仍然持有一块挺大的控制设备的 市场. 如果速度不重要并且你想支持老式主板, 一个 ISA 实现要优于 PCI. 这个老标准 的另外一个好处是如 ...

  6. LuoguP1402 酒店之王

    LuoguP1402 酒店之王 最大流题目.带有一定的思维技(tao)巧(lu) 依旧分析题目.如果只有房间或者菜一种限制.那么就是一道裸的最大流了 可是两种条件都应当满足, 这貌似也可以做. 因为每 ...

  7. hdu 2454 Degree Sequence of Graph G(可简单图化判定)

    传送门 •Havel-Hakimi定理: 给定一个非负整数序列{d1,d2,...dn},若存在一个无向图使得图中各点的度与此序列一一对应,则称此序列可图化. 进一步,若图为简单图,则称此序列可简单图 ...

  8. sparksql 练习题两道

    第一题:select '{"id":1,"name":{"url":"http://xxx/yyy/zz/test.js" ...

  9. C# 如何解析XML

  10. MFC入门

    目录 001.MFC_应用程序类型    002.MFC_对话框_静态文本_编辑框  003.MFC_对话框_访问控件_7种方法_A   004.MFC_对话框_访问控件_7种方法_B   005.M ...