log4cplus开源库使用

log4cplus 的github地址:https://github.com/log4cplus/log4cplus

下载链接:log4cplus - Browse /log4cplus-stable/2.0.7 at SourceForge.net

官方文档:log4cplus / Wiki / Home

1.log4cplus配置

(1)打开解决方案

打开Visual Studio,进入 log4cplus-2.x\msvc14目录下,运行log4cplus.sln解决方案。

(2)进行相应设置

编译log4cplus需要注意三点:

①解决方案的平台与目标程序一致,这里选择的是x64;

②版本也要与目标程序一致,这里选择的是release版本;

③属性里面的字符集和目标程序一致;

选择log4cplus项目,右键——>属性——>配置属性——>常规——>字符集,选择Unicode字符集,如下图所示。(log4cplus默认使用多字节字符集,而VS新建项目默认使用Unicode字符集,如果不修改此处,则后面新建项目使用生成的dll时需要手动修改新建的项目为多字节字符集,否则会报错,总之两边统一用一种即可)

编译完成后,会在log4cplus-2.x\msvc14\x64\bin.Release文件夹下生成我们需要的log4cplus.lib和log4cplus.dll两个文件(我编译的是release版),如下图所示。

(3)目标程序的配置

将log4cplus-2.0.x目录下的include文件夹拷贝到我们的目标程序文件夹中,这里面是我们需要的头文件;在目标程序的属性里面设置头文件的包含目录。

设置lib文件的库目录以及将lib文件填入附加依赖项,如下图所示。

将dll文件放到程序的根目录:如果运行的是VS放置到和*.vcxproj一个文件夹下,如果运行的是*.exe,则和*.exe放置到一个文件夹下。

右键——>属性——>链接器——>输入——>附加依赖项——>加入log4cplus.lib,如下图所示。

如果不添加上述附加依赖项,则需要在代码开头中添加如下代码:

#pragma comment(lib, "log4cplus.lib")

2.头文件

主要类说明:

类名

说明

Filter

过滤器,过滤输出消息

Layout

布局器,控制输出消息的格式

Appender

挂接器,与布局器和过滤器紧密配合,将特定格式的消息过滤后输出到所挂接的设备终端如屏幕,文件等

Logger

记录器,保存并跟踪对象日志信息变更的实体,当你需要对一个对象进行记录时,就需要生成一个logger。

Hierarchy

分类器,层次化的树型结构,用于对被记录信息的分类,层次中每一个节点维护一个logger的所有信息

LogLevel

优先权,包括TRACE, DEBUG, INFO, WARNING, ERROR, FATAL。

主要头文件如下:

#include <log4cplus/logger.h> //获取表示记录句柄
#include <log4cplus/loggingmacros.h>//这个头文件声明日志记录宏。除此之外,它还声明了若干个标准日志级别:FATAL, ERROR, WARN, INFO, DEBUG, TRACE
#include <log4cplus/configurator.h>//此头文件声明类 BasicConfigurator。
#include <log4cplus/initializer.h>//这个头文件声明类 Initializer。

在log4cplus2中,上述类都已经包含在头文件log4cplus.h中了,因此只需要包含该头文件即可:

#include <log4cplus/log4cplus.h>
3.初始化Initializer

实例化该类会初始化log4cplus Initializer:

log4cplus::Initializer initializer;

该类还维护一个引用计数。该类可以被实例化多次。当此引用计数达到零时,在的最后一个实例被销毁后,它会关闭log4cplus内部。在log4cplus解除初始化后,无法重新初始化。

log4cplus尝试使用其他一些方法关闭其内部。但是,这意味着在main()退出后不能使用它。

4.基本配置BasicConfigurator
log4cplus::BasicConfigurator config;
config.configure();

这两行使用简单的布局配置根记录器。ConsoleAppender

log4cplus::Logger logger = log4cplus::Logger::getInstance(
LOG4CPLUS_TEXT("main"));

这里我们获得名为main的记录器的记录器句柄。上面使用的宏与Windows上的或宏具有相同的功能:如果定义了预处理器符号,它会在作为参数传递的字符串文字前面加上前缀,使其成为宽字符串文字。

