第22天 IO
今日内容介绍
File
递归
第1章 File
1.1 IO概述
回想之前写过的程序,数据都是在内存中,一旦程序运行结束,这些数据都没有了,等下次再想使用这些数据,可是已经没有了。那怎么办呢?能不能把运算完的数据都保存下来,下次程序启动的时候,再把这些数据读出来继续使用呢?其实要把数据持久化存储,就需要把内存中的数据存储到内存以外的其他持久化设备(硬盘、光盘、U盘等)上。
当需要把内存中的数据存储到持久化设备上这个动作称为输出(写)Output操作。
当把持久设备上的数据读取到内存中的这个动作称为输入(读)Input操作。
因此我们把这种输入和输出动作称为IO操作。
package cn.itcast.demo;
import java.io.File;
/*
* java.io.File
* 将操作系统中的文件,目录(文件夹),路径,封装成File对象
* 提供方法,操作系统中的内容
* File与系统无关的类
* 文件File
* 目录directory
* 路径path
*/
public class FileDemo {
public static void main(String[] args) {
//File类静态成员变量
//与系统有关的路径的分隔符
//static String pathSeparator 与系统有关的路径分隔符,为了方便,它被表示为一个字符串
String separator = File.pathSeparator;
System.out.println(separator);//是一个分号,目录的分割Linux :
//与系统有关的默认名称分隔符
separator = File.separator;
System.out.println(separator);//向右 \ 目录名称分割Linux /
}
}
简单了解IO是怎么一回事之后,接下来就要进一步做系统了解。
在我们操作系统中,数据都保存在文件中,而文件存放相应的文件夹中。那么Java中是如何描述这些的呢?
1.2 File类的出现
打开API,搜索File类。阅读其描述:File文件和目录路径名的抽象表示形式。即,Java中把文件或者目录(文件夹)都封装成File对象。也就是说如果我们要去操作硬盘上的文件,或者文件夹只要找到File这个类即可。那么我们就要研究研究File这个类中都有那些功能可以操作文件或者文件夹呢?
1.3 File类的构造函数
通过构造方法创建File对象,我们进行演示:
package cn.itcast.demo;
import java.io.File;
/*
* File类的构造方法
* 三种重载形式(都要掌握)
*/
public class FileDemo1 {
public static void main(String[] args) {
function();
System.out.println();
function_1();
System.out.println();
function_2();
}
/*
* File(File parent, String child)
* 根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例
* 传递路径,传递File类型父路径,字符串子路径
* 好处:父路径是File类型,父路径可以直接调用File类方法
*/
public static void function_2(){
File parent = new File("d:");
File file = new File(parent,"eclipse");
System.out.println(file);
}
/*
* File(String parent,String child)
* 传递路径,传递字符串父路径,字符串子路径
* 好处:单独操作父路径和子路径
*/
public static void function_1(){
File file = new File("d:","eclipse");
System.out.println(file);
}
/*
* File(String pathname)
* 传递路径名:可以写到文件夹,可以写到一个文件
* c:\\abc c:\\abc\\Demo.java
* 将路径封装File类型对象
*/
public static void function(){
File file = new File("d:\\eclipse");
System.out.println(file);
}
}
1.4 File类创建文件功能
- A: File类创建文件功能
- a: public boolean createNewFile()
- 创建文件 如果存在这样的文件,就不创建了
- a: public boolean createNewFile()
- B: File类创建目录功能
- b: 创建目录
- public boolean mkdir():创建文件夹 如果存在这样的文件夹,就不创建了
- public boolean mkdirs():创建文件夹,如果父文件夹不存在,会帮你创建出来
- b: 创建目录
- C: File类删除功能
- c: 删除功能
- public boolean delete():删除文件或者文件夹
文件和文件夹的创建删除等
经常上面介绍,我们知道可以通过File获取到文件名称,文件路径(目录)等信息。
接下来演示使用File类创建、删除文件等操作。
- public boolean delete():删除文件或者文件夹
- c: 删除功能
package cn.itcast.demo;
import java.io.File;
import java.io.IOException;
/*
* File类的创建和删除功能
* 文件或者目录
*/
public class FileDemo2 {
public static void main(String[] args) throws IOException {
function_3();
}
/*
* File类的删除功能
* boolean delete() 删除此抽象路径名表示的文件或目录
* 删除的文件或者文件夹,在File构造方法中给出
* 删除成功返回True,删除失败返回false
*
* 删除方法,不走回收站,直接从硬盘中删除
*/
public static void function_3(){
//删除文件夹(小心如果文件夹里面还要小文件夹,直接写文件最外面名,貌似删除不掉,得写全了,才行)
File file = new File("d:\\abc");
boolean b = file.delete();
System.out.println(b);
}
/*
* File创建文件夹功能
* boolean mkdir()
* 创建此抽象路径名指定的目录
* 创建的路径也在File构造方法中给出
* 文件夹已经存在,不在创建
*
* 推荐使用mkdirs:可以同时创建多层次文件夹
* boolean mkdirs()
创建此抽象路径名指定的目录,包括所有必需但不存在的父目录
*/
public static void function_2(){
File file = new File("d:\\abc\\b\\c");
boolean b = file.mkdirs();
System.out.println(b);
}
public static void function_1(){
File file = new File("d:\\abc");
boolean b = file.mkdir();
System.out.println(b);
}
/*
* File创建文件的功能
* boolean createNewFile()
* 当且仅当不存在具有此抽象路径名指定名称的文件时,不可分地创建一个新的空文件
* 创建的文件路径和文件名,在File构造方法中给出
*/
public static void function() throws IOException{
File file = new File("d:\\a1.txt");
boolean b = file.createNewFile();
System.out.println(b);
}
}
1.5 File类的获取
创建完了File对象之后,那么File类中都有如下常用方法,可以获取文件相关信息
方法演示如下:
package cn.itcast.demo;
import java.io.File;
/*
* File类的获取功能
*/
public class FileDemo3 {
public static void main(String[] args) {
function_3();
}
/*
* File类获取功能
* String getParent() 返回String对象
* File getParentFile() 返回File对象(可以继续调用File类的方法,推荐使用)
* 获取父路径
*/
public static void function_3(){
File file = new File("d:\\eclipse\\eclipse.exe");
File parent = file.getParentFile().getParentFile();
System.out.println(parent);
}
/*
* File类获取功能
* File getAbsoluteFile() 返回File对象(推荐使用这个)
返回此抽象路径名的绝对路径名形式
* String getAbsolutePath() 返回String对象
返回此抽象路径名的绝对路径名字符串
eclipse环境中,写的是一个相对路径,绝对位置工程根目录
*/
public static void function_2(){
File file = new File("d:\\eclipse");//Windows中文件名不区分大小写 d:\eclipse
//File file = new File("eclipse");//Windows中文件名不区分大小写 F:\workspace\day22\eclipse
File absolute = file.getAbsoluteFile();
System.out.println(absolute);
}
/*
* File获取功能
* long length()
* 返回路径中表示的文件大小的字节数
* 不是文件夹,是文件的大小
*/
public static void function_1(){
File file = new File("D:\\eclipse\\eclipse.exe");
long length = file.length();
System.out.println(length);
}
/*
* File类的获取功能
* String getName()
* 返回路径中表示的文件或者文件夹名
* 获取路径中最后部分的名字
*/
public static void function(){
File file = new File("D:\\eclipse\\eclipse.exe");
String name = file.getName();
System.out.println(name);
//String getPath() 将此抽象路径名转换为一个路径名字符串
String path = file.getPath();
System.out.println(path);
}
}
1.6 listFiles()方法介绍
文件都存放在目录(文件夹)中,那么如何获取一个目录中的所有文件或者目录中的文件夹呢?那么我们先想想,一个目录中可能有多个文件或者文件夹,那么如果File中有功能获取到一个目录中的所有文件和文件夹,那么功能得到的结果要么是数组,要么是集合。我们开始查阅API。
package cn.itcast.demo;
import java.io.File;
/*
* File类获取功能
* list
* listFiles
*/
public class FileDemo5 {
public static void main(String[] args) {
function();
System.out.println();
function_1();
System.out.println();
function_2();
}
/*
* static File[] listRoots() 列出可用的文件系统根
*/
public static void function_2(){
//获取系统中所有的根目录
File[] fileArr = File.listRoots();
for(File f : fileArr){
System.out.println(f);
}
}
/*
* File类的获取功能
* File[] listFiles() (常用)
* 获取到File类构造方法中封装的路径中的文件和文件夹名(遍历一个目录)
* 返回的是目录或者文件的全路径
*/
public static void function_1(){
File file = new File("d:\\eclipse");//连隐藏的文件都给你找出来
File[] fileArr = file.listFiles();
for(File f : fileArr){
//String s = f.toString();//这样就可以拿到String类型
System.out.println(f);
}
}
/*
* File类的获取功能
* String[] list()
* 获取到File类构造方法中封装的路径中的文件和文件夹名(遍历一个目录)
* 返回的只有名字
*/
public static void function(){
File file = new File("c:");//连隐藏的文件都给你找出来
String[] strArr = file.list();
System.out.println(strArr.length);
for(String s : strArr){
System.out.println(s);//按照英文字母排列,window里随你喜欢排的,正常文件夹排在前面
}
}
}
输出结果:
21
$Recycle.Bin
Anaconda
BIOS
Documents and Settings
Drivers
hiberfil.sys
Intel
LenovoDrivers
LenovoQMDownload
MSOCache
pagefile.sys
PerfLogs
Program Files
Program Files (x86)
ProgramData
Recovery
swapfile.sys
System Volume Information
UserGuidePDF
Users
Windows
d:\eclipse\.eclipseextension
d:\eclipse\.eclipseproduct
d:\eclipse\artifacts.xml
d:\eclipse\configuration
d:\eclipse\dropins
d:\eclipse\eclipse
d:\eclipse\eclipse.exe
d:\eclipse\eclipse.ini
d:\eclipse\eclipsec.exe
d:\eclipse\features
d:\eclipse\p2
d:\eclipse\plugins
d:\eclipse\readme
C:\
D:\
E:\
F:\
1.7 File类判断功能
- A: File类判断功能
- a: 方法介绍
- boolean exists(): 判断File构造方法中封装路径是否存在
- 存在返回true,不存在返回false
- boolean isDirectory(): 判断File构造方法中封装的路径是不是文件夹
- 如果是文件夹,返回true,不是文件返回false
- boolean isFile(): 判断File构造方法中封装的路径是不是文件
- 如果是文件,返回true,不是文件返回false
- boolean exists(): 判断File构造方法中封装路径是否存在
- a: 方法介绍
package cn.itcast.demo;
import java.io.File;
/*
* File类的判断功能
*/
public class FileDemo4 {
public static void main(String[] args) {
function_1();
System.out.println();
function_1();
}
/*
* File类判断功能
* boolean isDirectory()
* 判断File构造方法中是不是文件夹
* 如果是文件夹,返回true,不是文件返回true
*
* boolean isFile()
* 判断File类构造方法中封装的路径是不是文件
*/
public static void function_1(){
File file = new File("src");
if(file.exists()){
boolean b = file.isDirectory();
System.out.println(b);
}
}
/* File类判断功能
* boolean exists()
* 判断File构造方法中封装路径是否存在
* 存在返回true,不存在返回false
*/
public static void function(){
File file = new File("src");
boolean b = file.exists();
System.out.println(b);
}
}
1.8 文件过滤器
通过listFiles()方法,我们可以获取到一个目录下的所有文件和文件夹,但能不能对其进行过滤呢?比如我们只想要一个目录下的指定扩展名的文件,或者包含某些关键字的文件夹呢?
我们是可以先把一个目录下的所有文件和文件夹获取到,并遍历当前获取到所有内容,遍历过程中在进行筛选,但是这个动作有点麻烦,Java给我们提供相应的功能来解决这个问题。
查阅File类的API,在查阅时发现File类中重载的listFiles方法,并且接受指定的过滤器。
package cn.itcast.demo11;
import java.io.File;
import java.io.FilenameFilter;
//public interface FilenameFilter
//boolean accept(File dir, String name)
//dir - 被找到的文件所在的目录。
//name - 文件的名称
public class MyFilter implements FilenameFilter{
public boolean accept(File dir, String name) {
return name.endsWith(".java");
}
}
package cn.itcast.demo11;
import java.io.File;
public class FileDemo {
public static void main(String[] args) {
//获取扩展名为.java所有文件
//创建File对象
File file = new File("e://demo");
//获取指定扩展名的文件,由于要对所有文件进行扩展名筛选,因此调用方法需要传递过滤器
File[] files = file.listFiles(new MyFilter());
//遍历获取到的所有符合条件的文件
for (File f : files) {
System.out.println(f);
}
}
}
在查阅API时,我们发现,在listFiles(FileFilter filter) 也可以接受一个FileFilter过滤器,它和我们讲的FilenameFilter有啥区别呢?
FilenameFilter过滤器中的accept方法接受两个参数,一个当前文件或文件夹所在的路径,一个是当前文件或文件夹对象的名称。
FileFilter 过滤器中的accept方法接受一个参数,这个参数就当前文件或文件夹对象
当我们需要过滤文件名称时就可以使用FilenameFilter这个过滤器,当我们想对当前文件或文件夹进行过滤,就可以使用FileFilter ,比如需要当前目录下的所有文件夹,就可以使用FileFilter 过滤器。
package cn.itcast.demo1;
import java.io.File;
import java.io.FileFilter;
/*
* 自定义过滤器
* boolean accept(File pathname)
测试指定抽象路径名是否应该包含在某个路径名列表中
*/
public class MyFilter implements FileFilter{
/*
* pathname 接受到的也是文件的全路径
* e://demo//a.txt
* 对路径进行判断,如果是java文件,返回true,不是java文件,返回false
* 文件的后缀结尾是.java
* String getName() 返回由此抽象路径名表示的文件或目录的名称
* boolean endsWith(String suffix) 测试此字符串是否以指定的后缀结束
*/
public boolean accept(File pathname){
System.out.println(pathname + "##############");
//String name = pathname.getName();//获取到文件全路径最后尾部名
return pathname.getName().endsWith(".java");
}
}
package cn.itcast.demo1;
import java.io.File;
/*
* File类的获取,文件获取过滤器
* 遍历目录的时候,可以根据需要,只获取满足条件的文件
* 遍历目录方法listFiles()重载形式
* File[] listFiles(FileFilter filter) 接口 FileFilter
* public interface FileFilter 用于抽象路径名的过滤器
* 传递 FileFilter接口的实现类
* 自定义FileFilter
*/
public class FileDemo {
public static void main(String[] args) {
File file = new File("e://demo");
File[] fileArr = file.listFiles(new MyFilter());
for(File f : fileArr){
System.out.println(f);
}
}
}
第2章 递归
package cn.itcast.demo2;
import java.io.File;
/*
* 对一个目录下的所有内容,进行完全的遍历
* 编程技巧,方法的递归调用,自己调用自己
*/
public class FileDemo {
public static void main(String[] args) {
File dir = new File("e://demo");
getAllDir(dir);
}
/*
* 定义方法,实现目录的全遍历
*/
public static void getAllDir(File dir){
//打印文件名
System.out.println(dir);
//调用方法listFiles() 对目录,dir进行遍历
File[] fileArr = dir.listFiles();
for(File f : fileArr){
//判断变量f表示的路径是不是文件夹
if(f.isDirectory()){
//是一个目录,就要去遍历这个目录
//本方法,getArrDir,就是给这个目录去遍历
//继续调用getAllDir,传递他目录
getAllDir(f);
}else{
//变量f表示的路径是文件,直接打印路径名
System.out.println(f);
}
}
}
}
2.1 递归的概述
递归,指在当前方法内调用自己的这种现象
public void method(){
System.out.println(“递归的演示”);
//在当前方法内调用自己
method();
}
递归分为两种,直接递归和间接递归。
直接递归称为方法自身调用自己。间接递归可以A方法调用B方法,B方法调用C方法,C方法调用A方法。
2.2 递归求和计算
- A: 递归求和计算
- a: 题目分析
- 1+2+3+…+(n-1)+n:求1到n的和
- 总结规律:1到n的和等于1到(n-1)的和再加n
- getSum(n-1)+ n
- 递归出口:getSum(1) return 1;
递归求阶乘
- a: 题目分析
- B: 递归求和计算
- a: 题目分析
- 5!=54321
- =5*4!
- 4!=4*3!
- 3!=3*2!
- 2!=2*1!
- 1!=1
- n!=n*(n-1)!
- 递归出口:n*getJieCheng(n-1): getJieCheng(1) return 1;
- a: 题目分析
package cn.itcast.demo2;
/*
* 方法的递归调用
* 方法自己调用自己
* 适合于:方法中运算的主体不变,但是运行的时候,参与的方法参数会变化
* 但是递归调用坏处(注意):
* 递归一定要有出口(保证递归调用不是死循环,否则,会内存溢出),必须可让程序停下
* 递归次数不能过多(太多递归,内存也受不了)
* 构造方法(里写递归,直接不让你用),禁止递归
*/
public class RecursiveDemo1 {
public static void main(String[] args) {
System.out.println(getSum(100));
System.out.println(getJieCheng(5));
}
/*
* 计算阶乘5!
* 5*4*3*2*1
*/
public static int getJieCheng(int n){
if(1 == n){
return 1;
}
return n * getJieCheng(n-1);
}
/*
* 计算1+2+3+...+100 = 5050
* 计算规律:
* 假如n=100:
* n+(n-1)+(n-2)+..
* 100+(100-1)+(99-1)+..1
*/
public static int getSum(int n){
if(1 == n){
return 1;
}
return n + getSum(n - 1);
}
}
注意:递归一定要有条件限定,保证递归能够停止下来,否则会发生栈内存溢出。
在递归中虽然有限定条件,但是递归次数不能太多。否则也会发生栈内存溢出。
package cn.itcast.demo2;
/*
* 方法的递归调用
* 方法自己调用自己
* 适合于:方法中运算的主体不变,但是运行的时候,参与的方法参数会变化
* 但是递归调用坏处(注意):
* 递归一定要有出口(保证递归调用不是死循环,否则,会内存溢出),必须可让程序停下
* 递归次数不能过多(太多递归,内存也受不了)
* 构造方法(里写递归,直接不让你用),禁止递归
*/
public class RecursiveDemo {
public static void main(String[] args) {
a();//java.lang.StackOverflowError
}
public static void a(){
a();
}
}
2.3 递归计算斐波那契数列
package cn.itcast.demo3;
/*
* 斐波那契数列
*/
public class FibonacciSequenceDemo {
public static void main(String[] args) {
System.out.println(getFBNQ(12));
}
/*
* 方法递归,计算斐波那契数列
*/
public static int getFBNQ(int month){
if(1 == month){
return 1;
}
if(2 == month){
return 1;
}
return getFBNQ(month-1) + getFBNQ(month-2);
}
}
2.4 遍历目录下的所有java文件
package cn.itcast.demo4;
import java.io.File;
import java.io.FileFilter;
public class MyJavaFilter implements FileFilter {
@Override
public boolean accept(File pathname) {
//判断获取的是目录,直接返回true,让其继续遍历
if(pathname.isDirectory()){
return true;
}else{
//endsWith区分大小写
//toLowerCase() 方法用于将大写字符转换为小写
return pathname.getName().toLowerCase().endsWith(".java");
}
}
}
package cn.itcast.demo4;
import java.io.File;
/*
* 遍历目录,获取
*/
public class FileDemo {
public static void main(String[] args) {
getAllJava(new File("e:\\demo"));
}
/*
* 定义方法,实现遍历指定目录
* 获取目录中所有的.java文件
*/
public static void getAllJava(File dir){
//调用File对象方法listFiles()获取,加入过滤器
File[] fileArr = dir.listFiles(new MyJavaFilter());
for(File f : fileArr){
//对f路径,判断是不是文件夹
if(f.isDirectory()){
//递归进入文件夹遍历
getAllJava(f);
}else{
System.out.println(f);
}
}
}
}
第3章 总结
3.1 知识点总结
递归: 方法定义中调用方法本身的现象
直接递归
public void methodA(){
methodA();
}
间接递归
public void metohdB(){
methodC();
}
public void methodC(){
methodB();
}
递归注意实现
要有出口,否则就是死递归
次数不能太多,否则就内存溢出
File: 文件和目录路径名的抽象表示形式
构造方法:
public File(String pathname) 通过给定的文件或文件夹的路径,来创建对应的File对象
public File(String parent, String child) 通过给定的父文件夹路径,与给定的文件名称或目录名称来创建对应的File对象
public File(File parent, String child)通过给定的File对象的目录路径,与给定的文件夹名称或文件名称来创建对应的File对象
路径的分类:
绝对路径, 带盘盘符
E:\Workspace\day20_File\abc.txt
相对路径, 不带盘符
day20_File\abc.txt
注意: 当指定一个文件路径的时候,如果采用的是相对路径,默认的目录为 项目的根目录
方法
public boolean createNewFile()创建文件
返回值为true, 说明创建文件成功
返回值为false,说明文件已存在,创建文件失败
public boolean mkdir() 创建单层文件夹
创建文件夹成功,返回 true
创建文件夹失败,返回 false
public boolean mkdirs() 创建多层文件夹
public boolean delete()
删除此抽象路径名表示的文件或目录。
如果此路径名表示一个目录,则该目录必须为空才能删除
public boolean isDirectory() 判断是否为文件夹
public boolean isFile() 判断是否为文件
public boolean exists() 判断File对象对应的文件或文件夹是否存在
public String getAbsolutePath() 获取当前File的绝对路径
public String getName() 获取当前File对象的文件或文件夹名称
public long length() 获取当前File对象的文件或文件夹的大小(字节)
public File[] listFiles() 获取File所代表目录中所有文件或文件夹的绝对路径