A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 黑马11期 初级黑马   /  2018-11-26 15:35  /  690 人查看  /  0 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

                                               IO流学习总结
一、IO流

> 把这种数据的传输,可以看做是一种数据的流动,按照流动的方向,以内存为基准,分为 输入`input` 和 输出`output` ,即流向内存是输入流,流出内存的输出流。

Java中I/O操作主要是指使用**java.io**包下的内容,进行输入、输出操作。
- **输入** 也叫作 **读取数据**;
- **输出** 也叫作 **写出数据**


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

**根据数据的类型分为**
- **字节流**:以字节为单位,读写数据的流。
- **字符流**:以字符为单位,读写数据的流

**写入数据的原理**(内存-->硬盘):java程序-->JVM(java虚拟机)-->OS(操作系统)-->OS调用写数据的方法-->把数据写入到文件中

**顶级父类抽象类**

||输入流|输出流|
---|---|---|
字节流|字节输入流(InputStream)|字节输出流(OutputStream)|
字符流|字符输入流(Reader)|字符输出流(Writer)|

---
## 二、字节输出流【OutputStream】顶级父类

> 无论使用什么样的流,底层都是二进制数据。
> `StringObj.getBytes()`:得到字节字符串对应的字节数组

`java.io.OutputStream`**抽象类** 字节输出流超类定义了基本共性的方法(忽略public)
- `void close()` : 关闭此输出流并释放与此流相关联的任何系统资源。
- `void flush()` : 刷新此输出流并强制任何缓冲的输出字节被写出。
- `void write(byte[] b)` : 将b.length字节从指定的字节数组写入此输入流。
- `void write(byte[] b, int off, int len)` : 从指定的字节数组写入len字节,从偏移量为off的位置开始输出到此输出流
- `abstract void write(int b)` :将指定的 字节 输出流,就是写入一个字节

> **close()** 方法,当完成流操作后,必须调用此方法,释放系统资源。


FileOutputStream 字节输出流
1. 属于OutputStream的子类
2. `java.io.FileOutputStream`类是文件输出流,将数据写出到文件。

构造方法
- public FileOutputStream(File file) : 创建文件输出流 写入指定File对象表示的文件
- public FileOutputStream(String name) : 创建文件输出流以指定的名称写入文件。

> 创建一个流对象,必须传入一个文件路径,该路径下,如果没有这个文件,会创建该文件。
如果这个文件已存在,会清空这个文件的数据

```


**1.写出字节数据**`write(int b)` : 每次写出一个字节数据

```java
FileOutputStream fos2 = new FileOutputStream(".\\day_09\\test2.txt");
fos2.write(100);
fos2.close(); // 必须关闭资源
```

> int类型在内存中为4个字节,但是上面的只需要一个字节就能存储,所以只会保留一个字节(字节流没编码那么麻烦)。
> 使用完必须释放资源

**3.写出字节数组** `write(byte[] b)`

```java
FileOutputStream fos2 = new FileOutputStream(".\\day_09\\test2.txt");
fos2.write("我是一个兵,来自老百姓".getBytes());
fos2.close(); // 必须关闭资源
```

**写多个字节,文本方式打开的时候,查询的规则**
- 第一个字节是正数(0-127),查询Ascii表
- 第一个字节是负数,(winGBK)查询第一个与第二个组合找中文。

**4.写出指定长度字节数组**`write(byte[] b, int off, int len)`

```java
FileOutputStream fos2 = new FileOutputStream(".\\day_09\\test2.txt");
fos2.write("天王盖地虎,宝塔镇河妖".getBytes(), 18, 15);
// utf-8编码   宝塔镇河妖
fos2.close(); // 必须关闭资源
```

**5.数据追加续写**

保留数据并进行***追加操作***,构造方法需要传入一个是否追加的参数
- `public FileOutputStream(File file, boolean append)`: 文件对象形式,追加操作
- `public FileOutputStream(String name, boolean append)`: 字符串路径形式, 追加操作。

> 如果要追加数据就传入true,清空就传入false(默认是false)
```
> - 回车符 \r 和换行符 \n :
>   - 回车符:回到一行的开头(return)。
>   - 换行符:下一行(newline)。
> - 系统中的换行:
>   - Windows系统里,每行结尾是 回车+换行 ,即 \r\n
>   - Unix系统里,每行结尾只有 换行 ,即 \n
>   - Mac系统里,每行结尾是 回车 ,即 \r 。从 Mac OS X开始与Linux统一。