LOG4CPLUS_WARN(logger, LOG4CPLUS_TEXT(“Hello, World!”));

这里我们调用宏来记录Hello,World!将消息输入主记录器。记录的消息将从主记录器传播到根记录器,根记录器连接了一个用于在控制台上打印的日志。在内部,这个宏使用C++字符串流来格式化hello, World!消息这样做的结果是,您可以使用所有标准的C++流操作器。

5.取消初始化

log4cplus试图取消初始化(deinitialize),并在退出后释放所有分配的资源。然而,同样,根据编译器、平台和运行时库的不同,这可能是不可能的。这就是为什么适当的去初始化是必要的。

在2.0及更高版本中,它由类的最后一个实例及其析构函数完成。在以前的版本中,调用是正确的关闭方法Logger::shutdown()

6.日志记录宏

宏在hood下使用C++字符串流。

7.日志级别

此示例显示了如何在运行时通过调整实例上的日志级别阈值来过滤日志消息。log4cplus的优先级由低到高:

  • NOT_SET_LOG_LEVEL:接受缺省的LogLevel,如果有父logger则继承它的LogLevel;
  • ALL_LOG_LEVEL:开放所有log信息输出
  • TRACE_LOG_LEVEL:开放trace信息输出(即ALL_LOG_LEVEL)
  • DEBUG_LOG_LEVEL:开放debug信息输出
  • INFO_LOG_LEVEL:开放info信息输出
  • WARN_LOG_LEVEL:开放warning信息输出
  • ERROR_LOG_LEVEL:开放error信息输出
  • FATAL_LOG_LEVEL:开放fatal信息输出
  • OFF_LOG_LEVEL:关闭所有log信息输出

各个logger可以通过setLogLevel设置自己的优先级,当某个logger的LogLevel设置成NOT_SET_LOG_LEVEL时,该logger会继承父logger的优先级,另外,如果定义了重名的多个logger, 对其中任何一个的修改都会同时改变其它logger。

代码示例:

#include <log4cplus/logger.h>
#include <log4cplus/loglevel.h>
#include <log4cplus/loggingmacros.h>
#include <log4cplus/configurator.h>
#include <log4cplus/initializer.h>
#include <iomanip>
#include <iostream>

void printMessages(log4cplus::Logger const & logger)
{
        //使用所有常用日志级别打印信息
        LOG4CPLUS_TRACE(logger, "printMessages()");
        LOG4CPLUS_DEBUG(logger, "This is a DEBUG message");
        LOG4CPLUS_INFO(logger, "This is a INFO message");
        LOG4CPLUS_WARN(logger, "This is a WARN message");
        LOG4CPLUS_ERROR(logger, "This is a ERROR message");
        LOG4CPLUS_FATAL(logger, "This is a FATAL message");
}

void thresholdTest(log4cplus::LogLevel ll)
{
        log4cplus::Logger logger
 = log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("main"));

        //设置日志级别阈值
        logger.setLogLevel(ll);

            //打印信息
        //log4cplus::tcout << log4cplus::getLogLevelManager().toString(ll) << std::endl;

         printMessages(logger);


             std::cout << std::endl;
}

int main()
{
        //初始化
        log4cplus::Initializer initializer;
        //基本配置
        log4cplus::BasicConfigurator config;
        config.configure();

        thresholdTest(log4cplus::TRACE_LOG_LEVEL);//开放trace信息输出
        thresholdTest(log4cplus::DEBUG_LOG_LEVEL);//开放debug信息输出
        thresholdTest(log4cplus::INFO_LOG_LEVEL);//开放info信息输出
        thresholdTest(log4cplus::WARN_LOG_LEVEL);//开放warning信息输出
        thresholdTest(log4cplus::ERROR_LOG_LEVEL);//开放error信息输出
        thresholdTest(log4cplus::FATAL_LOG_LEVEL);//开放fatal信息输出

        return 0;
}
8.Appender输出位置

log4cplus默认将输出到控制台,提供ConsoleAppender用于操作。log4cplus还提供了三个类用于文件操作,它们是FileAppender类、RollingFileAppender类、DailyRollingFileAppender类。

