IO
第二十八章 IO流概述与文件流
提纲
- 28.1 IO流概述
- 28.1.1 什么是流
- 28.1.2 流的特点
- 28.1.3 流的分类
- 28.1.4 流结构介绍
- 28.1.5 字符流和字节流
- 28.1.6 输入流和输出流
- 28.2 文件字节输入流/输出流
- 28.2.1 为什么使用文件流
- 28.2.2 文件字节输入流
- 28.2.3 文件字节输出流
- 28.2.4 综合文件字节输入/输出流举例
- 28.3 文件字符输入流/输出流
- 28.3.1 为什么使用字符输入/输出流
- 28.3.2 文件字符输入流
- 28.3.3 文件字符输出流
- 28.3.4 综合文件字符输入/输出流举例
- 28.4 使用两种流来实现复制功能
- 28.4.1 使用字符流进行文档与图片的复制
- 28.4.2 使用字节流进行文档与图片的复制
28.1 IO流概述
- 28.1.1 什么是流:流是个抽象的概念,是对输入输出设备的抽象,Java程序中,对于数据的输入/输出操作都是以“流”的方式进行。设备可以是文件,网络,内存等。

- 28.1.2 流的特点:流具有方向性,至于是输入流还是输出流则是一个相对的概念,一般以程序为参考,如果数据的流向是程序至设备,我们成为输出流,反之我们称为输入流。可以将流想象成一个“水流管道”,水流就在这管道中形成了,自然就出现了方向的概念。当程序需要从某个数据源读入数据的时候,就会开启一个输入流,数据源可以是文件、内存或网络等等。相反地,需要写出数据到某个数据源目的地的时候,也会开启一个输出流,这个数据源目的地也可以是文件、内存或网络等等。

- 28.1.3 流的分类:可以从不同的角度对流进行分类:
- 根据处理数据类型的不同分为:字符流和字节流。
- 根据数据流向不同分为:输入流和输出流。
- 28.1.4 流结构介绍:
-
Java所有的流类位于java.io包中,都分别继承至以下四种(抽象类)流类型。
字节流 字符流
输入流 InputStream Reader
输出流 OutputStream Writer -
Java流类图结构:

