【Java基础】特殊文本文件、日志技术

特殊文件概述

认识

  • 普通文件.txt。
  • 属性文件.properties。
  • XML文件.xml。

为什么要用特殊文件?

  • 存储多个用户的用户名和密码,txt不可以解析,但是properties、xml可以。
  • 存储多个用户的用户名、密码、家乡和性别,txt、properties不可以解析,xml可以。
  • 可以存储有关系的数据,作为系统的配置文件作为信息进行传输

我们主要学什么?

  • 了解它们的特点、作用。
  • 学习使用程序读取它们里面的数据。
  • 学习使用程序把数据存储到这些文件里。(用得不多。)

日志技术

把程序运行的信息,记录到文件中,方便程序员定位bug、并了解程序的执行情况等。

特殊文件:properties属性文件

  • 是一个Map集合键值对集合),但是我们一般不会当集合使用
  • 核心作用:Properties是用来代表属性文件的,通过Properties可以读写属性文件里的键值对。

(读)构造器

  1. public Properties()。用于构建Properties集合对象(空容器)。

(读)常用方法

  1. public void load(InputStream is)。通过字节输入流,读取属性文件里的键值对数据。
  2. public void load(Reader reader)。通过字符输入流,读取属性文件里的键值对数据。
  3. public String getProperty(String key)。根据键获取值(其实就是get方法的效果)。
  4. public Set stringPropertyNames()。获取全部键的集合(其实就是ketSet方法的效果)。

读取步骤

1
2
3
1、创建一个Properties的对象出来(键值对集合,空容器)
2、调用load(字符输入流/字节输入流)方法,开始加载属性文件中的键值对数据到properties对象中去
3、调用getProperty(键)方法,根据键取值

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* 目标:掌握使用Properties类读取属性文件中的键值对信息。
*/
public class PropertiesTest1 {
public static void main(String[] args) throws Exception {
// 1、创建一个Properties的对象出来(键值对集合,空容器)
Properties properties = new Properties();
System.out.println(properties);

// 2、开始加载属性文件中的键值对数据到properties对象中去
properties.load(new FileReader("properties-xml-log-app\\src\\users.properties"));
System.out.println(properties);

// 3、根据键取值
System.out.println(properties.getProperty("赵敏"));
System.out.println(properties.getProperty("张无忌"));

// 4、遍历全部的键和值。
//获取键的集合
Set<String> keys = properties.stringPropertyNames();
for (String key : keys) {
//再根据键获取值
String value = properties.getProperty(key);
System.out.println(key + "---->" + value);
}

properties.forEach((k, v) -> {
System.out.println(k + "---->" + v);
});
}
}

(写)构造器

  1. public Properties()。用于构建Properties集合对象(空容器)。

(写)常用方法

  1. public Object setProperty(String key, String value)。保存键值对数据到Properties对象中去。
  2. public void store(OutputStream os, String comments)。把键值对数据,通过字节输出流写出到属性文件里去。注意这里需要写评论信息。
  3. public void store(Writer w, String comments)。把键值对数据,通过字符输出流写出到属性文件里去。

步骤

1
2
3
4
5
1、先准备一个.properties属性文件,按照格式写几个键值对
1、创建Properties对象出来,
2、调用setProperty存储一些键值对数据
3、调用store(字符输出流/字节输出流, 注释),将Properties集合中的键和值写到文件中
注意:第二个参数是注释,必须得加;

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class PropertiesTest2 {
public static void main(String[] args) throws Exception {
// 1、创建Properties对象出来,先用它存储一些键值对数据
Properties properties = new Properties();
properties.setProperty("张无忌", "minmin");
properties.setProperty("殷素素", "cuishan");
properties.setProperty("张翠山", "susu");

// 2、把properties对象中的键值对数据存入到属性文件中去
properties.store(new FileWriter("properties-xml-log-app/src/users2.properties")
, "i saved many users!");

}
}

特殊文件:XML文件

概述

是什么?

  • XML( 全称EXtensible Markup Language, 可扩展标记语言 )。
  • 本质是一种数据的格式,可以用来存储复杂的数据结构,和数据关系。

特点

  • XML中的“<标签名>” 称为一个标签或一个元素,一般是成对出现的。
  • XML中的标签名可以自己定义(可扩展),但必须要正确的嵌套
  • XML中只能有一个根标签
  • XML中的标签可以有属性
  • 如果一个文件中放置的是XML格式的数据,这个文件就是XML文件,后缀一般要写成**.xml**。

XML的创建

  • 就是创建一个XML类型的文件,要求文件的后缀必须使用xml,如hello_world.xml。

语法规则

  • (1)XML文件的后缀名为:xml,文档声明(抬头)必须是第一行
