特殊文件,日志技术,多线程,线程的创建

1,特殊文件

普通文件:txt

属性文件:properties

XML文件:xml

使用特殊文件:存储多个用户的用户名,密码,家乡,性别

                        存储有关系的数据,作为系统的配置文件

                        作为信息进行传输

这些特殊文件,我问主要学什么:

1,了解它们的特点、作用

2,学习使用程序读取它们里面的数据

3,学习使用程序把数据存储到这些文件里

(1)Properties

是一个Map集合(键值对集合),但是我们一般不会当集合使用

核心作用: Properties是用来代表属性文件的,通过Properties可以读写属性文件里的内容

使用Properties读取属性文件里的键值对数据

构造器说明
public Properties()用于构建Properties集合对象(空容器)
常用方法说明
public void load(InputStream is)通过字节输入流,读取属性文件里的键值对数据
public void load(Reader reader)通过字符输入流,读取属性文件里的键值对数据
public String getProperty (String key)根据键获取值(其实就是get方法的效果)
public Set<String> stringPropertyNames()获取全部键的集合(其实就是ketSet方法的效果)

使用Properties把键值对数据写出到属性文件里去

构造器说明
public Properties()用于构建Properties集合对象(空容器)
常用方法说明
public Object setProperty(String key,String value)保存键值对数据到Properties对象中去
public void store(OutputStream os, String comments)把键值对数据,通过字节输出流写出到属性文件里去
public void store(Writer w,String comments)把键值对数据,通过字符输出流写出到属性文件里去

//修改李方的数据   从35到18

import java.io.FileReader;
import java.io.FileWriter;
import java.util.Properties;

public class TJ {
    public static void main(String[] args) throws Exception {
        Properties properties=new Properties();

        properties.load(new FileReader("C:\\Users\\Lenovo\\IdeaProjects\\two\\two2\\src\\users.txt"));

        if (properties.containsKey("李方")){
            properties.setProperty("李方","18");
        }
        properties.store(new FileWriter("C:\\Users\\Lenovo\\IdeaProjects\\two\\two2\\src\\users.txt"),"success");
    }
}

 (2)XML文件

XML:(全称EXtensible Markup Language,可扩展标记语言)

本质是一种数据的格式,可以用来存储复杂的数据结构,和数据关系

1)XML的特点

1,XML中的“<标签名>”称为一个标签或一个元素,一般是成对出现的

2,XML中的标签名可以自己定义(可扩展),但必须要正确的嵌套

3,XML中只能有一个根标签

4,XML中的标签可以有属性

5,如果一个文件中放置的是XML格式的数据,这个文件就是XML文件,后缀一般要写成.xml

2)XML文件的创建

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

3)XML的语法规则

1,XML文件的后缀名为: xml,文档声明必须是第一行

<?xml version="1.0" encoding="UTF-8" ?>

version:XML默认的版本号码、该属性是必须存在的

encoding:本XML文件的编码

2,XML中可以定义注释信息:<!--注释内容-->

3,XML中书写”<”、“&”等,可能会出现冲突,导致报错,此时可以用如下特殊字符替代

&lt;<        小于
&gt;>        大于
&amp;&        和号
&apos;'        单引号
&qout;"        引号

4,XML中可以写一个叫CDATA的数据区:<![CDATA[ ...内容...],里面的内容可以随便写

<?xml version="1.0" encoding="UTF-8" ?>
<!--注释:以上抬头声明必须放在第一行,必须有-->
<!--根标签只能有一个-->
<Users>
    <user id="1">
        <name>张无忌</name>
        <sex>男</sex>
        <password>123456</password>
        <date> 3 &lt; 2 &amp;&amp;5 > 4</date>
        <data1>
            [<![CDATA[
            3<2 &&5>4
            ]]>
        </data1>
    </user>
    <user id="2">
        <name>敏敏</name>
        <sex>女</sex>
        <password>456987</password>
    </user>
</Users>

 4)XML的作用和应用场景

本质是一种数据格式,可以存储复杂的数据结构,和数据关系

应用场景:经常用来做为系统的配置文件;或者作为一种特殊的数据结构,在网络中进行传输

5)解析XML文件

使用程序读取XML文件中的数据

注意:程序员并不需要自己写原始的IO流代码来解析XML,难度较大!也相当繁琐!

其实,有很多开源的,好用的,解析XML的框架,最知名的是:Dom4j(第三方研发的)

Dom4j解析XML-得到Document对象