Appender会注册到Logger中,Logger在写日志时,通过继承机制遍历所有注册到它本身和其父节点的Appender(在additivity为true的情况下),调用doAppend()方法,实现日志的写入。在doAppend方法中,若当前Appender注册了Filter,则doAppend还会判断当前日志时候通过了Filter的过滤,通过了Filter的过滤后,如果当前Appender继承自SkeletonAppender,还会检查当前日志级别时候要比当前Appender本身的日志级别阀门要打,所有这些都通过后,才会将LoggingEvent实例传递给Layout实例以格式化成一行日志信息,最后写入相应的目的地,在这些操作中,任何出现的错误都由ErrorHandler字段来处理。

(1)控制台输出ConsoleAppender

参考上文,输出在控制台中。

(2)文件输出FileAppender

FileAppender::FileAppender( const tstring& filename_,std::ios_base::openmode mode_, bool immediateFlush_,bool createDirs_)
  • filename:文件名;
  • mode:文件类型,可选择的文件类型包括app、ate、binary、in、out、trunc,因为实际上只是对stl的一个简单包装,这里就不多讲了。缺省是trunc,表示将先前文件删除;
  • immediateFlush:缓冲刷新标志,如果为true表示每向文件写一条记录就刷新一次缓存,否则直到FileAppender被关闭或文件缓存已满才更新文件,一般是要设置true的,比如你往文件写的过程中出现了错误(如程序非正常退出),即使文件没有正常关闭也可以保证程序终止时刻之前的所有记录都会被正常保存;
  • createDirs:是否创建目录;

输出在文件中,参考代码:

#include <log4cplus/log4cplus.h>

int main()
{
    //用Initializer类进行初始化
    log4cplus::Initializer initializer;

    //第1步:建立ConsoleAppender
    log4cplus::SharedAppenderPtr appender(new log4cplus::FileAppender(LOG4CPLUS_TEXT("E:\\test.log")));

    //第2步:设置Appender的名称和输出格式(SimpleLayout)
    appender->setName(LOG4CPLUS_TEXT("console"));

    log4cplus::tstring pattern = LOG4CPLUS_TEXT("%D{%m/%d/%y %H:%M:%S,%Q} [%t] %-5p %c - %m [%l]%n");
    appender->setLayout(std::unique_ptr<log4cplus::Layout>(new log4cplus::PatternLayout(pattern)));

    //第3步:得到一个Logger实例,并设置其日志输出等级阈值
    log4cplus::Logger logger = log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("test"));
    logger.setLogLevel(log4cplus::INFO_LOG_LEVEL);

    //第4步:为Logger实例添加ConsoleAppender
    logger.addAppender(appender);

    //第5步:使用宏将日志输出
    LOG4CPLUS_INFO(logger, LOG4CPLUS_TEXT("Hello world"));

    return 0;
}

同时输出到控制台和文件,代码示例:

#include <log4cplus/log4cplus.h>

int main()
{
    //用Initializer类进行初始化
    log4cplus::Initializer initializer;

    //第1步:建立ConsoleAppender
    log4cplus::SharedAppenderPtr consoleAppender(new log4cplus::ConsoleAppender);
    log4cplus::SharedAppenderPtr fileAppender(new log4cplus::FileAppender(LOG4CPLUS_TEXT("E:\\test.log")));

    //第2步:设置Appender的名称和输出格式(SimpleLayout)
    consoleAppender->setName(LOG4CPLUS_TEXT("console"));
    consoleAppender->setLayout(std::unique_ptr<log4cplus::Layout>(new log4cplus::SimpleLayout()));

    fileAppender->setName(LOG4CPLUS_TEXT("console"));
    log4cplus::tstring pattern = LOG4CPLUS_TEXT("%D{%m/%d/%y %H:%M:%S,%Q} [%t] %-5p %c - %m [%l]%n");
    fileAppender->setLayout(std::unique_ptr<log4cplus::Layout>(new log4cplus::PatternLayout(pattern)));

    //第3步:得到一个Logger实例,并设置其日志输出等级阈值
    log4cplus::Logger logger = log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("test"));
    logger.setLogLevel(log4cplus::INFO_LOG_LEVEL);

    //第4步:为Logger实例添加ConsoleAppender
    logger.addAppender(consoleAppender);
    logger.addAppender(fileAppender);

    //第5步:使用宏将日志输出
    LOG4CPLUS_INFO(logger, LOG4CPLUS_TEXT("Hello world"));

    return 0;
}

