IO流概述
体系结构图
介绍: 在程序中所有的数据都是以流的方式进行传输或保存的,程序通过输入流读取数据;当程序需要将一些数据长期保存起来的时候使用输出流完成。
例如:本地文件拷贝,上传文件和下载文件等等。
注意:
- 但凡是对数据的操作,Java都是通过流的方式来操作的。
- 程序中的输入输出都是以流的形式保存的,流中保存的实际上全都是字节文件。
- IO流可以做到数据的持久化,但是IO流本质上是用来处理本地文件系统以及不同设备之间的数据传输。
- 凡是针对流的操作(数据的传输),必须经过内存。
- 流的操作必须确定 数据源 目的地 交通工具。
- 凡是从内存 -> 外界 (输出 键盘 文件 网络) 选择输出流。
- 凡是从外界(输出 键盘 文件 网络) -> 内存 选择输入流。
IO流分类
按数据流向
- 输入流:从外界(键盘、网络、文件…)读取数据到内存
- 输出流:用于将程序中的数据写出到外界(显示器、文件…)
数据源 目的地 交通工具 c->文件A --> d->文件A
按数据类型
-
字节流:主要用来处理字节或二进制对象,虽然也可以处理文本文件但由于要考虑编码问题所以不是那么方便(MP3、png、jpg)。
-
字节输入流(InputStream)
InputStream is = new FileInputStream("b.txt"); PrintStream ps = System.out; byte[] bys = new byte[1024]; int len = 0; while ((len = is.read(bys)) != -1) { ps.print(new String(bys, 0, len)); }
-
字节输出流(OutputStream)
OutputStream os = new FileOutputStream("b.txt"); os.write("hello".getBytes()); os.close();
-
IO的文件拷贝
public class CopyFile {
public static void main(String []args) {
copyFile("idea.docx", "D:\\idea.docx", 8192);
}
public static void copyFile(String srcFileName,String descFileName,int capacity) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(srcFileName);
fos = new FileOutputStream(descFileName);
int len = 0;
byte[] reads = new byte[capacity];
while ((len = fis.read(reads))!=-1) {
fos.write(reads,0,len);
fos.flush();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
autoClose(fis, fos);
}
}
// 定义一个方法关闭资源,
public static void autoClose(AutoCloseable... resources) {
for (AutoCloseable resource : resources) {
if (resource != null) {
try {
resource.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
- 字符流:主要用来处理字符、字符数组或字符串等文本文件(html、css、js、java、json)。
- 字符输入流(Reader)
- 字符输出流(Writer)
字节流
注意事项:
-
数据写入完成后记得调用close()方法关闭流对象
-
数据追加写入要使用如下构造方法:
FileOutputStream(File file, boolean append)
-
不同的系统针对不同的换行符号识别是不一样的
例如:windows识别的换行符是\r\n,Linux识别的换行符是\n等等。
常见的一些高级记事本,是可以识别任意换行符号的。
-
数据写入中存在两个异常需要处理FileNotFoundException,IOException。
字节输入流
- InputStream
- FileInputStream
- FileInputStream的构造方法
- FileInputStream(File file) 创建一个从file读取数据的输入流
- FileInputStream(String name) 创建一个从name文件读取数据的输入流
- FileInputStream的成员方法
- int read() 一次读取一个字节
- int read(byte[] b) 一次读取一个字节数组
- int read(byte[] b, int off, int len) 一次读取一个字节数组的一部分
- void close() 关闭此文件输入流并释放与此流有关的所有系统资源
- FileInputStream的构造方法
字节缓冲流
-
通过之前的学习观察我们发现,字节流一次读写一个字节数组,大小为1024的速度明显比一次读写一个字节的速度要快的多的多,因为这里加入了数组缓冲区的思想,Java考虑到流读写效率的提升所以为我们提供了字节缓冲流。
- 字节缓冲输出流:BufferedOutputStream
- 字节缓冲输入流:BufferedInputStream
与上面没什么区别,只是效率更快
public class CopyFile { public static void main(String []args) { copyFile("idea.docx", "D:\\idea.docx", 8192); } public static void copyFile(String srcFileName,String descFileName,int capacity) { BufferedInputStream fis = null; BufferedOutputStream fos = null; try { fis = new BufferedInputStream(new FileInputStream(srcFileName)); fos = new BufferedOutputStream(new FileOutputStream(descFileName)); int len = 0; byte[] reads = new byte[capacity]; while ((len = fis.read(reads))!=-1) { fos.write(reads,0,len); fos.flush(); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { autoClose(fis, fos); } } // 定义一个方法关闭资源, public static void autoClose(AutoCloseable... resources) { for (AutoCloseable resource : resources) { if (resource != null) { try { resource.close(); } catch (Exception e) { e.printStackTrace(); } } } } }
字符流的引入
**字符流产生的原因:**字节流虽然作为万能流,但是在对字符进行处理的时候不是很方便,可能因为某些人为的操作出现乱码现象,所以Java就提供了字符流。
**介绍:**Writer(抽象类,不能直接使用,选择子类)
OutputStreamWriter(转换流,是字符流通向字节流的桥梁,可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认字符集编码。)
构造方法
- OutputStreamWriter(OutputStream out) 创建使用默认字符编码的字符输出转换流
- OutputStreamWriter(OutputStream out, Charset cs) 创建使用cs字符集的字符输出转换流
- OutputStreamWriter(OutputStream out, CharsetEncoder enc) 创建使用enc字符集编码器的
- OutputStreamWriter(OutputStream out, String charsetName) 创建使用指定字符集的
OutputStreamWriter的成员方法
- public void write(int c) 写一个字符
- public void write(char[] cbuf) 写一个字符数组
- public void write(char[] cbuf,int off,int len) 写一个字符数组的一部分
- public void write(String str) 写一个字符串
- public void write(String str,int off,int len) 写一个字符串的一部分
- void close() 关闭流对象
- void flush() 清空缓存
InputStreamWriter读数据方法
- public int read()
- public int read(char[] cbuf)
FileReader和FileWriter
- FileWriter:用来写入字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是可接受的。要自己指定这些值,可以先在 FileOutputStream 上构造一个OutputStreamWriter。
- FileReader:用来读取字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的。要自己指定这些值,可以先在 FileInputStream 上构造一个 InputStreamReader。
- 构造方法类似FileInputStream和FileOutputStream
- 成员方法完全继承自父类OutputStreamWriter和InputStreamReader
字符缓冲流
- 类似于字节流的BufferedOutputStream和BufferedInputStream,字符流同样存在字符字符缓冲流同理,字符缓冲流也是为了提高字符流的效率。
- BufferedWriter和BufferedReader继承自Writer和Reader,所以具备原有的读取方法,但是还存在自己特有的方法。
- 特有的方法:
- BufferedWriter:void newLine()
- BufferedReader:String readLine()
编码表
- 编码表:现实世界的字符所对应的数值组成的一张参照表。
- 常见编码表
- ASCII 美国标准信息交换码
- Unicode 国际标准码
- UTF-8 最多用三个字节来表示一个字符。
- ISO-8859-1 拉丁码表。欧洲码表。
- GB2312/GBK/GB18030 中文编码表。
- Java平台中默认采用的编码方式是GBK。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YFDLcWCK-1585476900656)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1585448993983.png)]
编码和解码
- 有关编码的问题在有中文的Java开发中是个大问题,其实解决起来很简单。
- 编码:
- 编码是信息从一种形式或格式转换为另一种形式的过程称为编码
- 简单来说,编码就是将看得懂的信息通过编码表转换成为看不懂的信息
- 解码:
- 是编码的逆过程。
- GB2312/GBK/GB18030 中文编码表。
- Java平台中默认采用的编码方式是GBK。
(下表源自百度搜索)
编码和解码
- 有关编码的问题在有中文的Java开发中是个大问题,其实解决起来很简单。
- 编码:
- 编码是信息从一种形式或格式转换为另一种形式的过程称为编码
- 简单来说,编码就是将看得懂的信息通过编码表转换成为看不懂的信息
- 解码:
- 是编码的逆过程。
- 简单来说,解码就是将看不懂的信息通过编码表转换为看得懂的信息