Java常用工具-IO流
1. 异常概述
什么是异常?
即非正常情况,通俗地说,异常就是程序出现的错误
异常的分类(Throwable)
- 异常(Exception)
合理的应用程序可能需要捕获的问题
举例:NullPointerException - 错误(Error)
合理的应用程序不应该试图捕获的问题
举例:StackOverFlowError
2. 异常的处理方式
JVM默认的异常处理方式
在控制台打印错误信息,并终止程序
开发中异常的处理方式
- try…catch(finally):捕获,自己处理
- throws:抛出,交给调用者处理
try…catch
代码演示
/*
方式一:try catch
特点:
处理完异常之后,程序会继续执行
执行流程:
先执行try()中的内容,看是否有问题(异常)
没有:直接执行finally语句中的内容
有:跳转到catch()语句中开始执行,再执行finally
方式二:throws
*/
public class Test {
public static void main(String[] args) {
//通过try. catch .finally来处理异常
try {
//尝试要执行的代码
int a = 10 / 0;
System.out.println("a:" + a);
return;
} catch (Exception e) {
//出现问题后的代码(解决方案)
System.out.println("被除数不能为0");
return;
}finally { //即使try,catch中有return,finally里边的代码也会执行
System.out.println("看看我执行了吗?");
}
//System.out.println("看看我执行了吗?");
}
}
运行结果
throws
代码演示
/*
异常处理方式二:throws
抛出异常,交给调用者处理
特点:
执行结束后,程序不再继续执行
*/
public class Test {
public static void main(String[] args) throws Exception{
//需求:调用show()
//因为show()方法已经抛出了一个异常,作为调用者(main函数)必须处理这个异常.
//方案一:接着抛
//show();
//方案二:采用try catch处理
try {
show();
}catch (Exception e) {
System.out.println("代码出问题啦!");
}
System.out.println("看看我执行了吗");
}
//定义一个方法
public static void show() throws Exception{
int a = 10 / 0;
System.out.println("a:" + a);
}
}
运行结果
3. IO流概述
什么是IO流?
I/O,即输入(Input)输出(Output),IO流指的是数据像连绵的流体一样进行传输。
IO流能干什么?
在本地磁盘和网络上操作数据
IO流的分类
- 按数据流向分:
输入流
输出流 - 按操作方式分:
字节流:
InputStream
OutputStream
字符流
Reader
Writer
IO流体系
- 字符流:按字符读写数据的IO流
Reader
FileReader
BufferedReader
Writer
FileWriter
BufferedWriter - 字节流:按字节读写数据的IO流
InputStream
FileInputStream
BufferedInputStream
OutputStream
FileOutputStream
BufferedOutputStream
4. File类
概念
文件,文件夹,一个File对象代表磁盘上的某个文件或文件夹
- 构造方法:
File(String pathname)
File(String parent,String child)
File(File parent,String child) - 成员方法:
createNewFile():创建文件
mkdir()和mkdirs():创建目录
isDirectory():判断File对象是否为目录
isFile():判断File对象是否为文件
exists():判断File对象是否存在
getAbsolutePath():获取绝对路径
绝对路径:以盘符开头的路径
例如:D:/1.txt
getPath():获取文件的相对路径
相对路径:一般是相对于当前项目路径来讲的
例如:1.txt
getName():获取文件名
list():获取指定目录下所有文件(夹)名称数组
listFiles():获取指定目录下所有文件(夹)File数组
5. 字符流读写文件
字符流读取数据-按单个字符读取
代码演示
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public class ReaderDemo1 {
public static void main(String[] args) throws IOException {
//需求:通过字符流读取数据
//1. 创建字符输入流对象
Reader reader = new FileReader("lib/1.txt");
//2. 读取数据
/*int ch1 = reader.read();
System.out.println(ch1); //97
int ch2 = reader.read();
System.out.println(ch2); //98
int ch3 = reader.read();
System.out.println(ch3); //99
int ch4 = reader.read();
System.out.println(ch4); //-1*/
/*
优化上述的读法,用循环改进
又因为不知道循环次数,所以用while循环
*/
//定义变量,用来接收读取到的字符
int ch;
/*
(ch = reader.read()) != -1 做了三件事
1. 执行了reader.read(),去文件中读取一个字符
2. 执行ch = reader.read(),将读取到的字符赋值给变量
3. (ch = reader.read()) != -1,用读取到的字符(内容)和-1进行比较
*/
while ((ch = reader.read()) != -1) {
//ch = reader.read();
System.out.println(ch);
}
//3. 释放资源
reader.close();
}
}
1.txt里面的内容
abc
运行结果
字符流读取数据-按字符数组读取
代码演示
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public class ReaderDemo2 {
public static void main(String[] args) throws IOException {
//需求:通过字符流读取数据,一次读取一个字符数组
//1. 创建字符输入流对象
Reader reader = new FileReader("lib/2.txt");
//2. 读取数据
/*char[] chs = new char[3];
int len1 = reader.read(chs);
System.out.println(chs); //abc
System.out.println(len1); //3
int len2 = reader.read(chs);
System.out.println(chs); //def
System.out.println(len2); //3
int len3 = reader.read(chs);
System.out.println(chs); //gef
System.out.println(len3); //1
int len4 = reader.read(chs);
System.out.println(chs); //gef
System.out.println(len4); //-1*/
/*
优化上述的代码,while循环
*/
//定义字符数组
char[] chs = new char[3];
//定义一个变量,记录读取到的有效字符数
int len;
while ((len = reader.read(chs)) != -1) {
//将读取到的内容,转换成字符串,然后打印
/*
chs:表示要操作的数组
0:表示起始索引
len:表示要操作的字符的个数
*/
String s = new String(chs,0,len); //[g,e,f] len = 1 只读取g 如果不写0,len 那么读取的就是gef
System.out.println(s);
}
//3. 释放资源
reader.close();
}
}
2.txt里面的内容
abcdefg
运行结果
字符流写数据-按单个字符写入
代码演示
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class WriterDemo {
public static void main(String[] args) throws IOException {
//需求:通过字符流,写数据
//1. 创建字符输出流对象
Writer writer = new FileWriter("lib/1.txt");
//2. 写数据
//一次写一个字符
writer.write('好'); //原来的文件里面的abc被好覆盖
//3. 释放资源
writer.close();
}
}
运行结果
字符流写数据-按字符数组写入![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/bbff63ed45c489574b029f62725b4eca.jpeg)
代码演示
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class WriterDemo {
public static void main(String[] args) throws IOException {
//需求:通过字符流,写数据
//1. 创建字符输出流对象
Writer writer = new FileWriter("lib/1.txt");
//2. 写数据
//一次写一个指定的字符数组
char[] chs = {'新','年','快','乐','呀'};
writer.write(chs,2,3);
//3. 释放资源
writer.close();
}
}
运行结果
字符流写数据-按字符串写入
代码演示
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class WriterDemo {
public static void main(String[] args) throws IOException {
//需求:通过字符流,写数据
//1. 创建字符输出流对象
Writer writer = new FileWriter("lib/1.txt");
//2. 写数据
//一次写一个字符串
writer.write("好好学习,天天向上");
//3. 释放资源
writer.close();
}
}
运行结果
字符流拷贝文件-按单个字符读写
代码演示
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
public class CopyFile1 {
public static void main(String[] args) throws IOException {
//需求:通过字符流拷贝文件,一次读写一个字符
//例如:将1.txt文件中的内容复制到2.txt文件中
/*
IO流拷贝文件核心6步:
1. 创建字符输入流对象,关联数据源文件
2. 创建字符输出流对象,关联目的地文件
3. 定义变量,记录读取到的内容
4. 循环读取,只要条件满足就一直读,并将读取到的内容赋值给变量
5. 将读取到的数据写入到 目的地文件中
6. 释放资源
*/
//1
//Reader reader = new FileReader("lib/1.txt");
FileReader fr = new FileReader("lib/1.txt");
//2
FileWriter fw = new FileWriter("lib/3.txt"); //细节:如果目的地文件不存在,程序会自动创建
//3
int len;
//4
while ((len = fr.read()) != -1) {
//5
fw.write(len);
}
//6
fr.close();
fw.close();
}
}
运行结果
字符流拷贝文件-按字符数组读写
代码演示
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class CopyFile2 {
public static void main(String[] args) throws IOException {
//需求:通过字符流拷贝文件,一次读写一个字符数组
//例如:将1.txt文件中的内容复制到2.txt文件中
/*
IO流核心6步
1. 创建字符输入流对象,关联数据源文件
2. 创建字符输出流对象,关联目的地文件
3. 创建变量,用来记录读取到的有效字符数
4. 通过循环进行读取,只要条件满足就一直读,并将读取到的有效字符数赋值给变量
5. 将读取到的数据写入到目的地文件中
6. 释放资源
*/
//1
FileReader fr = new FileReader("lib/1.txt");
//2
FileWriter fw = new FileWriter("lib/2.txt");
//3
//定义一个字符数组
char[] chs = new char[1024];
//用来记录读取到的有效字符数
int len;
//4
while ((len = fr.read(chs)) != -1) {
//
fw.write(chs,0,len);
}
//6
fr.close();
fw.close();
}
}
运行结果
字符缓冲流拷贝文件的标准代码
Demo1
代码演示
import java.io.*;
/*
特点:
字符缓冲流自带有缓冲区,大小为8192个字符,也就是16KB
*/
public class CopyFile1 {
public static void main(String[] args) throws IOException {
//需求:通过字符缓冲流将1.txt文件中的内容拷贝到2.txt文件中。
//1. 创建字符缓冲输入流对象,关联数据源文件
//1.1 创建普通的字符输入流对象
FileReader fr = new FileReader("lib/1.txt");
//1.2 创建字符缓冲输入流对象
BufferedReader br = new BufferedReader(fr);
//简化上述的代码
//BufferedReader br2 = new BufferedReader(new FileReader("lib/1.txt"));
//2. 创建字符缓冲输出流对象,关联目的地文件
//2.1 创建普通的字符输出流对象
FileWriter fw = new FileWriter("lib/2.txt");
//2.2 创建字符缓冲输出流对象
BufferedWriter bw = new BufferedWriter(fw);
//3. 定义变量,记录读取到的数据
int len;
//4. 循环读取,只要条件满足就一直读,并将读取到的内容赋值给变量
while ((len = br.read()) != -1) {
//5. 将读取到的数据写入到目的地文件中
fw.write(len);
}
//6. 释放资源
br.close();
bw.close();
}
}
运行结果
Demo2
代码演示
/*
字符缓冲流用法:
分类:
BufferedReader:字符缓冲输入流(也叫高效字符输入流)
成员方法:
public String readLine(); 一次读取一行数据并返回读取到的内容,读不到就返回null;
BufferedWriter:字符缓冲输出流(也叫高效字符输出流)
成员方法:
public void newLine(); 根据当前操作系统锅给对应的换行符
windows操作系统: \r\n
mac操作系统: \r
unix操作系统: \n
特点:字符缓冲流自带有缓冲区,大小为8192个字符,也就是16KB
注意:字符流只能拷贝纯文本文件
*/
import java.io.*;
public class CopyFile2 {
public static void main(String[] args) throws IOException {
//需求:通过字符缓冲流“一次读写一行”的方式,将1.txt文件中的内容拷贝到2.txt文件中
//1. 创建字符缓冲输入流对象,关联数据源文件
//FileReader fr = new FileReader("lib/1.txt");
//BufferedReader br = new BufferedReader(fr);
//合并版
BufferedReader br = new BufferedReader(new FileReader("lib/1.txt"));
//2. 创建字符缓冲输出流对象,关联目的地文件
BufferedWriter bw = new BufferedWriter(new FileWriter("lib/2.txt"));
//3. 定义变量,记录读取到的内容
String str;
//4. 循环读取,只要条件满足就一直读,并将读取到的内容赋值给变量
while ((str = br.readLine()) != null) {
//5. 将读取到的内容写入到目的地文件中
bw.write(str);
//千万注意一个小细节,你特别容易忽略
//千万别忘记换行
//bw.write("\r\n");
bw.newLine();
}
//6. 释放资源
br.close();
bw.close();
}
}
运行结果
6. 字节流读写文件
字节流拷贝文件 - 按单个字节读写
代码演示
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyFile1 {
public static void main(String[] args) throws IOException {
//需求:通过普通的字节流,一次读写一个字节的方式,将a.jpg复制到b.jpg中
//1. 创建字节输入流,关联数据源文件
FileInputStream fis = new FileInputStream("lib/a.jpg");
//2. 创建字节输出流,关联目的地文件
FileOutputStream fos = new FileOutputStream("lib/b.jpg");
//3. 定义变量,用来记录读取到的内容
int len;
//4. 循环读取,只要条件满足就一直读,并将读取到的内容赋值给变量
while ((len = fis.read()) != -1) {
//5. 将读取到的内容写入到目的地文件中
fos.write(len);
}
//6. 释放资源
fis.close();
fos.close();
}
}
运行结果
字节流拷贝文件 - 按字节数组读写
代码演示
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyFile2 {
public static void main(String[] args) throws IOException {
//需求:通过普通字节流一次读写一个字节数组的方式,将a.jpg复制到c.jpg中
//1. 创建字节输入流,关联数据源文件
FileInputStream fis = new FileInputStream("lib/a.jpg");
//2. 创建字节输出流,关联目的地文件
FileOutputStream fos = new FileOutputStream("lib/c.jpg");
//3. 定义变量,用来接收读取到的内容
byte[] bys = new byte[1024];
//用来记录读取到的有效字节数
int len;
//4. 循环读取,只要条件满足就一直读,并将读取到的内容(有效的字节数)赋值给变量
while ((len = fis.read()) != -1) {
//5. 将读取到的数据写入到目的地文件中
fos.write(bys,0,len);
}
//6. 释放资源
fis.close();
fos.close();
}
}
运行结果
字节缓冲流拷贝文件的标准代码
代码演示
import java.io.*;
/*
特点:
字节缓冲流有自己的缓冲区,大小为8192个字节,也就是8KB
总计:
拷贝纯文本文件使用字符流,拷贝其他(图片、音频、视频等)使用字节流
*/
public class CopyFile1 {
public static void main(String[] args) throws IOException {
//需求:通过字节缓冲流,将a.jpg复制到d.jpg中
//1. 创建字节输入流对象,关联数据源文件
//创建普通的字节输入流
//FileInputStream fis = new FileInputStream("lib/a.jpg");
//创建高效的字节输入流
//BufferedInputStream bis = new BufferedInputStream(fis);
//合并版
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("lib/a.jpg"));
//2. 创建字节输出流对象,关联目的地文件
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("lib/d.jpg"));
//3. 定义变量,用来记录读取到的内容
int len;
//4. 循环读取,只要条件满足就一直读,然后读取到的内容赋值给变量
while ((len = bis.read()) != -1) {
//5. 将读取到的内容写入到目的地文件中
bos.write(len);
}
//6. 释放资源
bis.close();
bos.close();
}
}
运行结果
案例:模拟文件上传功能
代码演示
import java.io.*;
import java.util.Scanner;
public class UpdateFile {
public static void main(String[] args) throws IOException {
//需求:模拟用户上传头像的功能,假设所有的用户头像都应上传到:项目下的lib文件夹中
//1. 定义一个方法,用来获取要上传的用户头像的路径: getPath();
File path = getPath();
System.out.println(path); //C:\Users\hp\Desktop\1\psc.jpg
//2. 定义一个方法,用来判断要上传的用户头像,在lib文件夹中是否存在
boolean flag = isExists(path.getName());
//3. 如果存在,提示:该用户头像已经存在,上传失败
if (flag) {
System.out.println("该用户头像已经存在,上传失败");
} else {
//4. 如果不存在,就上传该用户头像,并提示上传成功
//System.out.println("我马上要上传了,代码等下写");
//数据源文件 目的地文件
//e:/picture/psc.jpg -> lib/psc.jpg
uploadFile(path);
}
}
//1.定义一个方法,用来获取要上传的用户头像的路径:getPath();
/**
* 用来获取要上传的用户头像的路径
* @return 具体要上传的用户头像的路径
*/
public static File getPath() {
//1. 提示用户录入要上传的用户头像路径,并接收
Scanner sc = new Scanner(System.in);
//7. 因为不知道用户多少次能录入正确,所以用while(ture)改进
while (true) {
System.out.println("请录入您要上传的用户头像的路径:");
String path = sc.nextLine();
//2. 判断该路径的后缀名是否是: .jpg .png .bmp
//3. 如果不是,就提示:您录入的不是图片,请重新录入
if (!path.endsWith(".jpg") && !path.endsWith(".png") && !path.endsWith(".bmp")) {
System.out.println("您录入的不是图片,请重新录入");
//细节,千万注意,别忘了写
continue;
}
//4. 如果是,程序接着执行,判断该路径是否存在,并且是否是文件
File file = new File(path);
if (file.exists() && file.isFile()) {
//6. 如果是,说明就是我们想要的数据(图片,文件),直接返回
return file;
} else {
//5. 如果不是,就提示:您录入的路径不合法,请重新录入
System.out.println("您录入的路径不合法,请重新录入");
}
}
}
//2. 定义一个方法,用来判断要上传的用户头像,在lib文件夹中是否存在
public static boolean isExists(String path) {
//1. 将lib文件夹封装成File对象
File file = new File("lib");
//2. 获取lib文件夹中所有的文件(夹)的名称数组
String[] names = file.list();
//3. 遍历第二步获取到的数组,用获取到的数据依次和path进行比较
for (String name : names) {
if (name.equals(path)) {
//4. 如果一致,说明该用户头像已经存在了,就返回true
return true;
}
}
//5. 如果不一致,说明该用户头像不存在,就返回false
return false;
}
//4. 定义方法,用来上传具体的用户头像
/**
* 用来上传具体的用户头像
* @param path 数据源文件路径
*/
public static void uploadFile(File path) throws IOException {
//1. 创建字节输入流,关联数据源文件
//FileInputStream类中的构造方法
// public FileInputStream(File file)
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(path)); //path: e:/picture/psc.jpg
//2. 创建字节输出流,关联目的地文件
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("lib/" + path.getName())); // lib/psc.jpg
//3. 定义变量,记录读取到的数据
int len;
//4. 循环读取,只要条件满足就一直读,并将读取到的数据赋值给变量
while ((len = bis.read()) != -1) {
//5. 将读取到的数据写入到目的地文件中
bos.write(len);
}
//6. 释放资源
bis.close();
bos.close();
System.out.println("上传成功");
}
}
运行结果