(4)RollingFileAppender

RollingFileAppender可以实现滚动转储的文件操作功能:

RollingFileAppender类可以根据你预先设定的大小来决定是否转储,当超过该大小,后续log信息会另存到新文件中,除了定义每个记录文件的大小之外,你还要确定在RollingFileAppender类对象构造时最多需要多少个这样的记录文件(maxBackupIndex+1),当存储的文件数目超过maxBackupIndex+1时,会删除最早生成的文件,保证整个文件数目等于maxBackupIndex+1。然后继续记录。

RollingFileAppender(
const log4cplus::tstring& filename,
long maxFileSize = 10*1024*1024, // 10 MB
int maxBackupIndex = 1,
bool immediateFlush = true,
bool createDirs = false);
  • filename:文件名;
  • maxFileSize:文件的最大尺寸;
  • maxBackupIndex:最大记录文件数;
  • immediateFlush:缓冲刷新标志;
  • createDirs:创建目录;

(4)DailyRollingFileAppender

DailyRollingFileAppender实现根据频度来决定是否转储的文件转储功能:

DailyRollingFileAppender类可以根据你预先设定的频度来决定是否转储,当超过该频度,后续log信息会另存到新文件中,这里的频度包括:MONTHLY(每月)、WEEKLY(每周)、DAILY(每日)、TWICE_DAILY(每两天)、HOURLY(每时)、MINUTELY(每分)。

需要指出的是这里的"频度"并不是你写入文件的速度,其实是否转储的标准并不依赖你写入文件的速度,而是依赖于写入的那一时刻是否满足了频度条件,即是否超过了以分钟、小时、周、月为单位的时间刻度,如果超过了就另存。

DailyRollingFileAppender(
const log4cplus::tstring& filename,
DailyRollingFileSchedule schedule = DAILY,
bool immediateFlush = true,
int maxBackupIndex = 10,
bool createDirs = false);
  • filename:文件名;
  • schedule:存储频度;
  • immediateFlush:缓冲刷新标志;
  • maxBackupIndex:最大记录文件数;
  • createDirs:创建目录

其中schedule为一个枚举类型,如下

enum DailyRollingFileSchedule { 
MONTHLY, 
WEEKLY, 
DAILY,
TWICE_DAILY, 
HOURLY, 
MINUTELY
};

(5)SocketAppender

log4cplus提供了SocketAppender,实现了C/S方式的日志记录,用于支持重定向到远程服务器。

①客户端程序需要做的工作

定义一个SocketAppender类型的挂接器

SharedAppenderPtr _append(new SocketAppender(host, 8888, "ServerName"));

把该挂接器加入到logger中

Logger::getRoot().addAppender(_append);

SocketAppender类型不需要Layout, 直接调用宏就可以将信息发往loggerServer了

LOG4CPLUS_INFO(Logger::getRoot(), "This is a test: ")

②服务器端程序需要做的工作

定义一个ServerSocket

ServerSocket serverSocket(port);

调用accept函数创建一个新的socket与客户端连接

Socket sock = serverSocket.accept();

此后即可用该sock进行数据read/write了:

     SocketBuffer msgSizeBuffer(sizeof(unsigned int));
     if(!clientsock.read(msgSizeBuffer)){
         return;
     }
     unsigned int msgSize = msgSizeBuffer.readInt();
     SocketBuffer buffer(msgSize);
     if(!clientsock.read(buffer)){
         return;
      }

为了将读到的数据正常显示出来,需要将SocketBuffer存放的内容转换成InternalLoggingEvent格式:

log4cplus::spi::InternalLoggingEvent event = readFromBuffer(buffer);

然后输出:

Logger logger = Logger::getInstance(event.getLoggerName()); logger.callAppenders(event);

注意:read/write是按照阻塞方式实现的,意味着对其调用直到满足了所接收或发送的个数才返回。

9.布局设置

log4cplus通过布局器(Layouts)来控制输出的格式,log4cplus提供了三种类型的Layouts,分别是SimpleLayout、PatternLayout、和TTCCLayout。

