目录
一、Java IO原理
1.1 IO流原理
- IO技术用于处理设备之间的数据传输。如读写文件,网络通讯等
- Java程序中,对于数据输入输出操作以==流(“stream”)==的方式进行
- java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据
输入
:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中
输出
:将程序(内存)数据输出到光盘、磁盘等存储设备中
1.2 流的分类
- 按照数据单位不同:字节流(8 bit),字符流(16 bit)
- 按照数据流向:输入流、输出流
- 按照角色不同:节点流,处理流
下图更好的说明了流的分类
1.3 四个抽象基类
字节流 | 字符流 | |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutPutStream | Writer |
- IO流所涉及的40多个,都是从上述4个抽象基类派生来的
- 由这四个抽象基类派生出来的子类名称,都是以其父类名作为子类名后缀
流的体系结构
抽象基类 | 节点流(文件流) | 缓冲流(处理流的一种) |
---|---|---|
InputStream | FileInputStream | BufferedInputStream |
OutputStream | FileOutputStream | BufferedOutputStream |
Reader | FileReader | BufferedReader |
Writer | FileWriter | BufferedWriter |
二、Java IO流的具体使用
2.1 FileReader
2.1.1 FileReader读入数据的基本操作
将guigu20210912下的hello.txt读入到程序中,并输出到控制台
public void test1() {
FileReader fr = null;
//将异常直接处理掉:防止流无法关闭
try {
//1、实例化File类对象,指明要操作的文件
File file = new File("hello.txt");
//在单元测试中相对路径才是相对于当前module下的路径
//System.out.println(file.getAbsolutePath());//D:\IdeaProjects\JavaSenior\guigu20210912\hello.txt
//2、提供具体的流
fr = new FileReader(file);
//3、数据的读入
//read():返回读入的一个字符。如果达到文件末尾,返回-1
//方式一
// int read = fr.read();
// while (read != -1){
// System.out.print((char) read);
// read = fr.read();
// }
//方式二
int data;
while ((data = fr.read()) != -1){
System.out.println((char) data);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4、流的关闭操作.必须手动进行
try {
if (fr != null) {
fr.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
输出:
Hello world!
2.1.1.1涉及到的几个问题
read()的理解
返回读入的一个
字符
,返回值是int型的数字,要输出需要转换类型。如果达到文件末尾,返回-1,
异常的处理
为了保证流资源一定可以执行关闭操作,需要使用
try - catch - finally
进行处理
读入操作
读入的文件一定要存在,否则会报:
FileNotFoundExceprion
2.1.2 read()的升级操作
2.1.2.1 使用read的重载操作(重难点)
read(char[] cbuf)
代码一:
@Test
public void testFileReader1() {
FileReader fr = null;
try {
//1、File类的实例化
File file = new File("hello.txt");
//2、FileReader流的实例化
fr = new FileReader(file);
//3、读入操作
//read(char[] cbuf) :返回每次读入cbuf数组中的字符的个数,读到末尾返回-1
char[] cbuf = new char[5];
int len;
while((len = fr.read(cbuf)) != -1){
//输出char[]
//_________________________错误写法_____________________________________
for (int c:cbuf){
System.out.print((char) c);
}
//______________________________________________________________________
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4、资源关闭
try {
if (fr != null) {
fr.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
输出一:
Hello world!orl
针对代码一的错误部分修改:
方式一:
for (int i = 0; i < len; i++) {
System.out.print(cbuf[i]);
}
方式二:
//方式二
String str = new String(cbuf,0,len);//将字符数组里的数据变换为字符串,并从头取指定长度的字符串
System.out.print(str);
输出二:
Hello world!
2.1.2.涉及到的几个问题(难点)
出现输出一的原因(图解)
char[] 数组,在几次取数据过程中的变化
2.2 FileWriter
2.2.1 FileWriter写出数据的操作
- 输出操作对应的File可以不存在。并不会报异常
- File对应的硬盘中的文件如果不存在,会在输出过程中,自动创建。
File对应的硬盘中的文件如果存在
>如果使用FileWriter(file,false)/FileWriter(file):对原有文件进行覆盖
>如果使用FileWriter(file,true):不会对原有文件进行覆盖,在原有文件基础上增加内容
写出操作代码:
/*
从内存中写出数据到硬盘的文件里
*/
@Test
public void testFileWriter(){
FileWriter fw = null;
File file = null;
try {
//1、实例化File对象,指明写出的文件
file = new File("hello.txt");
//2、提供FileWriter的对象,用于数据的写出
fw = new FileWriter(file,true);//在原有文件基础是增加内容
//3、写出的操作——写入操
fw.write("I have a dream!\n");
fw.write("Fight for my dream!".toCharArray());
} catch (IOException e) {
e.printStackTrace();
} finally {
//4、关闭流资源
try {
fw.close();
//操作完成后,删除当前文件;注意当流资源没有关闭时,是无法删除的
/* boolean i = file.delete();
if (i){
System.out.println("删除成功!");
}*/
} catch (IOException e) {
e.printStackTrace();
}
}
}
使用FileWriter(file,true)第一次执行情况:
使用FileWriter(file,true)第二次执行情况:
2.3 FileWriter 和FileReader
2.3.1 从hello.txt读入并写出到hello1.txt
@Test
public void testFileWriterFileReader(){
FileReader fr = null;
FileWriter fw = null;
try {
//1、创建File类对象,指明读入和写出的文件
File fileR = new File("hello.txt");//读入文件
File fileW = new File("hello1.txt");//写出文件
//2、提供FileWriter对象,用于File的写出;提供FileReader对象,用于File的读入
fr = new FileReader(fileR);
fw = new FileWriter(fileW,true);
//5、读入:内存---->程序 FileReader:写出:程序---->内存
int readLen ;//每次读到的数据个数
char[] chRead = new char[5];
while((readLen = fr.read(chRead)) != -1){
for (int i = 0; i < readLen; i++) {
System.out.print(chRead[i]);
}
//每次写出readLen个字符
fw.write(chRead,0,readLen);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//6、关闭流
if (fr != null){
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
执行效果
执行前:
执行后:
不能使用字符流来处理图片等字节流数据,要处理就要用FileInputStream和FileOutputStream
2.4 字节流 FileInputStream和FileOutputStream
- 1、对于文本文件(.txt,.java,.c,.cpp),使用字符流进行处理
- 2、对于非文本文件(.jpd,.doc,.ppt,.mp3,.avi…),使用字节流处理
使用FileInputStream处理非文本文件,可能会出现乱码- 3、
对.jpg文件的复制操作
@Test
public void testFileInputStreamFiletOutputStream(){
FileInputStream fips = null;
FileOutputStream fops = null;
try {
//指定要操作的对象文件
File inFile = new File("皮卡丘.jpg");
File outFile = new File("皮卡丘副本.jpg");
//提供FileInputStream对象,用于文件的写出
fips = new FileInputStream(inFile);
fops = new FileOutputStream(outFile,false);
//复制过程
byte[] buffer = new byte[5];
int len;
while((len = fips.read(buffer)) != -1){
for (int i = 0; i < len; i++) {
System.out.print(buffer[i]);
}
fops.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流
if (fips != null) {
try {
fips.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fops != null ) {
try {
fops.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}