muduo库的高性能日志库(二)——LogStream文件

news2024/12/24 8:20:25

目录

  • 概述
  • FixBuffer类(模板缓冲区)
  • LogStream类
    • LogStream.h
    • LogStream.cc
      • 十进制整数转化为字符串
      • 地址(指针)数据转换为16进制字符串
      • 浮点类型数据转化为字符串
  • Fmt类
  • C++单元测试框架(简略)
    • 什么是单元测试
    • 常用测试工具
      • 1.测试的开始与结束
      • 2.验证表达式
      • 3.浮点数比较
  • 测试

概述

该文件下有三个类如下图所示

在这里插入图片描述

FixBuffer类(模板缓冲区)

该类实现为非类型参数的模板类,通过模板传入一个参数来设置实例化参数缓冲区的大小
通过data_,cur_,end()完成对该缓冲区的全部操作

该缓冲区思想极为简单,不过多赘述

//一个模板buffer,Logstream中的类长远变量Buffer是该类的一个实例化
//SIZE指缓冲区大小,实际该类维护了一个SIZE大小的char数组
//通过 data_,cur_.end_完成对缓冲区的各项操作
template<int SIZE>
class FixedBuffer : noncopyable
{
 public:
  FixedBuffer()
    : cur_(data_)
  {
    setCookie(cookieStart);
  }

  ~FixedBuffer()
  {
    setCookie(cookieEnd);
  }


 //将数据写入缓冲区当中
  void append(const char* /*restrict*/ buf, size_t len)
  {
    // FIXME: append partially
    //判断缓冲区剩余空间是否足够
    if (implicit_cast<size_t>(avail()) > len)
    {
      memcpy(cur_, buf, len);
      cur_ += len;
    }
  }


  //返回缓冲区首地址
  const char* data() const { return data_; }
  //返回缓冲区长度
  int length() const { return static_cast<int>(cur_ - data_); }

  // write to data_ directly
  //返回缓冲区可写入的位置(cur_指针指向已写入数据的末尾)
  char* current() { return cur_; }
  //返回空闲缓冲区长度
  int avail() const { return static_cast<int>(end() - cur_); }
  //增加已写入数据的长队,(cur指针往后移)
  void add(size_t len) { cur_ += len; }

  //重置缓冲区(将cur_重新指向开头)
  void reset() { cur_ = data_; }
  //将缓冲区全置空
  void bzero() { memZero(data_, sizeof data_); }

  // for used by GDB
  //供gdb使用
  const char* debugString();
  void setCookie(void (*cookie)()) { cookie_ = cookie; }
  // for used by unit test
  //供单元测试使用
  string toString() const { return string(data_, length()); }
  StringPiece toStringPiece() const { return StringPiece(data_, length()); }

 private:
  const char* end() const { return data_ + sizeof data_; }
  // Must be outline function for cookies.
  static void cookieStart();  //空
  static void cookieEnd();  //空

  void (*cookie_)();
  char data_[SIZE];
  char* cur_;
};

LogStream类

muduo库并没有使用标准库iostream,而是为了出于性能,自己实现了一个Logstream类

设计这个LogStream类,让它如同C++的标准输出流对象cout,能用<<符号接收输入,cout是输出到终端,而LogStream类是把输出保存自己内部的缓冲区,可以让外部程序把缓冲区的内容重定向输出到不同的目标,如文件、终端、socket等。

这个类主要完成了对运算符<<的重载,将输出保存入缓冲区(Buffer_中)

LogStream.h

/该类负责将要记录的数据写入缓冲区(Buffer_)当中对<<操作符进行了重载
//LogStream这个类的重点难点在于重载运算符<<,以整型的<<运算符重载的优化实现,效率高于标准库std::iostream。

class LogStream : noncopyable
{
  typedef LogStream self;
 public:
  typedef detail::FixedBuffer<detail::kSmallBuffer> Buffer;

 //针对各种类型数据eg:short,unsigneg short等对<<运算符进行了重载
 