1
2
3
<?xml version="1.0" encoding="UTF-8" > //自动
version:XML默认的版本号码、该属性是必须存在
encoding:本XML文件的编码
  • (2)XML中可以定义注释信息:

  • (3)根标签有且只能有一个。下面可以写子标签,子标签里面可以存属性,例如id=”1”。再往下可以继续写子标签。

  • (4)标签必须承成对出现,又开始有结束:

  • (5)必须能够正确的嵌套。

  • XML中书写“<”、“&”等,可能会出现冲突,导致报错,此时可以用如下特殊字符替代。注意,XML可以在浏览器中直接渲染,在IDEA里面右键-open in expolrer(将这些特殊字符转换完成)。

1
2
3
4
5
6
&lt;    <  小于
&gt; > 大于
&amp; & 和号
&apos; ' 单引号
&quot; " 引号
例如:<data> 3 &lt; 2 &amp;&amp; 5 &gt; 4 </data>
  • XML中可以写一个叫CDATA的特殊数据区: 里面的内容可以随便写
1
2
3
4
5
<data1>
<![CDATA[
3 < 2 && 5 > 4
]]>
</data1>

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8" ?>
<!-- 注释:以上抬头声明必须放在第一行,必须有 -->
<!-- 根标签只能有一个 -->
<users>
<user id="1" desc="第一个用户">
<name>张无忌</name>
<sex></sex>
<地址>光明顶</地址>
<password>minmin</password>
</user>
<people>很多人</people>
<user id="2">
<name>敏敏</name>
<sex></sex>
<地址>光明顶</地址>
<password>wuji</password>
</user>
</users>

作用和应用场景

  • 本质是一种数据格式,可以存储复杂的数据结构,和数据关系。
  • 应用场景:经常用来做为系统的配置文件;或者作为一种特殊的数据结构,在网络中进行传输(现在用得不多但是也能作为一种方案)。

读取XML文件中的数据

又叫,解析XML文件。使用程序读取XML文件中的数据。

  • 注意:程序员并不需要自己写原始的IO流代码来解析XML,难度较大!也相当繁琐!
  • 其实,有很多开源的,好用的,解析XML的框架,最知名的是:Dom4j(第三方研发的)。

Dom4j下载

  1. 下载Dom4j框架,官网下载。
  2. 在项目中创建一个文件夹:lib。
  3. 将dom4j-2.1.3.jar文件复制到 lib 文件夹。
  4. 在jar文件上点右键,选择 Add as Library -> 点击OK。
  5. 在类中导包使用。

DOM4J解析XML文件的思想:文档对象模型

思想

  1. 首先用SAXReader解析器把文件内容一下子加载到内存中,变成一个Document(整个文档)对象。
  2. 通过Document对象就可以获取Element对象:元素(标签)。
  3. Element又可以获取Attribute:属性、子元素、文本。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?xml version="1.0" encoding="UTF-8" ?>
<users>
<user id="1">
<name>张无忌</name>
<sex></sex>
<地址>光明顶</地址>
<password>minmin</password>
<data> 3 &lt; 2 &amp;&amp; 5 > 4 </data>
<data1>
<![CDATA[
3 < 2 && 5 > 4
]]>
</data1>
</user>
<user id="2">
<name>敏敏</name>
<sex></sex>
<地址>光明顶</地址>
<password>wuji</password>
<data> 3 &lt; 2 &amp;&amp; 5 > 4 </data>
<data1>
<![CDATA[
3 < 2 && 5 > 4
]]>
</data1>
</user>
</users>

构造器

  1. public SAXReader()。构建Dom4J的解析器对象。Dom4j提供的解析器,可以认为是代表整个Dom4j框架。
  2. public Document read(String url)。把XML文件读成Document对象。
  3. public Document read(InputStream is)。通过字节输入流读取XML文件。

常用方法

  1. Element getRootElement()。获得根元素对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Dom4JTest1 {
public static void main(String[] args) throws Exception {
// 1、创建一个Dom4J框架提供的解析器对象
SAXReader saxReader = new SAXReader();

// 2、使用saxReader对象把需要解析的XML文件读成一个Document对象。
Document document =
saxReader.read("properties-xml-log-app\\src\\helloworld.xml");

// 3、从文档对象中解析XML文件的全部数据了
Element root = document.getRootElement(); //获取了根元素
System.out.println(root.getName());
}
}

Element提供的方法

