IO 概述

I: input O:Output 流: 像水流一样传输数据

内存不能永久化存储 程序停止 数据丢失

IO流: 存储和读取数据的解决方案

File : 表示系统中的文件或者文件夹的路径 (获取文件信息 判断文件的类型 创建文件/文件夹 删除文件/文件夹 … )
注意: File类只能对文件本身进行操作 不能读写文件里面存储的数据

IO流 用于读写文件中的数据(可以读写文件 或 网络中的数据)

问: IO流中 谁在读 谁在写? 以谁为参照物看读写的方向呢?
答: 以程序为参照物 是程序在读 程序在写

IO的分类

纯文本文件: windows自带记事本能打开且能读懂的就是纯文本

IO流的体系

字节流

FileOutputStream

操作本地文件的字节输出流体 可以把程序中的数据写到本地文件中

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import java.io.FileOutputStream;
import java.io.IOException;

public class Main {
public static void main(String[] args) throws IOException {
/**
* 字节输出流 FileOutputStream
* 实现步骤:
* 创建对象
* 细节1: 参数是字符串表示的路径或者是File对象都是可以的
* 细节2: 如果文件不存在会创建一个新的文件 但是要保证父级路径是存在的
* 细节3: 如果文件已经存在 则会清空文件
* 写出数据
* 细节: write 方法参数是整数 但是实际上写到本地文件中的是整数在ASCII上对应的字符
* 97 --> a
* 释放资源
* 每次使用完流之后都要释放资源
*/

// 1. 创建对象
// 写出 输出流 OutputStream
// 本地文件 File
FileOutputStream fileOutputStream = new FileOutputStream("notes_IO\\a.txt"); // 指定文件的路径
// 写出数据
fileOutputStream.write(97); // 这里写入的是a
// 释放资源
fileOutputStream.close();
}
}

FileOutputStream写数据的3种方式

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

public class ByteStreamDemo3 {
public static void main(String[] args) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream("notes_IO\\a.txt");

// 一次写一个字节数据
fileOutputStream.write(97);
fileOutputStream.write(98);

// 一次写一个字符数据数据
byte [] bytes = {97,98,99,101};
fileOutputStream.write(bytes);

// 一次写一个字节数组的部分数据
/*
* 参数一: 数组
* 参数二: 起始索引
* 参数三: 个数
* */
fileOutputStream.write(bytes,1,2);

fileOutputStream.close();
}
}


FileOutputStream 换行与续写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;

public class ByteStreamDemo4 {
public static void main(String[] args) throws IOException {
/*
* 换行写:
* 再次写出一个换行符就可以了
* windows: \r\n
* Linux: \n
* Mac: \r
* 细节:
* 在windows操作系统当中 java对回车换行进行了优化
* 虽然完整的\r\n 但是我们写其中一个\r 或者 \n
* java也可以实现换行 因为java在底层会补全
* 建议:
* 不要省略 还是要写全
*
* 续写:
* 如果想要续写 打开续写开关即可
* 开关位置: 创建对象的第二个参数
* 默认: false 此时创建对象会清空文件 手动传递true 表示打开续写 此时创建对象不会清空文件
*
* */

// 1. 创建对象
FileOutputStream fileOutputStream = new FileOutputStream("notes_IO\\a.txt",true);
// 2. 写出数据
// kankelaoyezuishui
String str = "kankelaoyezuishui";
byte[] bytes = str.getBytes();
fileOutputStream.write(bytes);


// 换行
// 再次写出一个换行符实现换行
String wrap = "\r\n";
byte[] wrapBytes = wrap.getBytes();
fileOutputStream.write(wrapBytes);

String str2 = "666";
byte[] bytes2 = str2.getBytes();
fileOutputStream.write(bytes2);

// 3. 释放资源
fileOutputStream.close();
}
}


FileInputStream