 //针对bool值
  self& operator<<(bool v)
  {
    buffer_.append(v ? "1" : "0", 1);
    return *this;
  }
  self& operator<<(short);
  self& operator<<(unsigned short);
  self& operator<<(int);
  self& operator<<(unsigned int);
  self& operator<<(long);
  self& operator<<(unsigned long);
  self& operator<<(long long);
  self& operator<<(unsigned long long);

  self& operator<<(const void*);

  self& operator<<(float v)
  {
    *this << static_cast<double>(v);
    return *this;
  }
  self& operator<<(double);
  // self& operator<<(long double);

  self& operator<<(char v)
  {
    buffer_.append(&v, 1);
    return *this;
  }

  // self& operator<<(signed char);
  // self& operator<<(unsigned char);

  self& operator<<(const char* str)
  {
    if (str)
    {
      buffer_.append(str, strlen(str));
    }
    else
    {
      buffer_.append("(null)", 6);
    }
    return *this;
  }

  self& operator<<(const unsigned char* str)
  {
    return operator<<(reinterpret_cast<const char*>(str));
  }

  self& operator<<(const string& v)
  {
    buffer_.append(v.c_str(), v.size());
    return *this;
  }

  self& operator<<(const StringPiece& v)
  {
    buffer_.append(v.data(), v.size());
    return *this;
  }

  self& operator<<(const Buffer& v)
  {
    *this << v.toStringPiece();
    return *this;
  }

 //将数据写入缓冲区当中
  void append(const char* data, int len) { buffer_.append(data, len); }
  //获取缓冲区对象
  const Buffer& buffer() const { return buffer_; }

  //重置缓冲区
  void resetBuffer() { buffer_.reset(); }

 private:
  void staticCheck();


 //将整形转换为字符串的模板函数
  template<typename T>
  void formatInteger(T);

  //缓冲区
  Buffer buffer_;
 
 //最大位数
  static const int kMaxNumericSize = 48;
};

LogStream.cc

十进制整数转化为字符串

思路:先创建一个字符查询表,用于快速找到十进制数字对应的字符
通过余10除10的方法,获取每一位的数字,然后通过查询表,将对应字符存入数组当中
,最后判断正负获得符号位字符,应为是从低位开始存入的,后面需要对该字符数组进行反转。

//创建查询表,
const char digits[] = "9876543210123456789";
const char* zero = digits + 9;
static_assert(sizeof(digits) == 20, "wrong number of digits");

const char digitsHex[] = "0123456789ABCDEF";
static_assert(sizeof digitsHex == 17, "wrong number of digitsHex");

// Efficient Integer to String Conversions, by Matthew Wilson.

//将整形转换为字符串
template<typename T>
size_t convert(char buf[], T value)
{
  T i = value;
  char* p = buf;


 //循环余10除10,得到每一位的数字(从高位开始)
  do
  {
    int lsd = static_cast<int>(i % 10);
    i /= 10;
    //通过查询表获取对应字符
    *p++ = zero[lsd];
  } while (i != 0);


 //获取符号位
  if (value < 0)
  {
    *p++ = '-';
  }
  *p = '\0';

  //前面存储是将低位存在前面的
  //翻转
  std::reverse(buf, p);

  return p - buf;
}

整形数据流式操作方法的实际处理函数

template<typename T>
void LogStream::formatInteger(T v)
{
  if (buffer_.avail() >= kMaxNumericSize) {
    size_t len = convert(buffer_.current(), v);
    buffer_.add(len);
  }
}

地址(指针)数据转换为16进制字符串

实现思路与上相似

size_t convertHex(char buf[], uintptr_t value)
{
  uintptr_t i = value;
  char* p = buf;

  do{
    int lsd = static_cast<int>(i % 16);
    i /= 16;
    *p++ = digitsHex[lsd];
  } while (i != 0);

  *p = '\0';
  std::reverse(buf, p);

  return p - buf;
}

指针数据格式化为16进制字符串实际处理函数