注意,只能从根元素一级一级向下解析

  1. public String getName()。得到元素名字。
  2. public List elements()。得到当前元素下所有子元素。
  3. public List elements(String name)。得到当前元素下指定名字的子元素返回集合。
  4. public Element element(String name)。得到当前元素下指定名字的子元素,如果有很多名字相同的返回第一个
  5. public String attributeValue(String name)。通过属性名直接得到属性值。
  6. public String elementText(子元素名)。得到指定名称的子元素的文本。
  7. public String getText()。得到文本。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class Dom4JTest1 {
public static void main(String[] args) throws Exception {
// 1、创建一个Dom4J框架提供的解析器对象
SAXReader saxReader = new SAXReader();

// 2、使用saxReader对象把需要解析的XML文件读成一个Document对象。
Document document =
saxReader.read("properties-xml-log-app\\src\\helloworld.xml");

// 3、从文档对象中解析XML文件的全部数据了
Element root = document.getRootElement();
System.out.println(root.getName());

// 4、获取根元素下的全部一级子元素。
// List<Element> elements = root.elements();
List<Element> elements = root.elements("user");
for (Element element : elements) {
System.out.println(element.getName());
}

// 5、获取当前元素下的某个子元素。
Element people = root.element("people");
System.out.println(people.getText());

// 如果下面有很多子元素user,默认获取第一个。
Element user = root.element("user");
System.out.println(user.elementText("name"));

// 6、获取元素的属性信息呢?
System.out.println(user.attributeValue("id"));
Attribute id = user.attribute("id");
System.out.println(id.getName());
System.out.println(id.getValue());

List<Attribute> attributes = user.attributes();
for (Attribute attribute : attributes) {
System.out.println(attribute.getName() + "=" + attribute.getValue());
}

// 7、如何获取全部的文本内容:获取当前元素下的子元素文本值
System.out.println(user.elementText("name"));
System.out.println(user.elementText("地址"));
System.out.println(user.elementTextTrim("地址")); // 取出文本去除前后空格
System.out.println(user.elementText("password"));

Element data = user.element("data");
System.out.println(data.getText());
System.out.println(data.getTextTrim()); // 取出文本去除前后空格
}
}

