File类:
写在学习之前,在之前我们操作系统中的文件都是通过可视化界面,接下来关于IO学习中的示例,是使用代码去针对文件进行操作
File类构造函数
API
File(String pathname)
根据一个路径得到File对象
File(String parent, String child)
根据一个目录和一个子文件/目录得到File对象
File(File parent, String child)
根据一个父File对象和一个子文件/目录得到File对象
代码示例
需求:创建一个File类型对象,路径分为相对路径和绝对路径,判断该对象对应的文件/路径在电脑中是否存在
exists()用于判断File对象是否存在
File f1 = new File(相对路径/绝对路径);
System.out.println(f1.exists());
File f2 = new File(父路径,子路径/文件名);
System.out.println(f2.exists());
File f3 = new File(File类型对象,子路径/文件名);
System.out.println(f3.exists());
课程小结
1. File类型对象的创建有几种方式?
File类的创建功能
API
boolean mkdir()
创建文件夹,如果存在这样的文件夹,就不创建了,路径不存在返回flase
boolean mkdirs()
创建文件夹,如果父文件夹不存在,会帮你创建出来
boolean createNewFile()
创建文件,路径不存在抛出异常,如果存在这样的文件,就不创建了
代码示例
注意事项:若创建文件或者文件夹忘了写盘符路径,那么默认在项目路径下
需求:指定路径的File对象,mkdir创建文件夹,路径存在和路径不存在
需求:指定路径的File对象,mkdirs创建文件夹,路径存在和路径不存在
需求:指定路径的File对象,createNewFile创建文件,路径存在和路径不存在
课程小结
1. 单级文件夹创建和多级文件夹创建
2. 创建文件的操作
File类的获取功能
API
String getAbsolutePath()
获取文件的绝对路径
File getAbsoluteFile()
获取文件的绝对路径
String getPath()
获取文件的相对路径
String getName()
获取名称
String[] list()
获取指定目录下的所有文件或者文件夹的名称数组
File[] listFiles()
获取指定目录下的所有文件或者文件夹的File数组
File[] listRoots()
获取电脑中的盘符
String[] list (FilenameFilter filter)
获取指定目录下被FilenameFilter筛选后的文件,返回String类型数组
注意:FilenameFilter实现类中的accept(File file,String name)中两个参数,第一个参数为File对象可以表示为一个路径,第二个参数为该路径下的文件名
File[] list (FilenameFilter filter)
获取指定目录下被FilenameFilter筛选后的文件,返回String类型数组
File[] listFiles (FileFilter filter)
获取指定目录下被FileFilter筛选后的文件,返回File类型数组
注意:FileFilter实现类中的accept(File file)只有一个参数,该参数指代的是一个文件的路径,和FilenameFilter中的区别在于,FilenameFilter中两个参数合在一起才能指定一个文件,而FileFilter则没有将路径和文件名分开,通过观察两个接口的名称也能看出二者的区别
代码示例
思考&讨论:
如果当前只需要显示指定类型的文件,怎么做?画图工具打开指定的文件类型
【练习】自定义文件过滤
File f1 = new File("D:\\work\\STS\\JavaSE-Day23-IO\\2.txt\\aaa");
String suffix="txt";
//3.获取目录中存在的文件列表
String[] list = f1.list();
//4.针对获取到的文件进行一个后缀的判定,符合要求的文件输出
for (String string : list) {
if (string.endsWith(suffix)) {
System.out.println(string);
}
}
【扩展练习】将自定义文件过滤的方法封装为返回类型为String[]的方法
问题:
若直接定义数组返回,需要指定数组的长度,但当前获取的文件是不固定的
解决:
定义集合动态添加最终的值,最后将集合转化为数组
File f1 = new File("D:\\work\\STS\\JavaSE-Day23-IO\\2.txt\\aaa");
String suffix="txt";
//3.获取目录中存在的文件列表
String[] list = f1.list();
//4.针对获取到的文件进行一个后缀的判定,符合要求的文件添加到集合中
ArrayList arrayList = new ArrayList<>();
for (String string : list) {
if (string.endsWith(suffix)) {
//将筛选的值添加到集合中
arrayList.add(string);
}
}
//将集合中的数据转换为数组,数组的长度使用集合的长度
return arrayList.toArray(new String[arrayList.size()]);
【API中的过滤】使用list(FilenameFilter filter)、listFiles(FilenameFilter filter)、listFiles(FileFilter filter)过滤
list(FilenameFilter filter)方法代码演示:
//实现过滤接口FilenameFilter
public class MyFilenameFilter implements FilenameFilter {
@Override
public boolean accept(File dir, String name) {
System.out.println(dir+"======="+name);
return name.endsWith("txt");
}
}
//代码实现
File f1 = new File("D:\\work\\STS\\JavaSE-Day23-IO\\2.txt\\aaa");
//使用自定义的过滤器
String[] list = f1.list(new MyFilenameFilter());
for (String string : list) {
System.out.println(string);
}
list(FileFilter filter)代码演示:
//定义FileFilter实现类
public class MyFileFilter implements FileFilter {
@Override
public boolean accept(File pathname) {
System.out.println("========="+pathname);
return pathname.getName().endsWith("txt");
}
}
//代码实现
File f1 = new File("D:\\work\\STS\\JavaSE-Day23-IO\\2.txt\\aaa");
File[] listFiles = f1.listFiles(new MyFileFilter());
//过滤之后的信息
for (File file : listFiles) {
System.out.println(file);
}
课程小结
1. File类型中获取路径是根据什么形式来获取的?
2. 获取路径中存在的文件,使用的API?
3. 如何显示指定的文件?
File类的判断功能
思考&讨论:
为什么需要存在判断方法?
在IO的所有操作中,大家可以发现针对文件和文件夹的操作是不一样的,最明显的是API都不同
API
boolean exists()
判断路径表示的文件或者文件夹是否存在
boolean isDirectory()
判断当是否是一个文件夹
boolean isFile()
判断当前是否是一个文件
代码示例
【练习】判断当前File类型是否是一个文件夹,isDirectory()
【练习】判断当前File类型是否是一个文件,isFile()
课程小结
1. 判断文件夹使用的API?
2. 判断文件使用的API?
File类的删除功能
API
boolean delete()
若是文件就直接删除,若是文件夹则必须是空文件夹
代码示例
【代码练习】删除文件夹,文件夹中包含子文件
File f1 = new File("D:\\work\\STS\\JavaSE-Day23-IO\\2.txt\\aaa\\bb");
System.out.println(f1.delete());
//删除文件
File f2 = new File(f1,"cc");
System.out.println(f2.delete());
File f3 = new File(f1,"dd.txt");
System.out.println(f3.delete());
【代码练习】优化删除文件夹的代码,使用代码判定是文件夹还是文件
File f1 = new File("D:\\work\\STS\\JavaSE-Day23-IO\\2.txt\\aaa\\bb");
if (f1.isDirectory()) {
//如果File对象是文件夹
File[] listFiles = f3.listFiles();
for (File file : listFiles) {
file.delete();
}
}
// 如果File对象是文件或者是空文件夹就直接删除
F1.delete();
思考&讨论:
删除文件夹的时候,如果文件夹中还有嵌套的子文件夹,那么应该如何删除?
【代码练习】若文件夹中还嵌套的有其他不为空的文件夹呢?
File f1 = new File("D:\\work\\STS\\JavaSE-Day23-IO\\2.txt\\aaa\\bb");
//递归调用
aboutDelete3(f3);
public static void aboutDelete3(File f3) {
if (f3.isDirectory()) {
//如果File对象是文件夹
File[] listFiles = f3.listFiles();
for (File file : listFiles) {
aboutDelete3(file);
}
}
// 如果File对象是文件或者是空文件夹就直接删除
f3.delete();
}
递归
从前有座山,山上有座庙,庙里有个老和尚在给小和尚讲故事:从前有座山,山上有座庙,庙里有个老和尚在给小和尚讲故事:从前有座山,山上有座庙,庙里有个老和尚在给小和尚讲故事:……
递归:本质上就是方法自己调用自己
递归中处理的代码逻辑实质上是一样的,所以可以实现自己调用自己 ,但是递归不能无限制去调用,因为递归调用是无限次调用,而电脑内存是有限的,所以递归的使用需要慎重
代码示例
【演示】main方法自己调自己,出现的异常,截图
【练习】斐波拉契数列,假设有函数f(x)且f(0)=0、f(1)=1,第x个值公式为f(x)=f(x-1)+f(x-2),根据以上给出的条件实现x为任意数时的值的代码实现
public static int f(int x){
if (x == 0) {
return 0;
}else if (x == 1) {
return 1;
}
return f(x-1)+f(x-2);
}
访问文件:
字节输入流【FileInputStream】
字节输入流读取文件的实现步骤:
1. 关联实体文件,创建FileInputStream对象
2. 调用read方法
3. 关闭输入流【close】
API
1. 字节输入流对象,使用构造函数:
FileInputStream(File file)
返回一个字节输入流对象,该对象使用字节流读取文件,参数为File类型关联实体文件
FileInputStream(String name)
返回一个字节输入流对象,传入的name为路径+文件名
2. 使用字节输入流对象读取文件:
字节输入流对象在读取到最终的数据结尾时,返回-1
int read()
单字节读取文件,返回读取的下一次的数据字节数,若下一次读取没有数据则返回为-1
int read(byte[] b)
多字节读取文件,读取指定数组长度的数据字节,若下一次读取没有数据则返回为-1
多字节读取时,使用byte类型的数组作为缓冲区,可能会存在数据重复问题
int read(byte[] b,int off,int len)
多字节读取文件,读取指定数组长度的数据字节,若下一次读取没有数据则返回为-1
参数2和参数3是针对数组缓冲区进行的设置
参数off:从缓冲区数组第几个下标开始读取
参数len:从缓冲区数组中读取指定长度的数据
注意:参数2和参数3相加的值不能大于等于数组的长度,否则会引发下标异常
3. 关闭输入流对象
void close()
关闭输入流对象
代码示例
单个字节读取
FileInputStream inputStream = new FileInputStream(new File
("D:/work/STS/JavaSE-Day24-IO/1.txt"));
//System.out.println(inputStream.read());
//System.out.println((char)inputStream.read());
//循环遍历读取数据
int n;
while ((n=inputStream.read())!=-1) {
System.out.println((char)n);
}
//关闭输入流
inputStream.close();
多个字节读取,采用byte类型数组为缓冲区,若缓冲区不能被数据长度整除则可能造成数据重复输出
FileInputStream inputStream = new FileInputStream
("D:/work/STS/JavaSE-Day24-IO/1.txt");
byte[] b=new byte[4];
//将字节数组打印输出
for (byte c : b) {
System.out.println((char)c);
}
int n;
while ((n=inputStream.read(b))!=-1) {
System.out.println(new String(b));
}
//关闭输入流
inputStream.close();
多个字节读取,解决数据重复问题
FileInputStream inputStream = new FileInputStream
("D:/work/STS/JavaSE-Day24-IO/1.txt");
// 定义读取数据的缓冲区
byte[] b = new byte[4];
//循环读取并输出
int n;
while ((n = inputStream.read(b)) != -1) {
System.out.println(new String(b,0,n));
}
//关闭输入流
inputStream.close();
多个字节读取,对数组缓冲区进行设置
使用read(byte[] b,int off,int len)
参数2和参数3是针对缓冲区进行设置,相加的值不能大于等于数组长度
FileInputStream inputStream = new FileInputStream
("D:/work/STS/JavaSE-Day24-IO/1.txt");
// 定义读取数据的缓冲区
byte[] b = new byte[4];
//循环读取并输出
int n=0;
while ((n = inputStream.read(b,1,2)) != -1) {
System.out.println(new String(b));
}
//关闭输入流
inputStream.close();
课程小结
1.字节流读取文件的实现步骤?
字节输出流【FileOutputStream】
字节流输出数据的代码实现步骤:
1. 关联实体文件,创建输出流对象
2. 调用write方法
3. 关闭输出流
API
1. 字节输出流对象,构造函数:
FileOutputStream(File file)
返回一个字节输出流对象,参数为File类型关联实体文件
FileOutputStream(String name)
返回一个字节输出流对象,参数为String类型,取值为路径+文件名
向文件中设置是否追加数据:
FileOutputStream(File file, boolean append)
返回一个字节输出流对象,参数1File类型关联实体文件,参数2布尔值true代表追加
FileOutputStream(String name, boolean append)
返回一个字节输出流对象,参数1String类型关联实体文件,参数2布尔值true代表追加
2. 字节输出流对象输出数据到指定文件:
注意:
如果输出的路径不存在会抛出异常,如果输出的路径存在而文件不存在则会创建新的文件
如果不需要对输出的文件进行追加效果,那么需要在创建输出流对象的时候添加布尔值
void write(int b)
将指定字节写入文件输出流中
void write(byte[] b)
将指定的byte数组中的数据写入到文件
void write(byte[] b,int off,int len)
将指定byte数组中的数据指定起始位置和长度的数据输出到文件中
3. 关闭字节输出流对象:
void close()
关闭文件输出流
代码示例
注意事项:
如果输出的文件路径不存在,则抛出异常
如果输出的文件不存在,则自动创建新的文件
如果输出流对象没有设置追加,且输出路径和文件是一致的,则会覆盖前次的输出内容
使用FileOutputStream(File file)创建对象输出数据到文件:
FileOutputStream fos = new FileOutputStream
(new File("D:/work/STS/JavaSE-Day24-IO/2.txt"));
fos.write(97); //97 是ASCII码值,文件中写入的是a
fos.close();
使用FileOutputStream(String name)创建对象输出数据到文件:
FileOutputStream fos = new FileOutputStream
("D:/work/STS/JavaSE-Day24-IO/2.txt");
byte[] b="abcdefghijk".getBytes();
fos.write(b); //传入的是一个byte类型的数组
fos.close();
FileOutputStream(File file,boolean append)创建追加输出流对象:
FileOutputStream fos = new FileOutputStream
("D:/work/STS/JavaSE-Day24-IO/2.txt",true);
byte[] b="0123456789".getBytes();
fos.write(b, 2, 6);
fos.close();
FileOutputStream(String name,Boolean append)创建追加输出流对象:
FileOutputStream fos = new FileOutputStream
("D:/work/STS/JavaSE-Day24-IO/2.txt", true);
byte[] b="0123456789".getBytes();
fos.write(b, 2, 2);
fos.close();
课程小结
1. 不存在的路径中是否能将数据输出到文件中?
2. 文件若不存在,是否会自动创建?
字符编码【概述】
电脑上数据最终都是显示为二进制,但在实际生活中我们有很多种语言,比如:中文、英文、日文、韩文等。要将这些不同的文字形式显示在电脑上就出现了不同的编码,简单的讲字符编码就是指此类情况
常见的字符编码:
ASCII编码:
用来表示英文,它使用1个字节表示,其中第一位规定为0,其他7位存储数据,一共可以表示128个字符。
拓展ASCII编码:
用于表示更多的欧洲文字,用8个位存储数据,一共可以表示256个字符
GBK/GB2312/GB18030:
简称国标,表示汉字。GB2312表示简体中文,GBK/GB18030表示繁体中文,其实就是几个不同的版本而已。
Unicode编码:
包含世界上所有的字符,是一个字符集。
UTF-8:
是Unicode字符的实现方式之一,它使用1-4个字符表示一个符号,根据不同的符号而变化字节长度
ISO8859-1:
是单字节编码,向下兼容ASCII,不支持中文!
API
数据在电脑中传递时,本质上是字节,所以本次乱码问题主要讲解中文转字节
String中有对应的方法:
byte[] getBytes()
使用平台的默认字符集将此 String 编码为 byte 序列
byte[] getBytes(Charset charset)
使用指定的字符编码来编码字符串
byte[] getBytes(String charsetName)
使用指定的字符编码来编码字符串
String中有对应的构造方法:
String(byte[] bytes)
通过使用平台的默认字符集解码指定的 byte 数组
String(byte[] bytes, Charset charset)
使用指定的字符集来解码指定的byte数组
String(byte[] bytes, String charsetName)
使用指定的字符集来解码指定的byte数组
代码示例
将字符串使用ISO-8859-1编码,使用UTF-8解码
String res="我是中国人";
byte[] bytes = res.getBytes("ISO-8859-1");
System.out.println(new String(bytes,"UTF-8"));
将字符串使用UTF-8编码,使用UTF-8解码
String res="我是中国人";
byte[] bytes = res.getBytes("UTF-8");
System.out.println(new String(bytes,"UTF-8"));
字符流
字符输入流【FileReader】
字符输入流读取文件的实现步骤:
1. 关联实体文件,创建FileReader对象
2. 调用read方法
3. 关闭输入流【close】
API
1. 字符输入流对象,使用构造函数:
FileReader(File file)
返回一个字符输入流对象,该对象使用字符流读取文件,参数为File类型关联实体文件
FileReader(String name)
返回一个字符输入流对象,传入的name为路径+文件名
2. 使用字符输入流对象读取文件:
字符输入流对象在读取到最终的数据结尾时,返回-1
int read()
单字符读取文件,返回读取的下一次的数据字符数,若下一次读取没有数据则返回为-1
int read(char[] c)
多字符读取文件,读取指定数组长度的数据字符,若下一次读取没有数据则返回为-1
多字符读取时,使用byte类型的数组作为缓冲区,可能会存在数据重复问题
int read(char[] c,int off,int len)
多字符读取文件,读取指定数组长度的数据字符,若下一次读取没有数据则返回为-1
参数2和参数3是针对数组缓冲区进行的设置
参数off:从缓冲区数组第几个下标开始读取
参数len:从缓冲区数组中读取指定长度的数据
注意:参数2和参数3相加的值不能大于等于数组的长度,否则会引发下标异常
3. 关闭输入流对象
void close()
关闭输入流对象
代码示例
单个字符读取
FileReader fr = new FileReader(new File
("D:/work/STS/JavaSE-Day24-IO/1.txt"));
//System.out.println(fr.read());
//循环遍历读取数据
int n;
while ((n=fr.read())!=-1) {
System.out.println((char)n);
}
//关闭输入流
fr.close();
多个字节读取,采用byte类型数组为缓冲区,若缓冲区不能被数据长度整除则可能造成数据重复输出
FileReader fr = new FileReader("D:/work/STS/JavaSE-Day24-IO/1.txt");
char[] c=new char[4];
//将字节数组打印输出
for (char c : b) {
System.out.println((char)c);
}
int n;
while ((n=fr.read(b))!=-1) {
System.out.println(c);
}
//关闭输入流
fr.close();
多个字节读取,对数组缓冲区进行设置
使用read(char[] c,int off,int len)
参数2和参数3是针对缓冲区进行设置,相加的值不能大于等于数组长度
FileReader fr = new FileReader("D:/work/STS/JavaSE-Day24-IO/1.txt");
// 定义读取数据的缓冲区
char[] b = new char[4];
//循环读取并输出
int n=0;
while ((n = fr.read(c,1,2)) != -1) {
System.out.println(c);
}
//关闭输入流
fr.close();
字符输出流【FileWriter】
字符流输出数据的代码实现步骤:
1. 关联实体文件,创建输出流对象
2. 调用write方法
3. 关闭输出流
API
1. 字符输出流对象,构造函数:
FileWriter(File file)
返回一个字符输出流对象,参数为File类型关联实体文件
FileWriter(String name)
返回一个字符输出流对象,参数为String类型,取值为路径+文件名
向文件中设置是否追加数据:
FileWriter(File file, boolean append)
返回一个字符输出流对象,参数1File类型关联实体文件,参数2布尔值true代表追加
FileWriter(String name, boolean append)
返回一个字符输出流对象,参数1String类型关联实体文件,参数2布尔值true代表追加
2. 字符输出流对象输出数据到指定文件:
注意:
如果输出的路径不存在会抛出异常,如果输出的路径存在而文件不存在则会创建新的文件
如果不需要对输出的文件进行追加效果,那么需要在创建输出流对象的时候添加布尔值
void write(int b)
将指定字符写入文件输出流中
void write(char[] c)
将指定的char数组中的数据写入到文件
void write(char[] c,int off,int len)
将指定char数组中的数据指定起始位置和长度的数据输出到文件中
void write(String str)
将字符串输出到指定的文件中
void write(String str,int off,int len)
指定字符串的起始位置和长度,输出到指定的文件中
3. 关闭字节输出流对象:
void close()
关闭文件输出流
代码示例
注意事项:
如果输出的文件路径不存在,则抛出异常
如果输出的文件不存在,则自动创建新的文件
如果输出流对象没有设置追加,且输出路径和文件是一致的,则会覆盖前次的输出内容
使用FileWriter(File file)创建对象输出数据到文件:
FileWriter fw = new FileWriter
(new File("D:/work/STS/JavaSE-Day24-IO/2.txt"));
fw.write(97); //97 是ASCII码值,文件中写入的是a
fw.close();
使用FileWriter(String name)创建对象输出数据到文件:
FileWriter fw = new FileWriter("D:/work/STS/JavaSE-Day24-IO/2.txt");
char[] c={'我','你'};
fw.write(c); //传入的是一个char类型的数组
fw.close();
FileWriter(File file,boolean append)创建追加输出流对象:
FileWriter fw = new FileWriter
(new File("D:/work/STS/JavaSE-Day24-IO/2.txt"),true);
char[] c={'我','你'};
fw.write(c, 0, 1);
fw.close();
FileWriter(String name,Boolean append)创建追加输出流对象:
FileWriter fos = new FileWriter("D:/work/STS/JavaSE-Day24-IO/2.txt", true);
char[] c={'我','你'};
fw.write(c, 0, 1);
fw.close();
直接将字符串输出到文件中
FileWriter fw = new FileWriter("D:/work/STS/JavaSE-Day24-IO/2.txt",true);
fw.write("今晚小树林");
fw.close();
1. 转换流
电脑中任何数据都是以二进制形式存在的,文件被读取显示通过字节流读取然后转换为字符流显示,若需要将数据写入文件中,那么数据最终在文件中写入的是二进制形式,所以可以显示指定二进制流关联文件,字符流转换为字节流
字节流转字符流【InputStreamReader】
字节流转成字符流的步骤:
1. 准备一个字节流
2. 将字节流转成字符流输出
3. 关闭流
API
将字节流转换为字符流,使用InputStreamReader构造函数
InputStreamReader(InputStream in)
将字节流对象包装成一个InputStreamReader对象,默认使用本机字符编码
InputStreamReader(InputStream in,String charset)
将字节流对象包装成一个InputStreamReader对象,使用指定的编码格式
代码示例
先使用字节流读取包含中文的文件并输出
FileInputStream fis = new FileInputStream
("D:/work/STS/JavaSE-Day24-IO/src/cn/itsource/readerandwriter/ReaderAndWriterTest.java");
byte[] b=new byte[4];
int len;
StringBuilder build=new StringBuilder();
while ((len=fis.read(b))!=-1) {
build.append(new String(b));
}
System.out.println(build.toString());
fis.close();
优化字节流读取文件时可能出现的乱码问题
FileInputStream fis = new FileInputStream
("D:/work/STS/JavaSE-Day24-IO/src/cn/itsource/readerandwriter/ReaderAndWriterTest.java");
//将字节流包装为字符流
InputStreamReader isr = new InputStreamReader(fis);
char[] c=new char[4];
int len;
StringBuilder build=new StringBuilder();
while ((len=isr.read(c))!=-1) {
build.append(new String(c));
}
System.out.println(build.toString());
isr.close();
fis.close();
课程小结
1. 如何将字节流包装为字符流?
字符流转字节流【OutputStreamWriter】
字符流转字节流步骤:
1. 准备一个字符流
2. 将字符流转换为字节流
3. 关闭流
API
将字符流转换为字节流
OutputStreamWriter(OutputStream out)
将一个字符流中的数据内容写入到转换为显示指定的字节流对象
OutputStreamWriter(OutputStream out,String charset)
使用指定的编码格式将字符流转换为字节流
代码示例
字符流输出数据到文件中,使用字节流关联文件
FileOutputStream fos = new FileOutputStream
("D:/work/STS/JavaSE-Day24-IO/5.txt"); //字节流关联实体文件
OutputStreamWriter osw = new OutputStreamWriter(fos); //字符流输出
osw.write("输出中文");
osw.close();
fos.close();