LogStream& LogStream::operator<<(double v)
{
  if (buffer_.avail() >= kMaxNumericSize)
  {
    int len = snprintf(buffer_.current(), kMaxNumericSize, "%.12g", v);
    buffer_.add(len);
  }
  return *this;
}

浮点类型数据转化为字符串

这个就仅仅只是调用了库函数snprintf,
float类型的先强转为double类型,在调用下面的重载

LogStream& LogStream::operator<<(double v)
{
  if (buffer_.avail() >= kMaxNumericSize)
  {
    int len = snprintf(buffer_.current(), kMaxNumericSize, "%.12g", v);
    buffer_.add(len);
  }
  return *this;
}

Fmt类

该类就就实现了将一个数值类型的数据转换为一个长度不超过32位的字符串

//Logstream类并未提供数据类型转换接口
//该类实现了数据格式化,将一个数值类型的数据转换为一个长度不超过32位的字符串
class Fmt // : noncopyable
{
 public:
  template<typename T>
  Fmt(const char* fmt, T val);

  const char* data() const { return buf_; }
  int length() const { return length_; }

 private:
  char buf_[32];
  int length_;
};

inline LogStream& operator<<(LogStream& s, const Fmt& fmt)
{
  s.append(fmt.data(), fmt.length());
  return s;
}

具体实现

template<typename T>
Fmt::Fmt(const char* fmt, T val)
{

  //is_arithmetic是C++11的函数,头文件 <type_traits>
  //功能判断T是否为算数类型(eg:int,double,int_32....)则提供trie的bool值,反之false
  static_assert(std::is_arithmetic<T>::value == true, "Must be arithmetic type");

  length_ = snprintf(buf_, sizeof buf_, fmt, val);
  assert(static_cast<size_t>(length_) < sizeof buf_);
}

// Explicit instantiations
//显示实例化
//(为特定的函数模板生成定义)
template Fmt::Fmt(const char* fmt, char);

template Fmt::Fmt(const char* fmt, short);
template Fmt::Fmt(const char* fmt, unsigned short);
template Fmt::Fmt(const char* fmt, int);
template Fmt::Fmt(const char* fmt, unsigned int);
template Fmt::Fmt(const char* fmt, long);
template Fmt::Fmt(const char* fmt, unsigned long);
template Fmt::Fmt(const char* fmt, long long);
template Fmt::Fmt(const char* fmt, unsigned long long);

template Fmt::Fmt(const char* fmt, float);
template Fmt::Fmt(const char* fmt, double);

C++单元测试框架(简略)

什么是单元测试

复杂的C/C++代码很可能会包含错误,并且在编写代码后尝试对其进行测试类似于在大海捞针。 一种更审慎的方法是通过添加专门针对特定区域的小型(单元)测试来测试编写的各个代码段,例如,一些计算密集型C函数或某些C++类声称对某个数据结构进行建模,例如队列。 然后,以此理念构建的回归套件将具有单元测试的集合以及运行测试并报告结果的测试驱动程序。

常用测试工具

1.测试的开始与结束

BOOST_AUTO_TEST_SUITE (testname)
BOOST_AUTO_TEST_SUITE_END( )

这两个宏分别指示测试套件的开始和结束。
从某种意义上来说有点类似于C++的命名空间

2.验证表达式

BOOST_WARN()
BOOST_CHECK()
BOOST_REQUIRE()

以上三个用与验证表达式
BOOST_CHECK和BOOST_REQUIRE之间的区别在于,在前一种情况下,即使断言失败,测试仍将继续,而在后一种情况下,则认为是严重错误并且测试将停止。

BOOST_REQUIRE()也可以用于检测函数函数和类方法

3.浮点数比较

BOOST_WARN_CLOSE_FRACTION(left-value, right-value, tolerance-limit)
BOOST_CHECK_CLOSE_FRACTION(left-value, right-value, tolerance-limit)
BOOST_REQUIRE_CLOSE_FRACTION(left-value, right-value, tolerance-limit)

