title: IO流之基本流
index_img: img/25.svg
tags:
- Java SE
- 异常
- IO流
categories:
- Java SE
excerpt: IO流
IO流概述
IO流就是程序从外部或网络读取数据。
分类
根据流的方向:
根据操作的文件类型:
字节流
实现类速记:File+接口
本地字节输出流
- 创建字节输出流对象
- 写数据
- 释放资源
public class Main {
public static void main(String[] args) throws Exception {
//【对于程序来说】写出一段数据到文本,使用输出流
FileOutputStream out = new FileOutputStream("src\\main\\java\\bid\\simpleword\\io\\my.txt");
String str = "Hello,java!\nmy name is simpleWord"; //要换行,只需要写入换行符即可,不想环也可以使用\\转义
out.write(str.getBytes()); //注意write的参数
out.close();
}
}
public class Main {
public static void main(String[] args) throws Exception {
String path = "src\\main\\java\\bid\\simpleword\\io\\my.txt";
FileOutputStream out = new FileOutputStream(path, true); //开启追加
String str = "Hello,java!\nmy name is simpleWord";
out.write(str.getBytes());
out.close();
}
}
FileOutputStream
- 文件不存在,会创建文件【前提是父级目录有效】
- 文件存在,构造方法默认会清空文件
- 第二个参数修改为
true可开启追加功能。write:支持ASCII和byte字符,byte数组、byte数组的部分写入
本地字节输入流
- 创建字节输入流对象
- 写数据
- 释放资源
public class Main {
public static void main(String[] args) throws Exception {
//【对于程序来说】读入一段数据到文本,使用输入流
String path = "src\\main\\java\\bid\\simpleword\\io\\my.txt";
FileInputStream in = new FileInputStream(path);
byte[] bytes = in.readAllBytes();
String str = new String(bytes); //通过String构造方法返回字符串形式
System.out.println(str);
in.close();
}
}
//上一个指针到末尾了
public class Main {
public static void main(String[] args) throws Exception {
String path = "src\\main\\java\\bid\\simpleword\\io\\my.txt";
FileInputStream in = new FileInputStream(path);
int b;
byte[] bs = new byte[1024];
while ((b = in.read(bs)) != -1) {
String s = new String(bs, 0, b); // 创建新字符串
System.out.println(s);
}
in.close();
}
}
//上一个指针到末尾了
public class Main {
public static void main(String[] args) throws Exception {
String path = "src\\main\\java\\bid\\simpleword\\io\\my.txt";
FileInputStream in = new FileInputStream(path);
int b;
while ((b = in.read()) != -1) { //指针会后移,要存储读到的值
System.out.print((char) b);
}
in.close();
}
}
FileInputStream:文件不存在,直接报错read方法每次读取一个字节【包括空】的ASCII,指针后移,读到末尾会返回-1;
- read支持一个一个读【搭配循环】
- 太慢
- 支持边读边写
- read支持一次读取
byte[k]长度或部分的数据【返回值是读取到的长度】
- 推荐,但数组不推荐设置的太大,一般是1024的倍数。
- 支持边读编写,指针每次移动数组长度
- 使用
readALLBytes读取全部字节。【返回值是数组】
- 全部读到内存,再一次性写入文件
- 适用于小文件传输
文件拷贝
- 输入流读入,输出流写出
public class Main {
public static void main(String[] args) throws Exception {
String path1 = "src\\main\\java\\bid\\simpleword\\io\\my.txt";
String path2 = "src\\main\\java\\bid\\simpleword\\io\\you.txt";
FileInputStream in = new FileInputStream(path1);
FileOutputStream out = new FileOutputStream(path2);
int b;
byte[] bytes = new byte[1024 * 1024 * 5];
while ((b = in.read(bytes)) != -1) {
out.write(bytes, 0, b); //写入的长度是有效长度b
}
in.close();
out.close();
}
}
字符集
ASCII字符集
- 最大128,1byte最大\(2^8=256\),\(2^7\)即可解决存储。
- 只能存储英文且占
1字节 - 编码规则:左边第一位用不到,补为0
GBK中文字符
- 存储英文兼容ASCII:
1字节 - 存储中文:
2字节,最大\(2^16=65536\),足够使用 - 编码规则:
- 英文:左边第一位用不到,补为0
- 中文:左边字节第一位一定是1【防止与英文混淆,看到1就知道还要读一个字节】
Unicode
UTF-8(Unicode Transfer Format),Unicode下的一种编码方式【一般默认使用此编码】
- 存储英文兼容ASCII:
1字节 - 存储中文:
3字节 - 编码规则:
- 英文:左边第一位用不到,补为0
- 中文:
1110xxxx 10xxxxxx 10xxxxxx的格式【1110开头,3个字节】
中文乱码
原因
-
读取时字节不对,比如一个一个字节的读。
- 如果我们只是拷贝等,只要数据不丢失,不会乱码
-
编码和解码规则不一致
解决
- 使用字符流读取中文文本【可能包含中英文,不建议使用字节流】
- 编码和解码规则保持一致
编码和解码代码
| 方法 | 说明 |
|---|---|
public byte[ ] getBytes() |
使用默认方式进行编码 |
public byte[] getBytes(string charsetName) |
使用指定方式进行编码 |
string(byte[ ] bytes) |
使用默认方式进行解码 |
string(byte[ ] bytes,string charsetName) |
使用指定方式进行解码 |
public class Main {
public static void main(String[] args) throws UnsupportedEncodingException {
String s = "I am 张三";
//编码
int length = s.getBytes().length; //默认字符集:UTF-8
System.out.println(length); //中文占3字节,共11字节
int length1 = s.getBytes("GBK").length;
System.out.println(length1); //中文占2字节,共9字节
//解码
String s1 = new String(s.getBytes()); //默认解码UTF-8
System.out.println(s1.equals(s)); //解码结果是否一致
String s2 = new String(s.getBytes("GBK"), "GBK"); //GBK
System.out.println(s2.equals(s));
}
}