## 三、字节输人流【InputStream】顶级父类

先介绍字节输出流的超类`InputStream`字节输出流
`java.io.InputStream`抽象类 总超类 ,字节信息-\>读到内存,共性方法如下(省略public)
- `void close()` : 【**必须使用**】关闭此输入流并释放与此流相关联的任何系统资源。
- `abstract int read()` : 从输入流读取的下一个字节,
- `int read(byte[] b)`: 从输入流中读取一些字节数,并将它们存储大字节数组中。

> 必须使用**close**方法释放资源

### FileInputStream 字节输出流

`java.io.FileInputStream` 类 读取字节

**1.构造方法**(省略public)
- `FileInputStream(File file)`:通过打开一个与实际文件的连接 创建一个FileInputStream,该文件由文件由文件系统中的File对象file命名。
- `FileInputStream(String name)`: 通过打开与实际文件的连接来创建一个FileInputStream,该文件由文件系统中的路径名name命名。

> 创建一个流对象,必须传入一个文件路径,如果该路径下没有改文件(文件不存在),会抛出`FileNotFondException`

```java
// 使用File对象创建流对象
File file = new File(".\\day_09\\a.txt");
new FileOutputStream(file).write("还是写一点东西吧".getBytes());
FileInputStream fos = new FileInputStream(file);

// 使用文件名称创建流对象
FileInputStream fos2 = new FileInputStream(".\\day_09\\a.txt");
```

**2.读取字节数据**`int read()`方法,每次读取一个字节的数据提升为int类型,读到文件末尾,返回`-1`

```java
// 使用文件名称创建流对象
FileInputStream fos2 = new FileInputStream(".\\day_09\\a.txt");
int b;
while ((b = fos2.read()) != -1)
    System.out.println((char)b);

fos2.close();
```

> 1. 虽然读取了一个字节,但是会自动提升为int类型。
> 2. 流操作完毕后,调用**close**方法,必须释放系统资源。

**3.使用字节数组读取*****开发中建议的方式***】:`int read(byte[] b)` 每次读取b的长度个字节到数组中,返回读取代的**有效字节个数**,读取到末尾时,返回-1
``
# 转换流

> 注意:JVM内部使用的编码方式为默认编码方式为系统的编码方式(当然可以自己设置),但是在IEDA中,会把默认当前运行的JVM的编码方式改成UTF-8!
> 而python解释器在内存中是使用的Unicode编码!

### 修改JVM默认编码方式!
1. 在系统的环境变量中添加一个变量,名为: JAVA_TOOL_OPTIONS, 值为:-Dfile.encoding=UTF-8
2. 在运行java程序的时候指定参数java -Dfile.encoding=UTF-8 Test【**注意:第2种方式每次运行时都需要指定**
3. 如果是web工程,可以在catalina.bat的最前面加入set JAVA_OPTS=-Dfile.encoding=UTF-8;设置了编码后使用java -help可能会出现乱码,这个时候可以使用-Duser.language=en设置一下语言


## 一、字符编码

- **字符编码`Character Encoding`**:一套自然语言与二进制数之间的对应规则。

> @@@@@@@@@@@@@@@@@@@@@@@@@@@   <---decoded解码---   1010101010
> 【**数字、英文、标点符号、汉字**】   (**编码规则**)    【**底层二进制**
> @@@@@@@@@@@@@@@@@@@@@@@@@@@   ---encoding编码--->  1010101010
> *如果解码的规则和编码的规则不同,就会出现乱码的现象!*
## 二、字符集

- **字符集`Charset`**: 编码表。系统支持的所有字符的集合,包括各国国家文字、标点符号、图形符号、数字等。

> 常见的字符集:ASCII、GBK、Unicode、UTF-8等。

@@@@@@@@@@@@@@@@@@@@@@@@@ 字符集与编码规则

- **ASCII:(*不超过1字节*)**
    - 基于拉丁字母、用于显示英文、包含控制字符(回车等)、显示字符
    - 基本的ASCII使用7bits表示一个字符(128个字符),拓展的使用8bits(256个字符)。

- **Unicode:(*统一4字节编码*)**
    - 标准万国码,国际标准、有三种优化编码方案:UTF-8【常用】、UTF-16、UTF-32
    - **UTF-8(*1-4个字节*):**: 一个压缩版的Unicode(*空间压缩,使用1-4个字节为每个字符编码,节省空间,根据编码规则及编码头的数字可以准确判断是对应的多少字节*)
        - 编码规则:
            - 128个US-ASCII字符:1个字节编码
            - 拉丁文等:2个字节编码
            - 大部分常用字(包含**中文**):3个字节编码
            - 极少使用的Unicode辅助字符:4个字节编码