使用2中的宏进行浮点数比较是不对的,总是会因为精度问题导致测试过不去
Boost测试实用程序提供了BOOST_WARN_CLOSE_FRACTION,BOOST_CHECK_CLOSE_FRACTION,BOOST_REQUIRE_CLOSE_FRACTION宏。 要使用这三个宏中的任何一个,必须包含预定义的Boost头float_point_comparison.hpp。 这三个宏的语法都相同

前两个参数是要比较的两个数,第三个参数为公差极限(即误差不能超过)

宏中的左值和右值必须是同一类型float或double。

测试

#include "muduo/base/LogStream.h"

#include <limits>
#include <stdint.h>

//#define BOOST_TEST_MODULE LogStreamTest
#define BOOST_TEST_MAIN
#define BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>
#define BOOST_TEST_MODULE First_TestSuite
#include <boost/test/included/unit_test.hpp>
using muduo::string;

BOOST_AUTO_TEST_CASE(testLogStreamBooleans)
{
  muduo::LogStream os;
  const muduo::LogStream::Buffer& buf = os.buffer();
  BOOST_CHECK_EQUAL(buf.toString(), string(""));
  os << true;
  BOOST_CHECK_EQUAL(buf.toString(), string("1"));
  os << '\n';
  BOOST_CHECK_EQUAL(buf.toString(), string("1\n"));
  os << false;
  BOOST_CHECK_EQUAL(buf.toString(), string("1\n0"));
}

BOOST_AUTO_TEST_CASE(testLogStreamIntegers)
{
  muduo::LogStream os;
  const muduo::LogStream::Buffer& buf = os.buffer();
  BOOST_CHECK_EQUAL(buf.toString(), string(""));
  os << 1;
  BOOST_CHECK_EQUAL(buf.toString(), string("1"));
  os << 0;
  BOOST_CHECK_EQUAL(buf.toString(), string("10"));
  os << -1;
  BOOST_CHECK_EQUAL(buf.toString(), string("10-1"));
  os.resetBuffer();

  os << 0 << " " << 123 << 'x' << 0x64;
  BOOST_CHECK_EQUAL(buf.toString(), string("0 123x100"));
}

BOOST_AUTO_TEST_CASE(testLogStreamIntegerLimits)
{
  muduo::LogStream os;
  const muduo::LogStream::Buffer& buf = os.buffer();
  os << -2147483647;
  BOOST_CHECK_EQUAL(buf.toString(), string("-2147483647"));
  os << static_cast<int>(-2147483647 - 1);
  BOOST_CHECK_EQUAL(buf.toString(), string("-2147483647-2147483648"));
  os << ' ';
  os << 2147483647;
  BOOST_CHECK_EQUAL(buf.toString(), string("-2147483647-2147483648 2147483647"));
  os.resetBuffer();

  os << std::numeric_limits<int16_t>::min();
  BOOST_CHECK_EQUAL(buf.toString(), string("-32768"));
  os.resetBuffer();

  os << std::numeric_limits<int16_t>::max();
  BOOST_CHECK_EQUAL(buf.toString(), string("32767"));
  os.resetBuffer();

  os << std::numeric_limits<uint16_t>::min();
  BOOST_CHECK_EQUAL(buf.toString(), string("0"));
  os.resetBuffer();

  os << std::numeric_limits<uint16_t>::max();
  BOOST_CHECK_EQUAL(buf.toString(), string("65535"));
  os.resetBuffer();

  os << std::numeric_limits<int32_t>::min();
  BOOST_CHECK_EQUAL(buf.toString(), string("-2147483648"));
  os.resetBuffer();

  os << std::numeric_limits<int32_t>::max();
  BOOST_CHECK_EQUAL(buf.toString(), string("2147483647"));
  os.resetBuffer();

  os << std::numeric_limits<uint32_t>::min();
  BOOST_CHECK_EQUAL(buf.toString(), string("0"));
  os.resetBuffer();

  os << std::numeric_limits<uint32_t>::max();
  BOOST_CHECK_EQUAL(buf.toString(), string("4294967295"));
  os.resetBuffer();

  os << std::numeric_limits<int64_t>::min();
  BOOST_CHECK_EQUAL(buf.toString(), string("-9223372036854775808"));
  os.resetBuffer();

  os << std::numeric_limits<int64_t>::max();
  BOOST_CHECK_EQUAL(buf.toString(), string("9223372036854775807"));
  os.resetBuffer();

  os << std::numeric_limits<uint64_t>::min();
  BOOST_CHECK_EQUAL(buf.toString(), string("0"));
  os.resetBuffer();

  os << std::numeric_limits<uint64_t>::max();
  BOOST_CHECK_EQUAL(buf.toString(), string("18446744073709551615"));
  os.resetBuffer();

  int16_t a = 0;
  int32_t b = 0;
  int64_t c = 0;
  os << a;
  os << b;
  os << c;
  BOOST_CHECK_EQUAL(buf.toString(), string("000"));
}