(1)SimpleLayout

一种简单格式的布局器,在输出的原始信息之前加上LogLevel和一个"-",如果初始化时没有将布局器附加到挂接器,则默认使用SimpleLayout。

(2)PatternLayout

一种有词法分析功能的模式布局器,类似于C语言的printf()函数,能够对预定义的转换标识符(conversion specifiers)进行解析,转换成特定格式输出。

以下代码片段演示了如何使用PatternLayout。

#include <log4cplus/log4cplus.h>

int main()
{
    //用Initializer类进行初始化
    log4cplus::Initializer initializer;

    //第1步:建立ConsoleAppender
    log4cplus::SharedAppenderPtr appender(new log4cplus::ConsoleAppender());

    //第2步:设置Appender的名称和输出格式(SimpleLayout)
    appender->setName(LOG4CPLUS_TEXT("console"));

    log4cplus::tstring pattern = LOG4CPLUS_TEXT("%D{%m/%d/%y %H:%M:%S,%Q} [%t] %-5p %c - %m [%l]%n");
    appender->setLayout(std::unique_ptr<log4cplus::Layout>(new log4cplus::PatternLayout(pattern)));

    //第3步:得到一个Logger实例,并设置其日志输出等级阈值
    log4cplus::Logger logger = log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("test"));
    logger.setLogLevel(log4cplus::INFO_LOG_LEVEL);

    //第4步:为Logger实例添加ConsoleAppender
    logger.addAppender(appender);

    //第5步:使用宏将日志输出
    LOG4CPLUS_INFO(logger, LOG4CPLUS_TEXT("Hello world"));

    return 0;
}

PatterLayout支持的转换标识符主要包括:

  • "%%",转义为%, 即,std::string pattern = “%%” 时输出"%"。
  • "%c",输出logger名称,比如std::string pattern ="%c" 时输出: “test_logger.subtest”, 也可以控制logger名称的显示层次,比如"%c{1}“时输出"test_logger”,其中数字表示层次。
  • "%D",显示本地时间,当std::string pattern ="%D" 时输出:“2004-10-16 18:55:45”,%d显示标准时间,所以当std::string pattern ="%d" 时输出 “2004-10-16 10:55:45” (因为北京时间位于东8区,差8个小时)。
  • 可以通过%d{…}定义更详细的显示格式,比如%d{%H:%M:%s}表示要显示小时:分钟:秒。大括号中可显示的预定义标识符如下:
  • %a – 表示礼拜几,英文缩写形式,比如"Fri"
  • %A – 表示礼拜几,比如"Friday"
  • %b – 表示几月份,英文缩写形式,比如"Oct"
  • %B – 表示几月份,“October”
  • %c – 标准的日期+时间格式,如 “Sat Oct 16 18:56:19 2004”
  • %d – 表示今天是这个月的几号(1-31)“16”
  • %H – 表示当前时刻是几时(0-23),如 “18”
  • %I – 表示当前时刻是几时(1-12),如 “6”
  • %j – 表示今天是哪一天(1-366),如 “290”
  • %m – 表示本月是哪一月(1-12),如 “10”
  • %M – 表示当前时刻是哪一分钟(0-59),如 “59”
  • %p – 表示现在是上午还是下午, AM or PM
  • %q – 表示当前时刻中毫秒部分(0-999),如 “237”
  • %Q – 表示当前时刻中带小数的毫秒部分(0-999.999),如 “430.732”
  • %S – 表示当前时刻的多少秒(0-59),如 “32”
  • %U – 表示本周是今年的第几个礼拜,以周日为第一天开始计算(0-53),如 “41”
  • %w – 表示礼拜几,(0-6, 礼拜天为0),如 “6”
  • %W – 表示本周是今年的第几个礼拜,以周一为第一天开始计算(0-53),如 “41”
  • %x – 标准的日期格式,如 “10/16/04”
  • %X – 标准的时间格式,如 “19:02:34”
  • %y – 两位数的年份(0-99),如 “04”
  • %Y – 四位数的年份,如 “2004”
  • %Z – 时区名,比如 “GMT”
  • "%F",输出当前记录器所在的文件名称,比如std::string pattern ="%F" 时输出: “main.cpp”。
  • "%L",输出当前记录器所在的文件行号,比如std::string pattern ="%L" 时输出: “51”
  • "%l",输出当前记录器所在的文件名称和行号,比如std::string pattern ="%L" 时输出"main.cpp:51"。
  • "%m",输出原始信息,比如std::string pattern ="%m" 时输出: “teststr”,即上述代码中LOG4CPLUS_DEBUG的第二个参数,这种实现机制可以确保原始信息被嵌入到带格式的信息中。
  • "%n",换行符,没什么好解释的。
  • "%p",输出LogLevel,比如std::string pattern ="%p" 时输出: “DEBUG”。
  • "%t",输出记录器所在的线程ID,比如std::string pattern ="%t" 时输出: “1075298944”。
  • "%x",嵌套诊断上下文NDC (nested diagnostic context) 输出,从堆栈中弹出上下文信息,NDC可以用对不同源的log信息(同时地)交叉输出进行区分,关于NDC方面的详细介绍会在下文中提到。
  • 格式对齐,比如std::string pattern ="%-10m"时表示左对齐,宽度是10,此时会输出"teststr “,当然其它的控制字符也可以相同的方式来使用,比如”%-12d","%-5p"等等。