- **GB(xxx)**:为中文显示而设计的
    - GB2312:简体中文码表。一个小于127的字符的意义与原来相同。但两个大于127的字符连在一起时,就表示一个汉字,这样大约可以组合了包含7000多个简体汉字,此外数学符号、罗马希腊的字母、日文的假名们都编进去了,连在ASCII里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的"全角"字符,而原来在127号以下的那些就叫"半角"字符了。
    - **GBK**: 最常用的(**一个汉字两个字节**),扩展了GB2312,双字节编码方法,共收录了21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等
    - **GB18030** 最新的中文码表,收录汉字70244个,采用多字节编码,每个字可以由1个、2个或4个字节组成。支持中国国内少数民族的文字,同时支持繁体汉字以及日韩汉字等。
- ISO-8859-1:拉丁码表、Latin-1、欧洲使用、一个字节编码,兼容ASCII
---------------------------------------------------------------------------------------------------------------------------------------------------
## 三、InputStreamReader

回顾一下之前类的关系:

|抽象类|InputStream|OutputStream|Reader|Writer|
---|---|---|---|---|
抽象类的实现子类|FileInputStream|FileOutputStream|FileReaderInputStreamReader(InputStream 字节流到字符流的桥梁)|FileWriter、OutputStreamWriter(OutputStream 字符流到字节流的桥梁)
对应的增强类(无继承关系)|BufferedInputStream|BufferedOutputStream|BufferedReader|BufferedWriter

> 转换流`java.io.InputStreamReader``Reader`的子类、**字节流** **字符流** 的桥梁,读取字节,使用指定的字符集将其解码为字符。可指定名称、可接受系统默认编码方式。

### 1.构造方法(省略public)
- `InputStreamReader(InputStream in)` : 创建一个使用默认字符集的字符流,使用系统的编码方式。
- `InputStreamReader(InputStream in, String charsetName)` :创建一个指定字符集的字符流。
    - > InputStream抽象接口一般肯定是使用FileInputStream!

- 案例:使用指定字符集读取文件!`BufferedReader` 结合 `InputStreamReader` 再结合 `FileInputStream` 使用

```java
/**@指定字符级
* BufferedReader(需要传入Reader -- InputStreamReader)
* InputStreamReaderReader的子类,
* InputStreamReader(需要传入InputStream -- FileInputStream)
*/
InputStreamReader isr = new InputStreamReader(new FileInputStream("F:\\test\\GBK.txt"), "GBK");
BufferedReader br = new BufferedReader(isr);
System.out.println(br.readLine());
br.close();
isr.close();

// 我是GBK编码的,哈哈,必须的使用GBK编码方式才能读出来知道不!
```

## 四、OutputStreamWriter

> 转换流 `java.io.OutputStreamWriter` ,Writer子类,字符流到字节流的桥梁,可使用操作系统默认字符集将字符编码为字节。字符集也可以由名称指定。

### 1.构造方法(省略public)
- `OutputStreamWriter(OutputStream out)` : 创建一个使用默认字符集的字符流
- `OutputStreamWriter(OutputStream out, String charsetName)`: 创建一个指定字符集的字符流

**使用指定编码写出**

```java
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("F:\\test\\UTF-8.txt"), "UTF-8");
BufferedWriter bw = new BufferedWriter(osw);
osw.write("UTF-8编码方式");
osw.close();
osw.close();
```

转换流是字节与字符间的桥梁

@@@@@@@@@@@@@@@@@@@@@@@@@@@ 转换流是字节与字符间的桥梁

将GBK编码的文件转换为UTF-8的文本文件

IDEA中,JVM运行使用的编码方式!


System.out.println("内容:‘" +  line + "’ 编码方式GBK  ,外存中大小2字节,JVM " +  line.getBytes().length + "字节");

System.out.println("内容:‘" +  line + "’ 编码方式UTF-8,外存中大小3字节,JVM " +  line.getBytes().length + "字节");

/** IDEA
* 内容:编码方式GBK  ,外存中大小2字节,JVM 3字节
* 内容:编码方式UTF-8,外存中大小3字节,JVM 3字节
*/
```

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马