BOOST_AUTO_TEST_CASE(testLogStreamFloats)
{
  muduo::LogStream os;
  const muduo::LogStream::Buffer& buf = os.buffer();

  os << 0.0;
  BOOST_CHECK_EQUAL(buf.toString(), string("0"));
  os.resetBuffer();

  os << 1.0;
  BOOST_CHECK_EQUAL(buf.toString(), string("1"));
  os.resetBuffer();

  os << 0.1;
  BOOST_CHECK_EQUAL(buf.toString(), string("0.1"));
  os.resetBuffer();

  os << 0.05;
  BOOST_CHECK_EQUAL(buf.toString(), string("0.05"));
  os.resetBuffer();

  os << 0.15;
  BOOST_CHECK_EQUAL(buf.toString(), string("0.15"));
  os.resetBuffer();

  double a = 0.1;
  os << a;
  BOOST_CHECK_EQUAL(buf.toString(), string("0.1"));
  os.resetBuffer();

  double b = 0.05;
  os << b;
  BOOST_CHECK_EQUAL(buf.toString(), string("0.05"));
  os.resetBuffer();

  double c = 0.15;
  os << c;
  BOOST_CHECK_EQUAL(buf.toString(), string("0.15"));
  os.resetBuffer();

  os << a+b;
  BOOST_CHECK_EQUAL(buf.toString(), string("0.15"));
  os.resetBuffer();

  BOOST_CHECK(a+b != c);

  os << 1.23456789;
  BOOST_CHECK_EQUAL(buf.toString(), string("1.23456789"));
  os.resetBuffer();

  os << 1.234567;
  BOOST_CHECK_EQUAL(buf.toString(), string("1.234567"));
  os.resetBuffer();

  os << -123.456;
  BOOST_CHECK_EQUAL(buf.toString(), string("-123.456"));
  os.resetBuffer();
}

BOOST_AUTO_TEST_CASE(testLogStreamVoid)
{
  muduo::LogStream os;
  const muduo::LogStream::Buffer& buf = os.buffer();

  os << static_cast<void*>(0);
  BOOST_CHECK_EQUAL(buf.toString(), string("0x0"));
  os.resetBuffer();

  os << reinterpret_cast<void*>(8888);
  BOOST_CHECK_EQUAL(buf.toString(), string("0x22B8"));
  os.resetBuffer();
}

BOOST_AUTO_TEST_CASE(testLogStreamStrings)
{
  muduo::LogStream os;
  const muduo::LogStream::Buffer& buf = os.buffer();

  os << "Hello ";
  BOOST_CHECK_EQUAL(buf.toString(), string("Hello "));

  string chenshuo = "Shuo Chen";
  os << chenshuo;
  BOOST_CHECK_EQUAL(buf.toString(), string("Hello Shuo Chen"));
}