字符流
实现类速记:File+接口
简述
编码规则都默认UTF-8,我们只需要采用字符流读取中文相关文本即可。
特点:
-
底层还是字符流
-
一次读取一个字节,遇到中文,读多个字节【与字符集相关】,写入时按指定编码好后写入文件
-
只能操作纯文本
本地字符输出流
参考字节流
public class Main {
public static void main(String[] args) throws Exception {
String path = "src\\main\\java\\bid\\simpleword\\io\\my.txt";
FileWriter out = new FileWriter(path, true); //开启追加
String s = "\n折戟沉沙铁未销,自将磨洗认前朝.";
String s1 = "\n谈笑间樯橹灰飞烟灭.";
out.write(s);
out.write(s1.toCharArray());
out.close();
}
}

本地字符输入流
参考字节流
public class Main {
public static void main(String[] args) throws IOException {
FileReader in = new FileReader("src\\main\\java\\bid\\simpleword\\io\\my.txt");
int b;
while ((b = in.read()) != -1) {
System.out.print((char) b);
}
in.close();
}
}
//上一个指针到末尾了
public class Main {
public static void main(String[] args) throws IOException {
FileReader in = new FileReader("src\\main\\java\\bid\\simpleword\\io\\my.txt");
int b;
char[] chars = new char[1024 * 1024];
while ((b = in.read(chars)) != -1) {
String s = new String(chars, 0, b);
System.out.println(s);
}
in.close();
}
}

拷贝文件
还是推荐使用字节流
public class Main {
public static void main(String[] args) throws Exception {
String path1 = "src\\main\\java\\bid\\simpleword\\io\\my.txt";
String path2 = "src\\main\\java\\bid\\simpleword\\io\\you.txt";
FileReader in = new FileReader(path1);
FileWriter out = new FileWriter(path2);
int b;
char[] chars = new char[1024];
while ((b = in.read(chars)) != -1) {
String s = new String(chars, 0, b);
out.write(s);
}
in.close();
out.close();
}
}
IO流异常捕获
之前我们与IO相关的异常,层层上抛,最后交给JVM,如果我们自己要处理,但是关闭资源又执行不到,怎么处理?
try…catch..finally
try{
}catch(异常类型 变量){
}finally{
//这里的代码一定执行,除非JVM停止
}
public class Main {
public static void main(String[] args) {
String path1 = "src\\main\\java\\bid\\simpleword\\io\\my.txt";
String path2 = "src\\main\\java\\bid\\simpleword\\io\\you.txt";
FileInputStream in = null; //只定义【finally要使用】,因为创建有编译时异常,创建应该在try中
FileOutputStream out = null;
try {
in = new FileInputStream(path1); //这里可能建立不成功,也有异常,在close之前要处理
out = new FileOutputStream(path2);
int b;
byte[] bytes = new byte[1024 * 1024 * 5];
while ((b = in.read(bytes)) != -1) {
out.write(bytes, 0, b);
}
} catch (IOException e) {
e.printStackTrace();
} finally { //关闭也有异常,还要继续异常处理
if (in != null) {
try {
in.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
}
简化方案
上方代码的复杂来自close
jdk9方案,自动关闭(特殊情况下)
public class Main {
public static void main(String[] args) throws FileNotFoundException { //抛
String path1 = "src\\main\\java\\bid\\simpleword\\io\\my.txt";
String path2 = "src\\main\\java\\bid\\simpleword\\io\\you.txt";
FileInputStream in = new FileInputStream(path1);
FileOutputStream out = new FileOutputStream(path2);
try (in; out) {
int b;
byte[] bytes = new byte[1024 * 1024 * 5];
while ((b = in.read(bytes)) != -1) {
out.write(bytes, 0, b);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}