输入输出流
- 1、字符集
-
- [1.1 常见字符集介绍](#1.1 常见字符集介绍 "#11__3")
- [1.2 字符集的编码、解码操作](#1.2 字符集的编码、解码操作 "#12__51")
- 2、IO流概述
- 3、字节流的使用
-
- [3.1 文字字节输入流](#3.1 文字字节输入流 "#31__90")
- [3.2 文件字节输出流](#3.2 文件字节输出流 "#32__189")
- [3.3 文件拷贝](#3.3 文件拷贝 "#33__265")
- 4、资源释放的方式
-
- [4.1 try-catch-finally](#4.1 try-catch-finally "#41_trycatchfinally_318")
- [4.2 try-with-resource](#4.2 try-with-resource "#42_trywithresource_405")
- 5、字符流的使用
-
- [5.1 文件字符输入流](#5.1 文件字符输入流 "#51__411")
- [5.2 文件字符输出流](#5.2 文件字符输出流 "#52__477")
1、字符集
1.1 常见字符集介绍
字符集基础知识:
计算机底层不可以直接存储字符的。计算机中底层只能存储二进制(0、1)二进制是可以转换成十进制的。
计算机底层可以表示十进制编号。计算机可以给人类字符进行编号存储,这套编号规则就是字符集。
ASCII字符集:
- ASCII(American Standard Code for Information Interchange,美国信息交换标准代码):包括了数字、英文、符号。
- ASCII使用1个字节存储一个字符,一个字节是8位,总共可以表示128个字符信息,对于英文,数字来说是够用的。
GBK:
- window系统默认的码表。兼容ASCII码表,也包含了几万个汉字,并支持繁体汉字以及部分日韩文字。
- 注意:GBK是中国的码表,一个中文以两个字节的形式存储。但不包含世界上所有国家的文字。
Unicode码表:
- unicode (又称统一码、万国码、单一码)是计算机科学领域里的一项业界字符编码标准。容纳世界上大多数国家的所有常见文字和符号,一个中文一般以三个字节的形式存储 。
- 由于Unicode会先通过UTF-8,UTF-16,以及UTF-32的编码成二进制后再存储到计算机,其中最为常见的就是UTF-8。
java
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
/**
学会自己进行文字的编码和解码,为以后可能用到的场景做准备。
*/
public class Test {
public static void main(String[] args) throws Exception {
// 1、编码:把文字转换成字节(使用指定的编码)
String name = "abc我爱你中国";
// byte[] bytes = name.getBytes(); // 以当前代码默认字符集进行编码 (UTF-8)
byte[] bytes = name.getBytes("GBK"); // 指定编码
System.out.println(bytes.length);
System.out.println(Arrays.toString(bytes));
// 2、解码:把字节转换成对应的中文形式(编码前 和 编码后的字符集必须一致,否则乱码 )
// String rs = new String(bytes); // 默认的UTF-8
String rs = new String(bytes, "GBK"); // 指定GBK解码
System.out.println(rs);
}
}
1.2 字符集的编码、解码操作
String编码
方法名称 | 说明 |
---|---|
byte[ ] getBytes() | 使用平台的默认字符集将该String编码为一系列字节,将结果存储到新的字节数组中 |
byte[ ] getBytes(String charsetName) | 使用指定的字符集将该String编码为一系列字节,将结果存储到新的字节数组中 |
String解码
构造器 | 说明 |
---|---|
String(byte[ ] bytes) | 通过使用平台的默认字符集解码指定的字节数组来构造新的String |
String(byte[ ] bytes,string charsetName) | 通过指定的字符集解码指定的字节数组来构造新的String |
2、IO流概述
IO也称为输入、输出流,就是用来读写数据的。
- I表示intput,是数据从硬盘文件读入到内存的过程,称之输入,负责读。
- O表示output,是内存程序的数据从内存到写出到硬盘文件的过程,称之输出,负责写。
IO流的分类
总结流的四大类:
- 字节输入流: 以内存为基准,来自磁盘文件/网络中的数据以字节的形式读入到内存中去的流称为字节输入流。
- 字节输出流: 以内存为基准,把内存中的数据以字节写出到磁盘文件或者网络中去的流称为字节输出流。
- 字符输入流: 以内存为基准,来自磁盘文件/网络中的数据以字符的形式读入到内存中去的流称为字符输入流。
- 字符输出流: 以内存为基准,把内存中的数据以字符写出到磁盘文件或者网络介质中去的流称为字符输出流。
3、字节流的使用
3.1 文字字节输入流
文件字节输入流:FilelnputStream
作用:以内存为基准,把磁盘文件中的数据以字节的形式读取到内存中去。
构造器 | 说明 |
---|---|
public FileInputStream(File file)创建字节 | 输入流管道与源文件对象接通 |
public FileInputStream(String pathname) | 创建字节输入流管道与源文件路径接通 |
方法名称 | 说明 |
---|---|
public int read() | 每次读取一个字节返回,如果字节已经没有可读的返回-1 |
public int read(byte[] buffer) | 每次读取一个字节数组返回,如果字节已经没有可读的返回-1 |
读取一个字节,性能较慢,读取中文字符输出无法避免乱码问题。
java
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class FileInputStreamDemo01 {
public static void main(String[] args) throws Exception {
// 创建一个文件字节输入流管道与源文件接通。
InputStream is = new FileInputStream("file-io-app\\src\\data.txt");
int b;
while (( b = is.read() ) != -1){
System.out.print((char) b);
}
}
}
读取一个字节数组读取性能得到了提升,读取中文字符输出无法避免乱码问题。
java
import java.io.FileInputStream;
import java.io.InputStream;
public class FileInputStreamDemo02 {
public static void main(String[] args) throws Exception {
// 创建一个文件字节输入流管道与源文件接通
InputStream is = new FileInputStream("file-io-app/src/data02.txt");
byte[] buffer = new byte[3];
int len; // 记录每次读取的字节数。
while ((len = is.read(buffer)) != -1) {
// 读取多少倒出多少
System.out.print(new String(buffer, 0 , len));
}
}
}
为了实现使用字节输入流读取中文内容不乱码,定义一个与文件一样大的字节数组,一次性读取完文件的全部字节。如果文件过大,字节数组可能引起内存溢出。
方式一
自己定义一个字节数组与文件的大小一样大,然后使用读取字节数组的方法,一次性读取完成。
方法名称 | 说明 |
---|---|
public int read(byte[] buffer) | 每次读取一个字节数组返回,如果字节已经没有可读的返回-1 |
方式二
官方为字节输入流InputStream提供了如下API可以直接把文件的全部数据读取到一个字节数组中。
方法名称 | 说明 |
---|---|
public byte[]readAllBytes() throws IOException | 直接将当前字节输入流对应的文件对象的字节数据装到一个字节数组返回 |
java
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
/**
使用文件字节输入流一次读完文件的全部字节。可以解决乱码问题。
*/
public class FileInputStreamDemo03 {
public static void main(String[] args) throws Exception {
//创建一个文件字节输入流管道与源文件接通
File f = new File("file-io-app/src/data03.txt");
InputStream is = new FileInputStream(f);
// 读取全部字节数组
byte[] buffer = is.readAllBytes();
System.out.println(new String(buffer));
}
}
3.2 文件字节输出流
作用:以内存为基准,把内存中的数据以字节的形式写出到磁盘文件中去的流。
构造器 | 说明 |
---|---|
public FileoutputStream(File file) | 创建字节输出流管道与源文件对象接通 |
public FileOutputStream(File file, boolean append) | 创建字节输出流管道与源文件对象接通,可追加数据 |
public Fileoutputstream(String filepath) | 创建字节输出流管道与源文件路径接通 |
public FileOutputstream(String filepath, boolean append) | 创建字节输出流管道与源文件路径接通,可追加数据 |
文件字节输出流(FileOutputStream)写数据出去的API
方法名称 | 说明 |
---|---|
public void write(int a) | 写一个字节出去 |
public void write(byte[ ] buffer) | 写一个字节数组出去 |
public void write(byte[ ] buffer , int pos , int len) | 写一个字节数组的一部分出去 |
流的关闭与刷新
方法 | 说明 |
---|---|
flush() | 刷新流,还可以继续写数据 |
close() | 关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据 |
字节输出流实现写出去的数据能换行:os.write("\r\n" .getBytes())
让写出去的数据能成功生效:
- flush()刷新数据
- close()方法是关闭流,关闭包含刷新,关闭后流不可以继续使用了
java
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class OutputStreamDemo {
public static void main(String[] args) throws Exception {
// 1、创建一个文件字节输出流管道与目标文件接通
OutputStream os = new FileOutputStream("file-io-app/src/out04.txt" , true); // 追加数据管道
// OutputStream os = new FileOutputStream("file-io-app/src/out04.txt"); // 先清空之前的数据,写新数据进入
// 2、写数据出去
// a.public void write(int a):写一个字节出去
os.write('a');
os.write(98);
os.write("\r\n".getBytes()); // 换行
// os.write('徐'); // [ooo]
// b.public void write(byte[] buffer):写一个字节数组出去。
byte[] buffer = {'a' , 97, 98, 99};
os.write(buffer);
os.write("\r\n".getBytes()); // 换行
byte[] buffer2 = "我是中国人".getBytes();
// byte[] buffer2 = "我是中国人".getBytes("GBK");
os.write(buffer2);
os.write("\r\n".getBytes()); // 换行
// c. public void write(byte[] buffer , int pos , int len):写一个字节数组的一部分出去。
byte[] buffer3 = {'a',97, 98, 99};
os.write(buffer3, 0 , 3);
os.write("\r\n".getBytes()); // 换行
// os.flush(); // 写数据必须,刷新数据 可以继续使用流
os.close(); // 释放资源,包含了刷新的!关闭后流不可以使用了
}
}
3.3 文件拷贝
需求:
把某个视频复制到其他目录下的"b.avi"
思路:
- 根据数据源创建字节输入流对象
- 根据目的地创建字节输出流对象
- 读写数据,复制视频
- 释放资源
java
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
/**
* 学会使用字节流完成文件的复制(支持一切文件类型的复制)
*/
public class CopyDemo {
public static void main(String[] args) {
try {
// 1、创建一个字节输入流管道与原视频接通
InputStream is = new FileInputStream("file-io-app/src/out04.txt");
// 2、创建一个字节输出流管道与目标文件接通
OutputStream os = new FileOutputStream("file-io-app/src/out05.txt");
// 3、定义一个字节数组转移数据
byte[] buffer = new byte[1024];
int len; // 记录每次读取的字节数。
while ((len = is.read(buffer)) != -1){
os.write(buffer, 0 , len);
}
System.out.println("复制完成了!");
// 4、关闭流。
os.close();
is.close();
} catch (Exception e){
e.printStackTrace();
}
}
}
4、资源释放的方式
4.1 try-catch-finally
- finally:在异常处理时提供finally块来执行所有清除操作,比如说IO流中的释放资源
- 特点:被finally控制的语句最终一定会执行,除非JVM退出
- 异常处理标准格式: try...catch...finally
java
try {
FileOutputStream fos = new FileOutputStream( "a.txt");
fos.write(97);
fos.close();
}catch ( IOException e) {
e.printStackTrace();
}finally{
}
java
import java.io.*;
/**
* 学会使用finally释放资源。
*/
public class TryCatchFinallyDemo1 {
public static void main(String[] args) {
InputStream is = null;
OutputStream os = null;
try {
// System.out.println(10/ 0);
// 1、创建一个字节输入流管道与原视频接通
is = new FileInputStream("file-io-app/src/out04.txt");
// 2、创建一个字节输出流管道与目标文件接通
os = new FileOutputStream("file-io-app/src/out05.txt");
// 3、定义一个字节数组转移数据
byte[] buffer = new byte[1024];
int len; // 记录每次读取的字节数。
while ((len = is.read(buffer)) != -1){
os.write(buffer, 0 , len);
}
System.out.println("复制完成了!");
// System.out.println( 10 / 0);
} catch (Exception e){
e.printStackTrace();
} finally {
// 无论代码是正常结束,还是出现异常都要最后执行这里
System.out.println("========finally=========");
try {
// 4、关闭流。
if(os!=null)os.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(is != null) is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println(test(10, 2));
}
public static int test(int a , int b){
try {
int c = a / b;
return c;
}catch (Exception e){
e.printStackTrace();
return -111111; // 计算出现bug.
}finally {
System.out.println("--finally--");
// 哪怕上面有return语句执行,也必须先执行完这里才可以!
// 开发中不建议在这里加return ,如果加了,返回的永远是这里的数据了,这样会出问题!
return 100;
}
}
}
4.2 try-with-resource
JDK7和JDK9中都简化了资源释放操作
5、字符流的使用
5.1 文件字符输入流
文件字符输入流: Reader
作用:以内存为基准,把磁盘文件中的数据以字符的形式读取到内存中去。
构造器 | 说明 |
---|---|
public FileReader(File file) | 创建字符输入流管道与源文件对象接通 |
public FileReader(String pathname) | 创建字符输入流管道与源文件路径接通 |
方法名称 | 说明 |
---|---|
public int read() | 每次读取一个字符返回,如果字符已经没有可读的返回-1 |
public int read(char[] buffer) | 每次读取一个字符数组,返回读取的字符个数,如果字符已经没有可读的返回-1 |
每次读取一个字符:读取中文字符不会出现乱码(如果代码文件编码一致);性能较慢。 |
java
import java.io.File;
import java.io.FileReader;
import java.io.Reader;
public class FileReaderDemo01 {
public static void main(String[] args) throws Exception {
// 目标:每次读取一个字符。
// 创建一个字符输入流管道与源文件接通
Reader fr = new FileReader("file-io-app\\src\\data06.txt");
int code;
while ((code = fr.read()) != -1){
System.out.print((char) code);
}
}
}
每次读取一个字符数组:读取的性能得到了提升,读取中文字符输出不会乱码。
java
import java.io.FileReader;
import java.io.Reader;
public class FileReaderDemo02 {
public static void main(String[] args) throws Exception {
// 1、创建一个文件字符输入流与源文件接通
Reader fr = new FileReader("file-io-app/src/data07.txt");
// 2、用循环,每次读取一个字符数组的数据。 1024 + 1024 + 8
char[] buffer = new char[1024]; // 1K字符
int len;
while ((len = fr.read(buffer)) != -1) {
String rs = new String(buffer, 0, len);
System.out.print(rs);
}
}
}
5.2 文件字符输出流
文件字符输出流:FileWriter
作用:以内存为基准,把内存中的数据以字符的形式写出到磁盘文件中去的流。
构造器 | 说明 |
---|---|
public Filewriter(File file) | 创建字符输出流管道与源文件对象接通 |
public Filewriter(File file, boolean append) | 创建字符输出流管道与源文件对象接通,可追加数据 |
public Filewriter(string filepath) | 创建字符输出流管道与源文件路径接通 |
public Filewriter(String filepath,boolean append) | 创建字符输出流管道与源文件路径接通,可追加数据 |
文件字符输出流(FileWriter)写数据出去的API
方法名称 | 说明 |
---|---|
void write(int c) | 写一个字符 |
void write(char[] cbuf) | 写入一个字符数组 |
void write(char[]cbuf, int off, int len) | 写入字符数组的一部分 |
void write(String str) | 写一个字符串 |
void write(String str, int off, int len) | 写一个字符串的一部分 |
void write(int c) | 写一个字符 |
流的关闭与刷新 | |
方法 | 说明 |
:-: | :-: |
flush() | 刷新流,还可以继续写数据 |
close() | 关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据 |
字符输出流实现写出去的数据能换行:fw.write("\r\n")
java
import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
public class FileWriterDemo03 {
public static void main(String[] args) throws Exception {
// 1、创建一个字符输出流管道与目标文件接通
// Writer fw = new FileWriter("file-io-app/src/out08.txt"); // 覆盖管道,每次启动都会清空文件之前的数据
Writer fw = new FileWriter("file-io-app/src/out08.txt", true); // 覆盖管道,每次启动都会清空文件之前的数据
// a.public void write(int c):写一个字符出去
fw.write(98);
fw.write('a');
fw.write('徐'); // 不会出问题了
fw.write("\r\n"); // 换行
// b.public void write(String c)写一个字符串出去
fw.write("abc我是中国人");
fw.write("\r\n"); // 换行
// c.public void write(char[] buffer):写一个字符数组出去
char[] chars = "abc我是中国人".toCharArray();
fw.write(chars);
fw.write("\r\n"); // 换行
// d.public void write(String c ,int pos ,int len):写字符串的一部分出去
fw.write("abc我是中国人", 0, 5);
fw.write("\r\n"); // 换行
// e.public void write(char[] buffer ,int pos ,int len):写字符数组的一部分出去
fw.write(chars, 3, 5);
fw.write("\r\n"); // 换行
// fw.flush();// 刷新后流可以继续使用
fw.close(); // 关闭包含刷线,关闭后流不能使用
}
}