如何往XML文件中写入数据?

  • DOM4J也提供了往XML文件中写标签的方法,但是用起来比较麻烦,不好维护。这里不建议使用。
  • 我们自己使用StringBuilder按照标签的格式拼接,然后再使用BufferedWriter写到XML文件中去就可以了。更加灵活。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Dom4JTest2 {
public static void main(String[] args) {
// 1、使用一个StringBuilder对象来拼接XML格式的数据。
StringBuilder sb = new StringBuilder();
sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n");
sb.append("<book>\r\n");
sb.append("\t<name>").append("从入门到跑路").append("</name>\r\n");
sb.append("\t<author>").append("dlei").append("</author>\r\n");
sb.append("\t<price>").append(999.99).append("</price>\r\n");
sb.append("</book>");

try (
BufferedWriter bw = new BufferedWriter(new FileWriter("properties-xml-log-app/src/book.xml"));
){
bw.write(sb.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}

补充知识:约束XML文件的编写[了解]

限制XML文件中的标签或者属性,只能按照规定的格式写。

专门用来限制xml书写格式的文档,比如:限制标签、属性应该怎么写。有两种约束技术:

  1. DTD约束文档。(能够约束具体的数据类型。)
  2. Schame约束文档。(能够约束具体的数据类型。)

案例:利用DTD约束文档,约束一个XML文件的编写。(了解)

1
2
3
1.编写DTD约束文档,后缀必须是.dtd
2.在需要编写的XML文件中导入该DTD约束文档(<!DOCTYPE 书架 SYSTEM "data.dtd">)
3.然后XML文件,就必须按照DTD约束文档指定的格式进行编写,否则报错!

代码(了解)

1
2
3
4
5
<!ELEMENT 书架 (书+)>
<!ELEMENT 书 (书名,作者,售价)>
<!ELEMENT 书名 (#PCDATA)>
<!ELEMENT 作者 (#PCDATA)>
<!ELEMENT 售价 (#PCDATA)>

案例:利用schema约束文档,约束一个XML文件的编写。(了解)

步骤(了解)

1
2
3
1.编写schema约束文档,后缀必须是.xsd,具体的形式到代码中观看。
2.在需要编写的XML文件中导入该schema约束文档
3.按照约束内容编写XML文件的标签。

日志技术

概述

场景引入

  • 希望系统能记住某些数据是被谁操作的,比如被谁删除了?
  • 想分析用户浏览系统的具体情况,以便挖掘用户的具体喜好?
  • 当系统在开发中或者上线后出现了bug,崩溃了,该通过什么去分析、定位bug?

日志

  • 好比生活中的日记,可以记录你生活中的点点滴滴。
  • 程序中的日志,通常就是一个文件,里面记录的是程序运行过程中的各种信息

输出语句的弊端

  • 日志会展示在控制台。
  • 不能更方便的将日志记录到其他的位置(文件,数据库)。
  • 想取消日志,需要修改源代码才可以完成。

日志技术

  • 可以将系统执行的信息,方便的记录到指定的位置(控制台、文件中、数据库中)。
  • 可以随时以开关的形式控制日志的启停,无需侵入到源代码中去进行修改。
输出语句 日志技术
输出位置 输出到控制台 可以将日志信息写入到文件或者数据库中
取消日志 需要修改代码,灵活性比较差 不需要修改代码,灵活性比较好
多线程 性能较差 性能较好

体系结构

日志框架

  1. JUL(java.util.loggiing)。
  2. Log4j。
  3. Logback。
  4. 其他实现。

日志接口

为了减轻负担,设置接口让大家都遵守。

  1. Commons Logging (JCL)。
  2. Simple Logging Facade for Java (SLF4J)。
  • 日志框架:牛人或者第三方公司已经做好的实现代码,后来者直接可以拿去使用。
  • 日志接口:设计日志框架的一套标准,日志框架需要实现这些接口。
  • 注意1:因为对Commons Logging接口不满意,有人就搞了SLF4J;因为对Log4j的性能不满意,有人就搞了Logback。
  • 注意2:Logback是基于slf4j的日志规范实现的框架

Logback日志框架

网站:https://logback.qos.ch/index.html

Logback日志框架有以下几个模块:

  1. logback-core。基础模块,是其他两个模块依赖的基础(必须有)。
  2. logback-classic。功能模块,完整实现了slf4j API的模块(必须有)。
  3. logback-access。与 Tomcat 和 Jetty 等 Servlet 容器集成,以提供 HTTP 访问日志的功能(可选,以后再接触)。

想使用Logback日志框架,至少需要在项目中整合如下三个模块:

  1. slf4j-api。日志接口。
  2. logback-core。基础模块。
  3. logback-classic。功能模块。

Logback入门

需求:使用Logback日志框架,纪录系统的运行信息。

实现步骤

1
2
3
4
5
1.导入Logback框架到项目中去。
2.将Logback框架的核心配置文件logback.xml直接拷贝到src目录下(必须是src下)。
3.创建Logback框架提供的Logger对象,然后用Logger对象调用其提供的方法就可以记录系统的日志信息。
创建一个日志记录日对象:
public static final Logger LOGGER = LoggerFactory.getLogger(“类名");

具体步骤

1
2
3
4
1.在项目下新建文件夹lib,导入Logback的相关jar包到该文件夹下,并添加到项目库中去。
2.必须将Logback的核心配置文件logback.xml直接拷贝到src目录下。
3.在代码中获取日志的对象
4.调用日志对象的方法记录日志信息

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class LogBackTest {
// 创建一个Logger日志对象
public static final Logger LOGGER = LoggerFactory.getLogger("LogBackTest");

public static void main(String[] args) {
//while (true) {
try {
LOGGER.info("chu法方法开始执行~~~");
chu(10, 0);
LOGGER.info("chu法方法执行成功~~~");
} catch (Exception e) {
LOGGER.error("chu法方法执行失败了,出现了bug~~~");
}
//}
}

public static void chu(int a, int b){
LOGGER.debug("参数a:" + a);
LOGGER.debug("参数b:" + b);
int c = a / b;
LOGGER.info("结果是:" + c);
}
}

Logback.xml日志配置文件

核心配置文件logback.xml,对Logback日志框架进行控制的。在记录日志时会读取配置文件中的配置信息,从而记录日志的形式。

具体可以做哪些配置

1
2
3
4
5
6
7
8
9
1. 可以配置日志输出的位置是文件、还是控制台。
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
2. 可以配置日志输出的格式。
3. 还可以配置日志关闭和开启、以及哪些日志输出哪些日志不输出。// 设置为 “ALL”或“OFF”。//设置只输出到配置文件或者控制台,可以删掉其中一行。
<root level="ALL">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE" />
</root>
  • 如下图所示,控制日志往文件中输出,还是往控制台输出**

1668045955362

  • 如下图所示,控制打开和关闭日志

1668046078574

  • 如下图所示,控制日志的输出的格式

    日志格式是由一些特殊的符号组成,可以根据需要删减不想看到的部分。比如不想看到线程名那就不要[%thread]。但是不建议同学们更改这些格式,因为这些都是日志很基本的信息。

1668046216355

Logback设置日志级别【重要】

认识日志级别

日志级别指的是日志信息的类型,日志都会分级别,常见的日志级别如下(优先级依次升高):

日志级别 说明
trace 追踪,指明程序运行轨迹
debug 调试,实际应用中一般将其作为最低级别,而 trace 则很少使用
info 输出重要的运行信息,数据连接、网络连接、IO操作等等,使用较多
warn 警告信息,可能会发生问题,使用较多
error 错误信息, 使用较多

日志级别的作用

用于控制系统中哪些日志级别是可以输出的

如何设置日志级别

可以在配置文件中书写日志级别:

1
2
3
4
<root level=“info">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE" />
</root>

只有日志的级别是大于或等于核心配置文件配置的日志级别,才会被记录,否则不记录。