日志框架、File、递归
1、日志框架
1.1 日志技术概述
- 生活中的日志:生活中的日志就好比日记,可以记录你生活的点点滴滴。
- 程序中的日志:程序中的日志可以用来记录程序运行过程中的信息,并可以进行永久存储。
日志技术具备的优势
- 可以将系统执行的信息选择性的记录到指定的位置(控制台、文件中、数据库中)。
- 可以随时以开关的形式控制是否记录日志,无需修改源代码。
日志技术体系结构
1.2 Logback概述
Logback日志框架
Logback是由log4j创始人设计的另一个开源日志组件,性能比log4j要好
官方网站:https://logback.qos.ch/index.html
Logback是基于slf4j的日志规范实现的框架。
Logback主要分为三个技术模块:
- logback-core: logback-core模块为其他两个模块奠定了基础,必须有。
- logback-classic:它是log4j的一个改良版本,同时它完整实现了slf4j API。
- logback-access模块与Tomcat和Jetty等Servlet容器集成,以提供 HTTP访问日志功能
1.3 Logback快速入门
导入Logback日志技术到项目中
-
在项目下新建文件夹lib,导入Logback的相关jar包到该文件夹下,并添加到项目依赖库中去。
-
将Logback的核心配置文件logback.xml直接拷贝到src目录下(必须是src下)。
-
在代码中获取日志的对象
public static final Logger LOGGER = loggerFactory.getLogger("类对象");
- 使用日志对象LOGGER调用其方法输出日志信息
1.4 Logback配置详解
Logback日志系统的特性都是通过核心配置文件logback.xml控制的。
Logback日志输出位置、格式设置:
- 通过logback.xml中的标签可以设置输出位置和日志信息的详细格式。
- 通常可以设置2个日志输出位置:一个是控制台、一个是系统文件中
输出到控制台的配置标志
< appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
输出到系统文件的配置标志
< appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
可以通过设置日志的输出级别来控制哪些日志信息输出或者不输出。
- 级别程度依次是:TRACE< DEBUG<INFO<WARN<ERROR;默认级别是debug(忽略大小写),对应其方法。
- 作用:用于控制系统中哪些日志级别是可以输出的,只输出级别不低于设定级别的日志信息。
- ALL和OFF分别是打开全部日志信息,及关闭全部日志信息。
<root level=INFO">
< appender-ref ref="CONSOLE"/>
< appender-ref ref="FILE”/>
< / root>
2、File类
2.1 File类的概述
File类在包java.io.File下、代表操作系统的文件对象(文件、文件夹)。
File类提供了诸如:定位文件,获取文件本身的信息、删除文件、创建文件(文件夹)等功能。
File类创建对象
方法名称 | 说明 |
---|---|
public File(string pathname) | 根据文件路径创建文件对象 |
public File(string parent,string child) | 从父路径名字符串和子路径名字符串创建文件对象 |
public File(File parent,string child) | 根据父路径对应文件对象和子路径名字符串创建文件对象 |
- File对象可以定位文件和文件夹
- File封装的对象仅仅是一个路径名,这个路径可以是存在的,也可以是不存在的。
绝对路径和相对路径
绝对路径:从盘符开始
File file1 = new File(“D: \\software\\a.txt”);
相对路径:不带盘符,默认直接到当前工程下的目录寻找文件。
File file3 = new File(“模块名\la.txt”);
import java.io.File;
public class FileDemo {
public static void main(String[] args) {
// 1、创建File对象(指定了文件的路径)
// 路径写法: D:\resources\xueshan.jpeg
// D:/resources/xueshan.jpeg
// File.separator
// File f = new File("D:\\resources\\xueshan.jpeg");
// File f = new File("D:/resources/xueshan.jpeg");
File f = new File("D:" + File.separator+"resources"+ File.separator +"xueshan.jpeg");
long size = f.length(); // 是文件的字节大小
System.out.println(size);
// 2、File创建对象,支持绝对路径 支持相对路径(重点)
File f1 = new File("D:\\resources\\beauty.jpeg"); // 绝对路径
System.out.println(f1.length());
// 相对路径:一般定位模块中的文件的。 相对到工程下!!
File f2 = new File("file-io-app/src/data.txt");
System.out.println(f2.length());
// 3、File创建对象 ,可以是文件也可以是文件夹
2.2 File类常用API
File类的判断文件类型、获取文件信息功能
方法名称 | 说明 |
---|---|
public boolean isDirectory() | 测试此抽象路径名表示的File是否为文件夹 |
public boolean isFile() | 测试此抽象路径名表示的File是否为文件 |
public boolean exists() | 测试此抽象路径名表示的File是否存在 |
public string getAbsolutePath() | 返回此抽象路径名的绝对路径名字符串 |
public string getPath() | 将此抽象路径名转换为路径名字符串 |
public string getName() | 返回由此抽象路径名表示的文件或文件夹的名称 |
public long lastModified() | 返回文件最后修改的时间毫秒值 |
import java.io.File;
import java.text.SimpleDateFormat;
public class FileDemo {
public static void main(String[] args) {
// 1.绝对路径创建一个文件对象
File f1 = new File("D:/resources/xueshan.jpeg");
// a.获取它的绝对路径。
System.out.println(f1.getAbsolutePath());
// b.获取文件定义的时候使用的路径。
System.out.println(f1.getPath());
// c.获取文件的名称:带后缀。
System.out.println(f1.getName());
// d.获取文件的大小:字节个数。
System.out.println(f1.length()); // 字节大小
// e.获取文件的最后修改时间
long time = f1.lastModified();
System.out.println("最后修改时间:" + new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(time));
// f、判断文件是文件还是文件夹
System.out.println(f1.isFile()); // true
System.out.println(f1.isDirectory()); // false
System.out.println("-------------------------");
File f2 = new File("file-io-app\\src\\data.txt");
// a.获取它的绝对路径。
System.out.println(f2.getAbsolutePath());
// b.获取文件定义的时候使用的路径。
System.out.println(f2.getPath());
// c.获取文件的名称:带后缀。
System.out.println(f2.getName());
// d.获取文件的大小:字节个数。
System.out.println(f2.length()); // 字节大小
// e.获取文件的最后修改时间
long time1 = f2.lastModified();
System.out.println("最后修改时间:" + new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(time1));
// f、判断文件是文件还是文件夹
System.out.println(f2.isFile()); // true
System.out.println(f2.isDirectory()); // false
System.out.println(f2.exists()); // true
File file = new File("D:/");
System.out.println(file.isFile()); // false
System.out.println(file.isDirectory()); // true
System.out.println(file.exists()); // true
File file1 = new File("D:/aaa");
System.out.println(file1.isFile()); // false
System.out.println(file1.isDirectory()); // false
System.out.println(file1.exists()); // false
}
}
File类创建文件的功能
方法名称 | 说明 |
---|---|
public boolean createNewFile() | 创建一个新的空的文件 |
public boolean mkdir() | 只能创建一级文件夹 |
public boolean mkdirs() | 可以创建多级文件夹 |
File类删除文件的功能
方法名称 | 说明 |
---|---|
public boolean delete() | 删除由此抽象路径名表示的文件或空文件夹 |
- delete方法默认只能删除文件和空文件夹。
- delete方法直接删除不走回收站。
import java.io.File;
import java.io.IOException;
public class FileDemo{
public static void main(String[] args) throws IOException {
File f = new File("file-io-app\\src\\data.txt");
// a.创建新文件,创建成功返回true ,反之 ,不需要这个,以后文件写出去的时候都会自动创建
System.out.println(f.createNewFile());
File f1 = new File("file-io-app\\src\\data02.txt");
System.out.println(f1.createNewFile()); // (几乎不用的,因为以后文件都是自动创建的!)
// b.mkdir创建一级目录
File f2 = new File("D:/resources/aaa");
System.out.println(f2.mkdir());
// c.mkdirs创建多级目录(重点)
File f3 = new File("D:/resources/ccc/ddd/eee/ffff");
// System.out.println(f3.mkdir());
System.out.println(f3.mkdirs()); // 支持多级创建
// d.删除文件或者空文件夹
System.out.println(f1.delete());
File f4 = new File("D:/resources/xueshan.jpeg");
System.out.println(f4.delete()); // 占用一样可以删除
// 只能删除空文件夹,不能删除非空文件夹.
File f5 = new File("D:/resources/aaa");
System.out.println(f5.delete());
}
}
File类的遍历功能
方法名称 | 说明 |
---|---|
public string[ ] list() | 获取当前目录下所有的"一级文件名称"到一个字符串数组中去返回 |
public File[] listFiles()(常用) | 获取当前目录下所有的"一级文件对象"到一个文件对象数组中去返回(重点) |
listFiles方法注意事项: |
- 当调用者不存在时,返回null
- 当调用者是一个文件时,返回null
- 当调用者是一个空文件夹时,返回一个长度为0的数组
- 当调用者是一个有内容的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回
- 当调用者是一个有隐藏文件的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏内容
- 当调用者是一个需要权限才能进入的文件夹时,返回null
import java.io.File;
import java.util.Arrays;
public class FileDemo{
public static void main(String[] args) {
// 1、定位一个目录
File f1 = new File("D:/resources");
String[] names = f1.list();
for (String name : names) {
System.out.println(name);
}
// 2.一级文件对象
// 获取当前目录下所有的"一级文件对象"到一个文件对象数组中去返回(重点)
File[] files = f1.listFiles();
for (File f : files) {
System.out.println(f.getAbsolutePath());
}
// 注意事项
File dir = new File("D:/resources/ddd");
File[] files1 = dir.listFiles();
System.out.println(Arrays.toString(files1));
}
}
3、方法递归
3.1 递归的形式和特点
方法直接调用自己或者间接调用自己的形式称为方法递归( recursion)。
递归做为一种算法在程序设计语言中广泛应用。
递归的形式
直接递归:方法自己调用自己。
间接递归:方法调用其他方法,其他方法又回调方法自己。
递归如果没有控制好终止,会出现递归死循环,导致栈内存溢出现象。
public class RecursionDemo {
public static void main(String[] args) {
test2();
}
public static void test(){
System.out.println("=======test被执行========");
test(); // 方法递归 直接递归形式
}
public static void test2(){
System.out.println("=======test2被执行========");
test3(); // 方法递归 间接递归
}
private static void test3() {
System.out.println("=======test3被执行========");
test2();
}
}
递归解决问题的思路:
把一个复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。
3.2 递归案例
计算1----n的和
需求:计算1-n的和的结果,使用递归思想解决。
public class RecursionDemo {
public static void main(String[] args) {
System.out.println(f(5));
}
public static int f(int n){
if(n == 1){
return 1;
}else {
return f(n - 1) + n;
}
}
}
猴子吃桃问题
猴子第一天摘下若干桃子,当即吃了一半,觉得好不过瘾,于是又多吃了一个第二天又吃了前天剩余桃子数量的一半,觉得好不过瘾,于是又多吃了一个以后每天都是吃前天剩余桃子数量的一半,觉得好不过瘾,又多吃了一个等到第10天的时候发现桃子只有1个了。
需求:请问猴子第—天摘了多少个桃子?
/**
猴子吃桃。
公式(合理的): f(x) - f(x)/2 - 1 = f(x+1)
2f(x) - f(x) - 2 = 2f(x + 1)
f(x) = 2f(x + 1) + 2
求f(1) = ?
终结点: f(10) = 1
*/
public class RecursionDemo {
public static void main(String[] args) {
System.out.println(f(1));
System.out.println(f(2));
System.out.println(f(3));
}
public static int f(int n){
if(n == 10){
return 1;
}else {
return 2 * f(n + 1) + 2;
}
}
}
3.3 非规律化递归案例
非递归化问题需要流程化的编程思想。
文件搜索
需求:文件搜索、从C:盘中,搜索出某个文件名称并输出绝对路径。
import java.io.File;
import java.io.IOException;
/**
去D判断搜索 eDiary.exe文件
*/
public class RecursionDemo{
public static void main(String[] args) {
// 2、传入目录 和 文件名称
searchFile(new File("D:/") , "eDiary.exe");
}
/**
* 1、搜索某个目录下的全部文件,找到我们想要的文件。
* @param dir 被搜索的源目录
* @param fileName 被搜索的文件名称
*/
public static void searchFile(File dir,String fileName){
// 3、判断dir是否是目录
if(dir != null && dir.isDirectory()){
// 可以找了
// 4、提取当前目录下的一级文件对象
File[] files = dir.listFiles(); // null []
// 5、判断是否存在一级文件对象,存在才可以遍历
if(files != null && files.length > 0) {
for (File file : files) {
// 6、判断当前遍历的一级文件对象是文件 还是 目录
if(file.isFile()){
// 7、是不是咱们要找的,是把其路径输出即可
if(file.getName().contains(fileName)){
System.out.println("找到了:" + file.getAbsolutePath());
// 启动它。
try {
Runtime r = Runtime.getRuntime();
r.exec(file.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
}
}else {
// 8、是文件夹,需要继续递归寻找
searchFile(file, fileName);
}
}
}
}else {
System.out.println("对不起,当前搜索的位置不是文件夹!");
}
}
}
啤酒问题
需求:啤酒2元1瓶,4个盖子可以换一瓶,2个空瓶可以换一瓶,请问10元钱可以喝多少瓶酒,剩余多少空瓶和盖子。
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
public class RecursionDemo{
// 定义一个静态的成员变量用于存储可以买的酒数量
public static int totalNumber; // 总数量
public static int lastBottleNumber; // 记录每次剩余的瓶子个数
public static int lastCoverNumber; // 记录每次剩余的盖子个数
public static void main(String[] args) {
// 1、拿钱买酒
buy(10);
System.out.println("总数:" + totalNumber);
System.out.println("剩余盖子数:" + lastCoverNumber);
System.out.println("剩余瓶子数:" + lastBottleNumber);
}
public static void buy(int money){
// 2、看可以立马买多少瓶
int buyNumber = money / 2; // 5
totalNumber += buyNumber;
// 3、把盖子 和瓶子换算成钱
// 统计本轮总的盖子数 和 瓶子数
int coverNumber = lastCoverNumber + buyNumber;
int bottleNumber = lastBottleNumber + buyNumber;
// 统计可以换算的钱
int allMoney = 0;
if(coverNumber >= 4){
allMoney += (coverNumber / 4) * 2;
}
lastCoverNumber = coverNumber % 4;
if(bottleNumber >= 2){
allMoney += (bottleNumber / 2) * 2;
}
lastBottleNumber = bottleNumber % 2;
if(allMoney >= 2){
buy(allMoney);
}
Integer[] arr2 = new Integer[]{11, 22, 33};
Arrays.sort(arr2);
}
}