BOOST_AUTO_TEST_CASE(testLogStreamFmts)
{
  muduo::LogStream os;
  const muduo::LogStream::Buffer& buf = os.buffer();

  os << muduo::Fmt("%4d", 1);
  BOOST_CHECK_EQUAL(buf.toString(), string("   1"));
  os.resetBuffer();

  os << muduo::Fmt("%4.2f", 1.2);
  BOOST_CHECK_EQUAL(buf.toString(), string("1.20"));
  os.resetBuffer();

  os << muduo::Fmt("%4.2f", 1.2) << muduo::Fmt("%4d", 43);
  BOOST_CHECK_EQUAL(buf.toString(), string("1.20  43"));
  os.resetBuffer();
}

BOOST_AUTO_TEST_CASE(testLogStreamLong)
{
  muduo::LogStream os;
  const muduo::LogStream::Buffer& buf = os.buffer();
  for (int i = 0; i < 399; ++i)
  {
    os << "123456789 ";
    BOOST_CHECK_EQUAL(buf.length(), 10*(i+1));
    BOOST_CHECK_EQUAL(buf.avail(), 4000 - 10*(i+1));
  }

  os << "abcdefghi ";
  BOOST_CHECK_EQUAL(buf.length(), 3990);
  BOOST_CHECK_EQUAL(buf.avail(), 10);

  os << "abcdefghi";
  BOOST_CHECK_EQUAL(buf.length(), 3999);
  BOOST_CHECK_EQUAL(buf.avail(), 1);
}

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

用了CDN就一定比不用更快吗?

对于开发同学来说&#xff0c;CDN这个词&#xff0c;既熟悉又陌生。 平时搞开发的时候很少需要碰这个&#xff0c;但却总能听到别人提起。 我们都听说过它能加速&#xff0c;也大概知道个原因&#xff0c;但是往深了问。 用了CDN就一定比不用更快吗&#xff1f; 就感觉有些…

C++ Reference: Standard C++ Library reference: Containers: deque: deque: cbegin

C官网参考链接&#xff1a;https://cplusplus.com/reference/deque/deque/cbegin/ 公有成员函数 <deque> std::deque::cbegin const_iterator cbegin() const noexcept;返回指向开始的常量迭代器 返回指向容器第一个元素的const_iterator。 const_iterator是指向const内…

大一新生HTML期末作业,实现登录页面

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

js+贝塞尔曲线+animate动画

文章目录一 介绍二 示例1阶贝塞尔曲线2阶贝塞尔曲线3阶贝塞尔曲线:4/n阶贝塞尔曲线三 封装和使用bezier.jsApp.jsxApp.scss一 介绍 贝塞尔曲线(Bzier curve)&#xff0c;又称贝兹曲线或贝济埃曲线&#xff0c;是应用于二维图形应用程序的数学曲线。 下面是我们最常用到bezier曲…

【7-创建商城系统的子模块并将修改后的信息使用Git提交到Gitee上】

一.知识回顾 【0.三高商城系统的专题专栏都帮你整理好了&#xff0c;请点击这里&#xff01;】 【1-系统架构演进过程】 【2-微服务系统架构需求】 【3-高性能、高并发、高可用的三高商城系统项目介绍】 【4-Linux云服务器上安装Docker】 【5-Docker安装部署MySQL和Redis服务】…

测试.net开源敏感词检测库ToolGood.Words

微信公众号“DotNet”看到介绍.net开源敏感词检测库ToolGood.Words的文章《.NET Core一款高性能敏感词检测开源库》&#xff0c;根据参考文献2中的测试&#xff0c;该库的检测效率比C#自带的正则效率高8.8倍&#xff0c;如果数量量越大性能优势越明显。   ToolGood.Words的Gi…

英文Paper写作如何尽量避免抄袭?

说到英文Paper的写作&#xff0c;我们就不得不提到reference&#xff0c;中文称之为引用。在国外&#xff0c;合理正确的利用reference非常重要&#xff0c;国外对于知识产权的保护很严格&#xff0c;对于抄袭行为也是不能容忍的。学术表现差或是学术不诚实问题是造成学生被开除…