SAXReader: Dom4j提供的解析器,可以认为是代表整个Dom4j框架

构造器/方法说明
public SAXReader()构建Dom4J的解析器对象
public Document read(String url)把XML文件读成Document对象
public Document read(InputStream is)通过字节输入流读取XML文件

Document

方法名说明
Element getRootElement()获得根元素对象

 Element提供的方法

方法名说明
public String getName( )得到元素名字
public List<Element> elements()得到当前元素下所有子元素
public List<Element> elements(String name)得到当前元素下指定名字的子元素返回集合
public Element element(String name)得到当前元素下指定名字的子元素,如果有很多名字相同的返回第一个
public String attributeValue(String name)通过属性名直接得到属性值
public String elementText(子元素名)得到指定名称的子元素的文本
public String getText()得到文本
public String getTextTrim()取出文本去除前后空格

 如何使用程序把数据写出到XML文件中去?

不建议用dom4j做

推荐直接把程序里的数据拼接成XML格式,然后用IO流写出去

import java.io.BufferedWriter;
import java.io.FileWriter;

public class XML {
    public static void main(String[] args) {
    StringBuilder sb=new StringBuilder();
    sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n");
    sb.append("<Users>\r\n");
    sb.append("<name>").append("张无忌").append("</name>\r\n");
    sb.append("<password>").append("123456").append("<password>\r\n");
    sb.append("<Users>");


        try (BufferedWriter bw = new BufferedWriter(new FileWriter("C:\\" +
                "Users\\Lenovo\\IdeaProjects\\two\\two2\\src\\helloworld.xml"))){
             bw.write(sb.toString());
        } catch (Exception e) {
          e.printStackTrace();;
        }
    }
}

 6)约束XML文件的书写

就是限制XML文件只能按照某种格式进行书写

约束文档

专门用来限制xml书写格式的文档,比如:限制标签、属性应该怎么写

【1】DTD文档

可以约束XML文件的编写

不能约束具体的数据类型

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE 书架 SYSTEM "data.dtd">

【2】Schema文档

可以约束XML文件的编写、和数据类型

2,日志技术

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

程序中的日志,通常就是一个文件,里面记录的是程序运行过程中的各种信息

输出语句的弊端:

1,日志会在控制台

2,不能更方便的将日志记录到其他的位置(文件,数据库)

3,想取消日志,需要修改源代码才可以完成

日志技术:

可以将系统执行的信息,方便的记录到指定的位置(控制台、文件中、数据库中)

可以随时以开关的形式控制日志的启停,无需侵入到源代码中去进行修改

(1)日志技术的体系结构

日志框架:牛人或者第三方公司已经做好的实现代码,后来者直接可以拿去使用

                   1,JUL(Java.util.logging)

                   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的日志规范实现的框架

1)Logback日志框架

模块:1,logback-core        基础模块,是其他两个模块依赖的基础(必须有)

           2,logback-classic        完整实现了slf4j API的模块(必须有)

           3,logback-access        与Tomcat和Jetty 等Servlet容器集成,以提供HTTP访问日志的功能(可选,以后再接触)

想使用Logback日志框架,至少需要以下3个模块:
1,slf4j-api:日志接口

2,logback-core

3,logback-classic

public static final Logger LOGGER = LoggerFactory.getLogger(“类名");

2)核心配置文件logback.xml

对Logback日志框架进行控制的

日志的输出位置、输出格式的设置

通常可以设置2个输出日志的位置:一个是控制台、一个是系统文件中

<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">

<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">

开启日志(ALL),取消日志(OFF)

<root level=ALL">

        <appender-ref ref="CONSOLE"/>

        <appender-ref ref="FILE”/>

< /root>

(2)日志级别

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

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

学习日志级别的原因:

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

3,多线程

线程:线程(Thread)是一个程序内部的一条执行流程

程序中如果只有一条执行流程,那这个程序就是单线程的程序

多线程的定义:

多线程是指从软硬件上实现的多条执行流程的技术(多条线程由CPU负责调度执行)

好处:再例如:消息通信、淘宝、京东系统都离不开多线程技术

如何在程序中创建出多条线程:

Java是通过java.lang.Thread类的对象来代表线程的

线程的创建

1)继承Thread类

1,定义一个子类MyThread继承线程类java.lang.Thread,重写run()方法

2,创建MyThread类的对象

3,调用线程对象的start()方法启动线程(启动后还是执行run方法的)

