IO
- input:读入,将磁盘上的数据读取到内存中
- output:写出,将内存中的数据写到磁盘
- 内存:软件执行的空间。速度快,造价高
- 磁盘中:可以永久保存数据,存放数据、文件、文件夹。空间大,速度慢
IO流
- 流:数据流。内存流向磁盘
- I:输入流:将磁盘数据以流的形式读取到内存
- O:输出流:将内存中的数据以流的形式写入磁盘中。
路径
- 绝对路径:完整的路径,从盘符开始,到具体的文件或者文件夹的路径
- 相对路径:相对于当前路径的路径。以当前路径为基础。目标文件路径
- 退出当前路径…/。当前路径./;
File
- 文件:java中表示文件或者文件夹的类,在java中,将文件或者文件夹作为一个File类的对象
- 操作这个FIle对象,你在操作这个文件
- 这个类是独立于系统的。无论你的电脑是win或者Mac,脱离与系统的。
静态属性
- pathSeparator:系统默认的路径分隔符,是一个封号,字符串表示,在Unix上是冒号表示
- pathSeparatorChar:系统默认的路径分隔符,是一个封号,字符表示
- separator:系统默认的名称分隔符,是一个反斜杠,字符串表示,在Unix是正斜杠
- separatorChar:系统默认的名称分隔符,是一个反斜杠,字符表示
构造方法
@Test
public void test03() {
//接受一个字符串对象,表示文件或者文件夹的路径名,可以抽象出一个File对象
File parent = new File("f:\\Python");
//接受一个file对象,和一个字符串的文件名,组合成一个完整的路径
File file = new File(parent,"pro01");
System.out.println(file.getAbsolutePath());
//接受两个字符串的路径,第一个是父路径,第二个是子路径
File file1 = new File("f:\\Python","pro02");
System.out.println(file1.getAbsolutePath());
}
- 构造中的路径可以是不存在的。路径存在的情况下,文件或者文件夹可以是不存在的
- 盘符不存在的情况,如果操作方法会报错
- 路径存在,文件或者文件夹不存在,操作没有问题的
常用方法
- 新建的方法
- createNewFile():新建一个文件。
- mkdir():新建一个文件夹,单级
- mkdirs():新建一个文件夹,多级
- 查看的方法
- canRead():查看文件或文件夹是否可读
- canWrite():查看文件是否可写
- exists():查看文件或文件夹是否存在
- getAbsoulutePath():返回file对象的绝对地址
- getPath():返回构造中的路径
- getName():返回路径的后缀名称
- getparentFile():返回父路径的File对象
- getParent():返回父路径的字符串表示
- isFile():查看是否是一个文件
- siDirectory():查看是否是一个文件夹
- length():返回文件的大小
- list():
- listFile():
- 删除的方法
- delete():可以删除文件或者文件夹,只能删除文件或者空文件夹
- 修改的方法
- setReadable():修改可写
- setWritable():修改可读
- setReadOnly():修改只读
@Test
public void test04() {
File file = new File("f:\\fileDemo");
//不管路径存在与否,只看属性,判断文件是否可读
//如果路径不存也是false
System.out.println(file.canRead());
//判断是否是可执行文件
System.out.println(file.canExecute());
//判断文件是否可写
System.out.println(file.canWrite());
//判断文件名字的字符串的大小
file.compareTo(new File("u:\\fileDemo"));
//根据你给定的路径创建文件,如果该文件不存在,如果路径不存在,报错
try {
boolean newFile = file.createNewFile();
System.out.println("newFile = " + newFile);
} catch (IOException e) {
e.printStackTrace();
}
//删除文件,无论文件是否为空,直接删除,不走回收站
boolean delete = file.delete();
System.out.println("delete = " + delete);
//如果file对象是一个文件夹,只能删除空的。如果文件夹有东西。不能删除的
boolean delete1 = new File("F:\\testdelete").delete();
System.out.println("delete1 = " + delete1);
//判断你路径表示的文件或者文件夹是否存在
boolean exists = file.exists();
System.out.println("exists = " + exists);
//返回file对象表示的绝对路径
String absolutePath = file.getAbsolutePath();
System.out.println("absolutePath = " + absolutePath);
try {
//返回绝对路径,可以单击直接打开路径表示的文件或者文件夹
String canonicalPath = file.getCanonicalPath();
System.out.println("canonicalPath = " + canonicalPath);
} catch (IOException e) {
e.printStackTrace();
}
//返回构造中给的路径名称
String name = file.getName();
System.out.println("name = " + name);
//返回路径,跟构造中一样,与File类的toString方法一样的
String path = file.getPath();
System.out.println("path = " + path);
//返回父路径的File对象
File parentFile = file.getParentFile();
System.out.println("parentFile = " + parentFile);
//返回父路径的字符串表示的路径
String parent = file.getParent();
System.out.println("parent = " + parent);
//判断file对象表示的是否是一个文件夹
boolean directory = file.isDirectory();
System.out.println("directory = " + directory);
//判断file对象表示的是否是一个文件
boolean file1 = file.isFile();
System.out.println("file1 = " + file1);
//判断是否是隐藏文件
boolean hidden = file.isHidden();
//返回最后一次修改的时间距离1990年的毫秒值
long l = file.lastModified();
//返回文件的大小,文件夹没有大小的,返回的是字节数
long length = file.length();
System.out.println("length = " + length);
//创建文件夹,如果文件夹不存在。路径没有的话报错,只能创建一级目录
boolean mkdir = file.mkdir();
System.out.println("mkdir = " + mkdir);
//创建新的文件夹,可以创建多级目录
file.mkdirs();
//文件重命名,移动文件,如果路径相同,就是重名名,如果路径不同,就复制文件
//file.renameTo(new File(""));
//修改可读属性
file.setReadable(true);
//修改可写属性
file.setWritable(true);
//只读,修改文件属性为只读
file.setReadOnly();
}
@Test
public void test05() throws IOException {
File file = new File("f:\\XDjob");
//返回file下的所有的文件或者文件夹的名称,在数组中
String[] list = file.list();
for (String s : list) {
System.out.println("s = " + s);
}
System.out.println("*************************");
//返回file下的所有的文件或者文件夹的file对象,在数组中
File[] files = file.listFiles();
for (File file1 : files) {
System.out.println("file1 = " + file1);
}
}
文件过滤器
-
过滤特定文件或文件夹
-
FileFiter:一个参数,File类型的
public void test07(File file) { if (file.isFile()) { if (file.getAbsolutePath().endsWith(".md")) { System.out.println(file); } return; } File[] files = file.listFiles(new FileFilter() { @Override public boolean accept(File pathname) { if (pathname.isDirectory()||pathname.getAbsolutePath().endsWith(".md")) { return true; } return false; } }); for (File file1 : files) { if (file1.isFile()) { System.out.println(file1); } else { test07(file1); } } } File[] files = file.listFiles(f->{ if (f.isDirectory()||f.getAbsolutePath().endsWith(".md")) { return true; } return false; });
-
FileNameFilter():两个参数,File dir,String name;dir父路径,name,文件或者文件夹名称
public void test07(File file) { if (file.isFile()) { if (file.getAbsolutePath().endsWith(".md")) { System.out.println(file); } return; } File[] files = file.listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String name) { if (new File(dir,name).isDirectory()||name.endsWith(".md")) { return true; } return false; } }); for (File file1 : files) { if (file1.isFile()) { System.out.println(file1); } else { test07(file1); } } }
-
list()中只能用第二个
-
listFiles()中两个过滤器都可以使用
递归
-
语法:方法在内部调用自己。
-
好处:可以将复杂的n阶问题,简化成一或二阶问题
-
理论上所有的循环都可以写成递归
-
所有的递归都要有一个出口
-
构造方法不能用递归
-
注意
- 递归是很容易出错的。尽量少用
- 即使递归没有错的,运行依然可能报错
-
求1+2+。。。n的和
-
等于n+(n-1的和)
-
n-1+(n-2的和)
public int add2(int n) { if (n==1) { return 1; } return n+add2(n-1); }
-
-
直接递归
-
间接递归
-
用递归求n的阶乘
-
递归遍历文件夹
public void test02(){ out(new File("G:/project")); } public void out(File file){ if(file.isFile()){ System.out.println(file); return; } File[] files = file.listFiles(); for (File file1 : files) { if (file1.isFile()) { System.out.println(file1); } else { out(file1); } } }
递归遍历删除文件夹
@Test public void test01(){ boolean deletes = deletes(new File("G:\\线下")); System.out.println("deletes = " + deletes); } public boolean deletes(File file){ if(file.isFile()){ file.delete(); return true; } File[] files = file.listFiles(); for (File file1 : files) { if(file1 != null){ if(file1.isFile()){ file1.delete(); }else{ deletes(file1); } } } file.delete(); // 删除剩余空文件 return true; }
IO流框架
- I:从其他设备到内存
- O:从内存到其他设备
- 流的分类
- 按照流向分:
- 输入流:从其他设备指向内存的。读入
- 输出流:从内存指向其他设备。写出
- 按照流的单位分:
- 字节流:流操作的基本数据单位是字节
- 字符流:流操作的基本数据单位是字符
- 按照功能分:
- 节点流:流的父类/接口
- 功能流:具体的子类/实现类
- 按照流向分:
字节流
- 字节输入流:inputStream、以字节为单位的输入流
@Test
public void test07() {
InputStream input = null;
try {
input = new FileInputStream("F:\\demo.txt");
int tem;
while ((tem = input.read())!=-1) {
System.out.println(tem);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (input!=null) {
input.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Test
public void test08() {
try {
InputStream input = new FileInputStream("F:\\demo.txt");
byte[] arr = new byte[10];
int tem;
while ((tem = input.read(arr))!=-1) {
System.out.println(new String(arr,0,tem));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
try (InputStream input = new FileInputStream("F:\\demo.txt")){
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
-
字节输出流:outputStream、以字节为单位的输出流
- 如果文件不存在,新建文件。如果路径不存在,报错
- 如果文件存在呢。清空文件,然后再写入。
@Test
public void test10() {
try {
OutputStream stream = new FileOutputStream("F:\\abcdef.txt");
stream.write(97);
byte[] arr = {98,99,0,0};
stream.write(arr);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 电脑保存的数据就是字节形式的0和1,字节流就是一个字节一个字节的操作。字节流是万能的。多用于多媒体数据传输
- 字节流复制图片
//复制图片
@Test
public void test05(){
InputStream input = null;
OutputStream out = null;
try {
input = new FileInputStream("F:\\图片\\_20201010181131.jpg");
out = new FileOutputStream("G:\\图片.jpg");
byte [] arr = new byte[1024*1024];
int temp;
while((temp = input.read(arr)) != -1){
out.write(arr,0,temp);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if(input != null){
input.close();
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 字节流复制文件夹
// 文件夹的复制
@Test
public void test23(){
try {
copyFile(new File("D:\\线下"),new File("G:\\线下"));
System.out.println("成功");
} catch (IOException e) {
e.printStackTrace();
}
}
public void copyFile(File file,File fileNew) throws IOException {
fileNew.mkdirs();
if(file != null){
File[] files = file.listFiles();
if(files != null){
for (File file1 : files) {
if(file1.isFile()){
InputStream inputStream = new FileInputStream(file1);
OutputStream outputStream = new FileOutputStream(fileNew.getAbsolutePath()
+ "\\" + file1.getName());
byte [] bytes = new byte[1024*1024];
int len =0;
while((len = inputStream.read(bytes)) != -1){
outputStream.write(bytes,0,len);
}
inputStream.close();
outputStream.close();
}else {
copyFile(file1,new File(fileNew.getAbsolutePath()
+ "\\" + file1.getName()));
}
}
}
}
- 构造中可以设置是否追加
- \nLinux上的换行
- \r\nwin上的换行
- \rMac上的换行
字符流
-
字符输入流:Read,以字符为单位的输入流
-
字符输出流:Write、以字符为单位的输出流
-
能够用字符表示的。一般都是文本文件文本数据。相比字节速度更快
@Test
public void test12() {
Reader reader = null;
Writer writer = null;
try {
reader = new FileReader("F:\\cde.txt");
writer = new FileWriter("F:\\def.txt");
char[] arr = new char[3];
int len;
while ((len=reader.read(arr))!=-1) {
writer.write(arr,0,len);
}
int read = reader.read();
System.out.println(read);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
字符流复制文件
//字符复制文本文件
@Test
public void test06(){
Reader reader = null;
Writer writer = null;
try {
reader = new FileReader("F:\\一故事一设计模式-LieBrother(完整版).pdf");
writer = new FileWriter("G:\\设计模式.pdf");
char [] chars = new char[10];
int temp;
while((temp = reader.read(chars)) != -1){
writer.write(chars,0,temp);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
reader.close();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
字节流与字符流的不同
- 字节流任意数据都可以,字符流只能操作文本类型
- 默认的读取或者写入字节流是一个字节,字符流一个字符
- 手动给一个数组缓冲。字节流接受的是字节数组,字符流接受的字符数组或者字符串
- 字节数组一般不需要手动刷新,字符流,一般都是要刷新的,关闭流的时候都会自动刷新