操作本地文件的字节输入流 可以把本地文件中的数据读取到程序中来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class ByteStreamDemo1 {
public static void main(String[] args) throws IOException {
/**
*
* 字节输入流 FileInputStream
* 实现需求 读取文件中的数据
*
* 实现步骤:
* 创建对象
* 1. 如果文件不存在直接报错
* Java为什么这么设计?
* 输出流: 不存在 创建
* 把数据写到文件当中 (数据是程序中存在的)
*
* 输入流: 不存在 而是报错呢?
* 因为创建出来的文件是没有数据的 这样的文件没有任何意义
* 所以Java就没有设计这种无意义的逻辑 文件不存在直接报错
*
* 程序中最重要的是 数据
*
* 读取数据
* 1. 一次读一个字节 读出来的数据实在ASCII上对应的数字
* 2. 读到文件末尾了 read方法返回-1
*
* 释放资源
* 每次使用完流 必须要释放资源
*/

// 创建对象
FileInputStream fileInputStream = new FileInputStream("notes_IO\\a.txt");
// 读取数据
int b1 = fileInputStream.read();
System.out.println((char) b1);

int b2 = fileInputStream.read();
System.out.println((char) b2);

// 释放资源
fileInputStream.close();
}
}

FileInputStream循环读取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class ByteStreamDemo2 {
public static void main(String[] args) throws IOException {
/*
* 字节循环流读取
* */

// 1. 创建对象
FileInputStream fis = new FileInputStream("notes_IO\\a.txt");
// 2. 循环读取
int b;

/**
* read: 表示读取数据 而且是读取一个数据就移动一次指针
* 书写时一定要定义第三方变量 b
*/
while ((b = fis.read()) != -1){
System.out.println((char) b);
}

// 释放资源
fis.close();
}
}


为什么会有乱码?

原因1: 读取时未读完整个汉字
原因2: 编码和解码时的方式不统一 -> 统一 UTF-8

字符流

字符流的底层其实就是字节流
字符流 = 字节流 + 字符集

特点:
输入流: 一次读一个字节 遇到中文 一次读多个字节
输出流: 底层会把数据按照指定的编码形式进行编码 变成字节再写到文件中

使用场景:
对于纯文本文件进行读写操作

FileReader

空参 read

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class CharStreamDemo1 {
public static void main(String[] args) throws IOException {
/*
* 创建对象
* 读取数据
* 释放资源
* */

// 1.创建对象 关联本地文件
FileReader fileReader = new FileReader("notes_IO\\a.txt");
// 2.读取资源 read()
// 字符流的底层也是字节流 默认也是一个字节一个的读取的
// 如果遇到中文就会一次读取多个 GBK一次读两个字节 UTF-8一次读三个字节
/**
* 1. read(): 默认也是一个字节一个字节的读取 如果遇到中文就会一次读取多个
* 2. 在读取之后 方法的底层还会进行解码并转成十进制
* 最终把这个十进制作为返回值
* 这个十进制的数据也表示在字符集上的数字
*
* 英文: 在文件里面二进制数据 0110 0001
* read 方法进行读取 解码并转成十进制97
*
* 中文: 文件里的二进制数据 11100110 10110001 10001001
* read方法进行读取 解码并转换成是继子女hi 27721
*
* 十进制强转 -> 汉字
*/

int ch;
while ((ch = fileReader.read()) != -1){
System.out.println((char) ch);
}

// 释放资源
fileReader.close();

}
}

带参 read

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class CharStreamDemo2 {
public static void main(String[] args) throws IOException {
FileReader fileReader = new FileReader("notes_IO\\a.txt");
// 长度为2 表示一次读两个
char[] chars = new char[2];
int len;
// read(chars): 读取数据 解码 强转 三步合并了 把强转之后的字符放到数组当中
// 空参的read + 强制类型转换
while ((len = fileReader.read(chars))!= -1){
// 把数组中的数据变成字符串再进行打印
System.out.println(new String(chars,0,len));
}

fileReader.close();
}
}

FileWriter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import java.io.*;

public class CharStreamDemo3 {
public static void main(String[] args) throws IOException {
// true表示续写开关 每次写的时候不会清空 而是接着下去
FileWriter fileReader = new FileWriter("notes_IO\\a.txt",true);

// 写出一个字符
// 根据字符集的编码方式进行编码
// 把编码之后的数据写到文件中取 UTF-8
// '我' -> 25105
fileReader.write(25105);


// 写出一个字符串
fileReader.write("你好啊!!!");

// 写出一个字符数组
char [] chars = {'a','v','k','元'};
fileReader.write(chars);

fileReader.close();
}
}


字符流原理解析

字符输入流的底层原理

字符输出流的底层原理