public class ThreadTest1 {
    public static void main(String[] args) {
        //创建对象
        Thread t=new MyThread();

        t.start();//main线程 t线程

        for (int i = 1; i <=5 ; i++) {
            System.out.println("主线程main线程输出:"+i);
        }
    }
}



class MyThread extends Thread{
    @Override
    public void run() {
        //描述线程的执行任务
        for (int i = 1; i <=5 ; i++) {
            System.out.println("MyThread线程输出:"+i);
        }
    }
}

优点:编码简单

缺点:线程类已经继承Thread,无法继承其他类,不利于功能的扩展

多线程的注意事项:

1、启动线程必须是调用start方法,不是调用run方法

直接调用run方法会当成普通方法执行,此时相当于还是单线程执行

只有调用start方法才是启动一个新的线程执行

2、不要把主线程任务放在启动子线程之前

这样主线程一直是先跑完的,相当于是一个单线程的效果了

2)实现Runnable接口

1,定义一个线程任务类MyRunnable实现Runnable接口,重写run()方法

2,创建MyRunnable任务对象

3,把MyRunnable任务对象交给Thread处理

Thread类提供的构造器说明
public Thread(Runnable target)封装Runnable对象成为线程对象

4,调用线程对象的start()方法启动线程

public class ThreadTest2 {
    public static void main(String[] args) {
        //创建任务对象
        Runnable target=new MyRunnable();
        //把任务对象交给线程对象
        new Thread(target).start();

        for (int i = 1; i <=5 ; i++) {
            System.out.println("主线程main输出===》"+i);
        }
    }
}



class MyRunnable implements Runnable{
    //重写Runnable的run方法
    @Override
    public void run() {
        //线程执行的任务
        for (int i = 1; i <=5 ; i++) {
            System.out.println("子线程输出===》"+i);
        }
    }
}

优点: 任务类只是实现接口,可以继续继承其他类、实现其他接口,扩展性强

缺点:需要多一个Runnable对象

线程创建方式二的匿名内部类写法

1,可以创建Runnable的匿名内部类对象

2,再交给Thread线程对象

3,再调用线程对象的start()启动线程

        Runnable target=new Runnable() {
            @Override
            public void run() {
                for (int i = 1; i <=5 ; i++) {
                    System.out.println("子线程1输出:"+i);
                }
            }
        };
        new Thread(target).start();

        for (int i = 1; i <=5 ; i++) {
            System.out.println("主线程main输出:"+i);
        }


//简化后1
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 1; i <=5 ; i++) {
                    System.out.println("子线程2输出:"+i);
                }
            }
        }).start();

        for (int i = 1; i <=5 ; i++) {
            System.out.println("主线程main输出:"+i);
        }

//简化后2
new Thread(()-> {
                for (int i = 1; i <=5 ; i++) {
                    System.out.println("子线程3输出:"+i);
                }
        }).start();

        for (int i = 1; i <=5 ; i++) {
            System.out.println("主线程main输出:"+i);
        }

3)利用Callable接口,FutureTask类实现

前两种方法的问题:

假如线程执行完毕后有一些数据需要返回,他们重写的run方法均不能直接返回结果

解决方法:

JDK 5.0提供了Callable接口和FutureTask类来实现(多线程的第三种创建方式)

1,创建任务对象

定义一个类实现Callable接口,重写call方法,封装要做的事情,和要返回的数据

把Callable类型的对象封装成FutureTask(线程任务对象)

2,把线程任务对象交给Thread对象

3,调用Thread对象的start方法启动线程

4,线程执行完毕后、通过FutureTask对象的的get方法去获取线程任务执行的结果

public class ThreadTest3 {
    public static void main(String[] args) throws Exception {
        Callable<String> call=new MyCallable(100);
        FutureTask<String> f1 =new FutureTask<>(call);

        new Thread(f1).start();
        
        String rs=f1.get();
        System.out.println(rs);
    }
}



class MyCallable implements Callable<String> {
    private int n;

    public MyCallable(int n) {
        this.n = n;
    }

    @Override
    public String call() throws Exception {
        int sum=0;
        for (int i = 1; i <=n ; i++) {
            sum+=i;
        }

        return "线程求和是:"+sum;
    }
}

FutureTask的API

FutureTask提供的构造器说明
public FutureTask<>(Callable call)把callable对象封装成FutureTask对象
FutureTask提供的方法说明

public v get() throws Exception

获取线程执行call方法返回的结果

优点:

线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强;可以在线程执行完毕后去获取线程执行的结果

缺点:

编码复杂一点

  • 25
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值