(3)TTCCLayout

TTCCLayout是在PatternLayout基础上发展的一种缺省的带格式输出的布局器, 其格式由时间,线程ID,Logger和NDC 组成(consists of time, thread, Logger and nested diagnostic context information, hence the name),因而得名。

10.基本步骤

使用log4cplus有六个基本步骤:

  1. 实例化一个封装了输出介质的appender对象;
  2. 实例化一个封装了输出格式的layout对象;
  3. 将layout对象绑定(attach)到appender对象;如省略此步骤,简单布局器SimpleLayout(参见5.1小节)对象会绑定到logger。
  4. 实例化一个封装了日志输出logger对象,并调用其静态函数getInstance()获得实例,log4cplus::Logger::getInstance(“logger_name”);
  5. 将appender对象绑定(attach)到logger对象;
  6. 设置logger的优先级,如省略此步骤,各种有限级的日志都将被输出。

代码示例:

#include <log4cplus/log4cplus.h>


int main()
{
    //用Initializer类进行初始化
    log4cplus::Initializer initializer;

    //第1步:创建ConsoleAppender(实例化一个appender对象)
    log4cplus::SharedAppenderPtr appender(new log4cplus::ConsoleAppender());

    //第2步:设置Appender的名称和输出格式(SimpleLayout)
    appender->setName(LOG4CPLUS_TEXT("console"));

    //第3步:实例化一个layout对象,将layout对象绑定到appender对象
    appender->setLayout(std::unique_ptr<log4cplus::Layout>(new log4cplus::SimpleLayout));

    //第4步:实例化一个封装了日志输出的Logger对象,并设置其日志输出等级阈值
    log4cplus::Logger logger = log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("test"));

    //第5步:将appender对象绑定到logger对象
    logger.addAppender(appender);

    //第6步:设置日志log的优先级
    logger.setLogLevel(log4cplus::INFO_LOG_LEVEL);

    //使用宏将日志输出
    LOG4CPLUS_INFO(logger, LOG4CPLUS_TEXT("Hello world"));

    return 0;
}
11.注意事项

(1)如果使用ConsoleAppender()默认参数,那么控制台消息不会实时输出,需要等到缓冲区达到一定大小才会输出。当时这个可调试了好一会。因为我当时需要的效果就是实时输出到控制台与文件。代码如下:

log4cplus::SharedAppenderPtr append_console(new log4cplus::ConsoleAppender(false,true));

(2)输出数字、字符、字符串的方法如下:

    //第5步:使用宏将日志输出
    //数字输出
    for(int i=0; i<10; ++i)
    {
        LOG4CPLUS_INFO(logger, "Entering loop #" << i);
    }
    //字符输出
    char x='i';
    LOG4CPLUS_INFO(logger, "Entering loop #" << x);
    //字符串输出
    std::string y="xyz";
    LOG4CPLUS_INFO(logger, "Entering loop #" << LOG4CPLUS_C_STR_TO_TSTRING(y));

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/352947.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