4.构造类型,类型转换

构造类型 由若干各个相同或不同类型的数据构成的集合&#xff0c;这种集合类型被称为构造类型 例&#xff1a;int a[10]; 数组、结构体、共用体、枚举 类型转换 数据有不同的类型&#xff0c;不同类型数据之间进行混合运算时必然涉及到类型转换的问题。 转换的方式有两种&am…

使用verdaccio搭建私有组件库

前言 最近公司需要根据现有的公用组件搭建一套私有组件库&#xff0c;方便其他项目使用&#xff0c;然后经过一系列尝试和走了许多坑&#xff0c;终于搭建成功了&#xff0c;这里记录下搭建步骤&#xff0c;希望对你有些帮助。 为什么选择verdaccio 由于公司组件库越来越多&…

ZZNUOJ_Java软件的下载安装和写代码

ZZNUOJ_Java软件的下载安装和写代码一、Java软件myeclipse图标二、下载安装的步骤三、使用myeclipse软件1、创建项目名和类名的步骤2、写代码和运行结果一、Java软件 myeclipse图标 二、下载安装的步骤 第一步骤&#xff1a;下载myeclipse&#xff1a;myeclipse 第二步骤&…

怎么把旧电脑的用户配置文件迁移到新电脑

您购买了一台新笔记本电脑&#xff0c;但不想花大量时间重新下载、编辑、备份旧电脑上的所有文件&#xff0c;也不想重新安装常用的软件&#xff0c;更不想重新配置电脑账户&#xff0c;那么&#xff0c;应该怎么把旧电脑的用户配置文件迁移到新电脑&#xff1f; 一、如何迁移用…

[附源码]java毕业设计基于疫情防控物流管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

BDP 581/591 azide,Bodipy581/591标记叠氮,2183473-20-1

产品名称&#xff1a;Bodipy581/591标记叠氮 英文名称&#xff1a;BDP 581/591 azide CAS&#xff1a;2183473-20-1 BDP 581/591是一种相对疏水的明亮且多用途的荧光团。 结构式&#xff1a; General properties Appearance: dark solid Molecular weight: 474.31 分子式…

中台深入剖析和实现技巧

什么是中台 中台发展史 无共享架构-大烟囱架构 共享架构模式 IaaS架构 PaaS架构 SaaS架构 中台架构 中台定义 中台就是“企业级的能力复用平台”-Thoughtworks 首席咨询师王健 中台是将系统的通用化能力进行打包整合&#xff0c;通过接口的形式赋能到外部系统&#xff0c;从…

jsp教育培训系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 教育培训系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql&#xff0c;使用jav…

[附源码]java毕业设计教务系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

计算机网络:IEEE 802.11无线局域网

文章目录1.无线局域网的组成(1)有固定基础设施无线局域网(2)无固定基础设施移动自组织网络2.802.11局域网的MAC帧1.无线局域网的组成 无线局域网可分为两大类:有固定基础设施的无线局域网和无固定基础设施的移动自组织网络。所谓“固定基础设施”&#xff0c;是指预先建立的、…

[附源码]java毕业设计基于智能推荐的房屋租赁系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Docker(狂神)

Docker概述 Docker为什么出现&#xff1f; 一款产品&#xff1a;开发&#xff0c;上线&#xff0c;两套环境&#xff0c;应用环境&#xff0c;应用配置 开发&#xff0c;运维 环境配置十分麻烦&#xff0c;每一个机器都要部署环境&#xff0c;费时费力。 发布一个项目&#xff…

数据流与重定向,vim练习,grep过滤练习,cut练习

今日作业&#xff1a; 1、重定向练习&#xff1a;将根目录下的文件的文件名写入/test/file文件中&#xff08;先切换到根目录&#xff0c;再查看根目录下的文件名&#xff0c;进行数据重定向&#xff0c;最后查看/test/file文件&#xff09; 2、vim命令练习&#xff1a;将/root…