-
- 28.1.5 字符流和字节流
- 字节流:按照字节来读写文件。
- 字符流:因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。Java中的字符是Unicode编码,一个字符占用两个字节。
- 字节流和字符流的区别:
- 读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
- 处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。
- 结论:只要是处理纯文本数据,就优先考虑使用字符流。 除此之外都使用字节流。
- 28.1.6 输入流和输出流:对输入流只能进行读操作,对输出流只能进行写操作。即读入写出。
28.2 文件字节输入流/输出流
- 28.2.1 为什么使用文件流:程序运行期间,大部分数据都是在内存中进行操作,当程序结束或关闭时,这些数据将消失。如果需要将数据永久保存,可使用文件输入/输出流与指定的文件建立连接,将需要的数据永久保存到文件中。
- 28.2.2 文件字节输入流:FileInputStream类:继承了InputStream类,专门用来读取文件。读取的文件必须存在,且路径必须正确,否则报异常。
- 构造方法:
- FileInputStream(File file):通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的 File 对象 file 指定。这个方法允许在把文件连接输入流之前对文件进行进一步分析。
- FileInputStream(String name) :通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的路径名 name 指定。
- 常用方法:
- close():关闭此文件输入流并释放与此流有关的所有系统资源。返回值:void。
- read():从此输入流中读取一个数据字节。返回值:int。
- read(byte[] b):从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。返回值:int。
- read(byte[] b, int off, int len):从此输入流中将最多 len 个字节的数据读入一个 byte 数组中。返回值:int。其中,b - 存储读取数据的缓冲区。off - 目标数组 b 中的起始偏移量。len - 读取的最大字节数。
- skip(long n): 从输入流中跳过并丢弃 n 个字节的数据。返回值:long。
- 构造方法:
- 28.2.3 文件字节输出流:FileOutputStream类:继承了OutputStream类,专门用来写入文件。当写入的文件不存在时,会自动创建一个,但是文件父级文件夹目录必须存在,否则会报异常。
- 构造方法
- FileOutputStream(File file):创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
- FileOutputStream(File file, boolean append):创建一个向指定 File 对象表示的文件中写入数据的文件输出流。append:是否覆盖原文档。ture-接着文件内容的末尾继续写入内容。false-覆盖原文档。
- FileOutputStream(String name):创建一个向具有指定名称的文件中写入数据的输出文件流。
- FileOutputStream(String name, boolean append):创建一个向具有指定 name 的文件中写入数据的输出文件流。
- 常用方法:
- close():关闭此文件输出流并释放与此流有关的所有系统资源。返回值:void。
- write(byte[] b):将 b.length 个字节从指定 byte 数组写入此文件输出流中。返回值:。
- write(byte[] b, int off, int len):将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。
- write(int b):将指定字节写入此文件输出流。
- 构造方法
- 28.2.4 综合文件字节输入/输出流举例:
-
写文件
public class IoDemo1 {
public static void main(String[] args) {
try {
//1.使用输出流写文件
//创建FileOutputStream对象,当写入的文件不存在时,会自动创建一个,
//但是文件父级文件夹目录必须存在,否则会报异常。
FileOutputStream fos = new FileOutputStream("E:\JavaTest\lpm.txt");
//创建字符串,并且转化成byte数组
byte[] by = "我有一只小毛驴,我从来也不骑。".getBytes();
fos.write(by);
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
} -
读取文件
public class IoDemo2 {
public static void main(String[] args) {
File file = new File("E:\JavaTest\lpm.txt");
try {
//2.创建FileInputStream对象,读取的文件必须存在,且路径必须正确,否则报异常
FileInputStream fis = new FileInputStream(file);
//方法一:单个字节的读取
// String str = "";
// int c = 0;
// while((c = fis.read()) != -1){
// //将字节转化成字符,然后用字符串拼接
// //为什么会乱码:因为读取的是一个字节,而汉字GBK和Unicode编码下是2个字节,UTF-8是三个字节
// str += (char) c;
// }
// //最后由字符转化成字节数组
// System.out.println(new String(str.getBytes("ISO-8859-1")));
//方法二:多个字节读取
byte[] by = new byte[3];//UTF-8状态下一个汉字占三个字节
while(fis.read(by) != -1){
System.out.println(new String(by));
}
fis.close();//关闭流
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
结论:虽然Java在程序结束时自动关闭所有开打的流,但是当使用完流后,显式地关闭所有打开的流仍是一个好习惯。一个被打开的流有可能会用尽系统资源,这取决于平台和实现。如果没有将打开的流关闭,当另一个程序试图打开另一个流时,可能会得不到需要的资源。
-
28.3 文件字符输入流/输出流
- 28.3.1 为什么使用字符输入/输出流:文件字节流这两个类写入文件和读取文件只提供了对字节或字节数组的读写方法。由于一个汉字占2-3个字节,如果使用字节流,就很容易出现乱码现象。此时采用字符输入/输出流Reader/Writer类即可避免这种现象。
- 28.3.2 文件字符输入流:FileReader类,继承了InputStreamReader类。
- 构造方法:
- FileReader(File file):在给定从中读取数据的 File 的情况下创建一个新 FileReader。
- FileReader(String fileName):在给定从中读取数据的文件名的情况下创建一个新 FileReader。
- 常用方法:
- read():读取单个字符。返回值:int。
- read(char[] cbuf):将字符读入数组。返回值:int。
- read(char[] cbuf, int off, int len):将字符读入数组的某一部分。返回值:int。
- getEncoding():返回此流使用的字符编码的名称。返回值:String。
- 构造方法:
- 28.3.3 文件字符输出流:FileWriter类,继承OutputStreamWriter类。
- 构造方法:
- FileWriter(File file):根据给定的 File 对象构造一个 FileWriter 对象。
- FileWriter(File file, boolean append):根据给定的 File 对象构造一个 FileWriter 对象。
- FileWriter(String fileName):根据给定的文件名构造一个 FileWriter 对象。
- FileWriter(String fileName, boolean append):根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。
- 常用方法:
- close():关闭此流,但要先刷新它。返回值:void。
- flush():刷新该流的缓冲。返回值:void。
- getEncoding():返回此流使用的字符编码的名称。返回值:String。
- write(char[] cbuf):写入字符数组。
- write(char[] cbuf, int off, int len):写入字符数组的某一部分。返回值:void。
- write(int c):写入单个字符。返回值:void。
- write(String str):写入字符串。返回值:void。
- write(String str, int off, int len):写入字符串的某一部分。返回值:void。
- append(char c):将指定字符添加到此 writer。返回值:Writer。
- 构造方法:
- 28.3.4 综合文件字符输入/输出流举例:
-
写文件
public class IoDemo3 {
public static void main(String[] args) {
try {
//为true,接着后面写
FileWriter fw = new FileWriter("E:\JavaTest\FileWriter.txt", true);
fw.write("你好啊");//写入字符串
fw.write("今天吃什么呢?", 0, 6);//截取一部分写入
fw.write("\r\n");//跨行
char[] ch = {'你','好','呀','!','我','是','j'};
fw.write(ch);//写入字符数组
char[] ch2 = {'a','v','a','!','l','p','m'};
fw.write(ch2, 2, 5);//截取字符数组写入
System.out.println("字符编码为:"+fw.getEncoding());
fw.flush();
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} -
读文件
public class IoDemo4 {
public static void main(String[] args) {
try {
FileReader fr = new FileReader("E:\JavaTest\FileWriter.txt");
//方法一:一个一个字符读
int c = 0;
while((c = fr.read()) != -1){
System.out.print((char)c);
}
//方法二:多个字符一起读
char[] ch = new char[1024];
while(fr.read(ch) != -1){
for (int i = 0; i < ch.length; i++) {
System.out.print(ch[i]);
}
}
fr.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
-
28.4 使用两种流来实现复制功能
- 28.4.1 使用字符流进行文档与图片的复制
-
复制图片
public class IoDemo6 {
public static void main(String[] args) {
try {
//1.复制图片源文件
String pathyPhoto = "C:\Users\hasee\Desktop\文件\timg.jpg";
//11.复制图片目标文件
String pathmPhoto = "E:\JavaTest\fw美女复制版.jpg";
FileReader fry = new FileReader(pathyPhoto);
FileWriter fwm = new FileWriter(pathmPhoto);
//方法一:一个字符复制
int c = 0;
while((c = fry.read()) != -1){
fwm.write(c);
}
//方法二:多个字符复制
char[] ch = new char[1024*1024];
while(fry.read(ch) != -1){
fwm.write(ch);
}
fwm.flush();
fwm.close();
fry.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} -
复制文档
public class IoDemo6 {
public static void main(String[] args) {
try {
//2.复制文档
String pathyTxt = "C:\Users\hasee\Desktop\文件\个人简介-刘盼民.txt";
//22.复制文档目标文件
String pathmTxt = "E:\JavaTest\fw个人简介-刘盼民复制版.txt";
FileReader fry = new FileReader(pathyTxt);
FileWriter fwm = new FileWriter(pathmTxt);
//方法一:一个字符复制
int c = 0;
while((c = fry.read()) != -1){
fwm.write(c);
}
//方法二:多个字符复制
char[] ch = new char[1024*1024];
while(fry.read(ch) != -1){
fwm.write(ch);
}
fwm.flush();
fwm.close();
fry.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
结论:1.字符流不能复制图片;2.字符流复制文字时必须源文档编码与编辑器编码必须一致,如果不一致会出现乱码。
-
- 28.4.2 使用字节流进行文档与图片的复制
-
复制图片
public class IoDemo5 {
public static void main(String[] args) {
try {
//1.复制图片源文件
String pathyPhoto = "C:\Users\hasee\Desktop\文件\timg.jpg";
//11.复制图片目标文件
String pathmPhoto = "E:\JavaTest\fis美女复制版.jpg";
FileInputStream fisy = new FileInputStream(pathyPhoto);
FileOutputStream fosm = new FileOutputStream(pathmPhoto);
//方法一:单个字节复制
int c = 0;
while((c = fisy.read()) != -1){
fosm.write(c);
}
//方法二:多个字节复制
// byte[] by = new byte[1024*1024];
// while(fisy.read(by) != -1){
// fosm.write(by);
// }
fosm.close();
fisy.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
} -
复制文档
public class IoDemo5 {
public static void main(String[] args) {
try {
//2.复制文档
String pathyTxt = "C:\Users\hasee\Desktop\文件\一个大妈误加了一个博士群.docx";
//22.复制文档目标文件
String pathmTxt = "E:\JavaTest\fis一个大妈误加了一个博士群复制版.docx";
FileInputStream fisy = new FileInputStream(pathyTxt);
FileOutputStream fosm = new FileOutputStream(pathmTxt);
//方法一:单个字节复制
int c = 0;
while((c = fisy.read()) != -1){
fosm.write(c);
}
//方法二:多个字节复制
// byte[] by = new byte[1024*1024];
// while(fisy.read(by) != -1){
// fosm.write(by);
// }
fosm.close();
fisy.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
结论:字节流,不论源文件是什么样子,会照原来的样子复制过去。
-

浙公网安备 33010602011771号