迷人的数据结构:揭秘数组和链表的不同

数据结构中的数组和链表的区别 一、简介二、数组的特点和特性三、链表的特点和特性四、数组和链表的对比五、数组和链表的代码实现六、总结 一、简介 数据结构是组织和存储数据的方式&#xff0c;直接影响着程序性能、内存利用和资源管理等关键方面。 数据结构提供了各种方法来…

写点东西《JavaScript 中的递归》

写点东西《JavaScript 中的递归》 您是否曾经发现自己需要在 JavaScript 中循环遍历一个复杂的多维对象&#xff0c;却不知道如何操作&#xff1f; 那么&#xff0c;递归函数到底是什么&#xff1f; 让我们回到我们的树对象。 为什么使用递归&#x1f31f;更多精彩 您是否曾经发…

【前端web入门第二天】01 html语法实现列表与表格

html语法实现列表与表格 文章目录: 1.列表 1.1 无序列表1.2 有序列表1.3 定义列表 2.表格 2.1 表格基本结构2.2 表格结构标签 写在最前,第二天学习目标: 列表 表格 表单 元素为嵌套关系 1.列表 作用:布局内容排列整齐的区域。 列表分类:无序列表、有序列表、定义列表。 1…

动态规划算法题刷题笔记

首先看动态规划的三要素&#xff1a;重叠子问题、最优子结构和状态转移方程。 重叠子问题&#xff1a;存在大量的重复计算 最优子结构&#xff1a; 状态转移方程&#xff1a;当前状态转移成以前的状态 动态规划的解题步骤主要有&#xff1a; 确定 dp 数组以及下标的含义状…

HTML新手教程

HTML入门 教程&#xff1a;【狂神说Java】HTML5完整教学通俗易懂_哔哩哔哩_bilibili 一.初识HTML HyperTextMarkupLanguage&#xff08;超文本标记语言&#xff09; 超文本包括&#xff1a;文字、图片、音频、视频、动画。 HTML5的优势 世界知名浏览器厂商对HTML5的支持市场的…

Spring: alibaba代码规范校验工具checkstyle

文章目录 一、idea配置checkstyle插件二、激活CheckStyle三、配置自动格式化功能四、使用代码格式化 一、idea配置checkstyle插件 下载 Intellij IDEA Checkstyle 插件&#xff1a;File -> setting -> plugin通过关键字CheckStyle-IDEA搜索并安装。 安裝完成后重启idea…

【复现】万户ezoffice协同管理平台 任意文件读取漏洞_30

目录 一.概述 二 .漏洞影响 三.漏洞复现 1. 漏洞一&#xff1a; 四.修复建议&#xff1a; 五. 搜索语法&#xff1a; 六.免责声明 一.概述 万户ezOFFICE协同管理平台分为企业版和政务版。 解决方案由五大应用、两个支撑平台组成&#xff0c;分别为知识管理、工作流程、沟…

Linux cat,tac,more,head,tail命令 查看文本

目录 一. cat 和 tac命令二. head 和 tail 命令三. more命令 一. cat 和 tac命令 cat&#xff1a;用来打开文本文件&#xff0c;从上到下的顺序显示文件内容。tac&#xff1a;用法和cat相同&#xff0c;只不过是从下到上逆序的方式显示文件内容。当文件的内容有很多的时候&…

LiveGBS流媒体平台GB/T28181常见问题-如何快速查看推流上来的摄像头并停止摄像头推流?

LiveGBS流媒体平台GB/T28181常见问题-如何快速查看推流上来的摄像头并停止摄像头推流&#xff1f; 1、负载信息2、负载信息说明3、会话列表查看3.1、会话列表 4、停止会话5、搭建GB28181视频直播平台 1、负载信息 实时展示直播、回放、播放、录像、H265、级联等使用数目 2、负…

Linux下的进程操作

进程概念 ps -elf&#xff1a;查看操作系统的所有进程&#xff08;Linux命令&#xff09; ctrl z&#xff1a;把进程切换到后台 crtl c&#xff1a;结束进程 fg&#xff1a;把进程切换到前台 获取进程进程号和父进程号 函数原型&#xff1a; pid_t getpid(void); //pid_t…

【阻塞队列】阻塞队列的模拟实现及在生产者和消费者模型上的应用

文章目录 &#x1f4c4;前言一. 阻塞队列初了解&#x1f346;1. 什么是阻塞队列&#xff1f;&#x1f345;2. 为什么使用阻塞队列&#xff1f;&#x1f966;3. Java标准库中阻塞队列的实现 二. 阻塞队列的模拟实现&#x1f35a;1. 实现普通队列&#x1f365;2. 实现队列的阻塞功…

美赛注意事项

2024年1月27日 &#xff1a; 赖维杰 同学分享 1、最后的展现必须要漂亮&#xff08;绘图、呈现&#xff09; 李维情 西北建模王 论文位&#xff08;核心&#xff09;必须清楚建模位、编程位知道做了些什么 常见模型&#xff1a; 1、看真题&#xff0c;读往年论文&#xff0c;选…

计算机找不到ucrtbased.dll无法运行程序,分享5种有效的解决方法

当计算机系统在运行过程中无法找到ucrtbased.dll这个特定的动态链接库文件时&#xff0c;可能会引发一系列的问题和故障现象。ucrtbased.dll是Windows操作系统中一个至关重要的组件&#xff0c;它包含了C运行时库的核心函数&#xff0c;对于许多应用程序特别是基于Microsoft Vi…

vue中的computed

目录 一&#xff1a;介绍 二&#xff1a;例子演示 一&#xff1a;介绍 在 Vue.js 中&#xff0c;computed 属性是一种特殊类型的属性&#xff0c;它允许你声明依赖于其他数据属性的值。computed 属性的值是通过一个函数计算得出的&#xff0c;这个函数可以在其依赖的数据发生…

【misc | CTF】攻防世界 适合作为桌面

天命&#xff1a;这题还挺繁琐的&#xff0c;知识点还不少 目录 步骤1&#xff1a;图片隐写 步骤2&#xff1a;Winhex查看ascii码 步骤1&#xff1a;图片隐写 拿到这张图片&#xff0c;不可能扔进ps会有多图层&#xff0c;普通图片也就一个图层而已 但居然可以有隐写图片这…

I/O多路复用

简介&#xff1a; I/O 多路复用(I/O 多路转接)使得程序能同时监听多个文件描述符&#xff0c;能够提高程序的性能&#xff0c;Linux 下实现 I/O 多路复用的系统调用主要有 select 、 poll 和 epoll 。 select &#xff1a; 主旨思想&#xff1a; 1. 首先要构造一个关于文…

查询排序(2)

Oracle从入门到总裁:https://blog.csdn.net/weixin_67859959/article/details/135209645 1.选择部门 30 中的所有员工 SQL> select *2 from emp3 where deptno 30;EMPNO ENAME JOB MGR HIREDATE SAL COMM …

《动手学深度学习(PyTorch版)》笔记2

Chapter2 Preliminaries 2.1 Automatic Differentiation 让计算机实现微分功能&#xff0c; 有以下四种方式&#xff1a; - 手工计算出微分&#xff0c; 然后编码进代码 - 数值微分 (numerical differentiation) - 符号微分 (symbolic differentiation) - 自动微分&#xff0…

搜维尔科技:【简报】元宇宙数字人赛道,《莉思菱娜》

个性有些古灵精怪时儿安静时而吵闹&#xff0c;虽然以人类寿命来算已经200多岁但在 吸血鬼中还只是个小毛头&#xff0c;从中学开始喜欢打扮偏爱黑白灰色系的服装喜欢时 尚圈&#xff0c;立志想成为美妆或时尚网红不过目前还是学生&#xff0c;脸上的浅色血迹是纹身 贴纸&#…

Javat集合之Lis---(ArrayList和LinkedList)

文章目录 一、 List概述1.1概念1.2list体系结构图1.3 通用方法测试代码 二、List的特点三、遍历方式foreachfor循环迭代器 四、ArrayListArrayList概述概念数据结构 ArrayList的特点 ArrayList去重字符串去重对象去重 五、LinkedListLinkedList概述概念数据结构LinkedList的特点…