关于Qt中进行输出的方式及对比分析

devtools/2024/10/22 12:59:27/

本文详细介绍了在Qt框架和C++标准库中可用的多种输出流方式,主要分为标准C++输出和Qt输出两大类。

摘要

标准C++输出
  1. std::cout:用于标准输出,支持多种数据类型,是C++最常用的输出流。结合std::stringQString(需转换)和C++20的std::format可方便地进行格式化输出。

  2. std::cerr:专门用于输出错误信息和警告,无缓冲,信息立即显示,适合紧急错误报告。

  3. std::clog:用于输出日志信息,缓冲输出,支持重定向到文件或其他输出设备。

  4. std::ofstream:用于将数据写入文件,支持文本和二进制模式,继承自std::ostream

  5. std::ostringstream:将输出重定向到内存中的字符串对象,支持动态字符串拼接。

  6. std::fstream:同时支持文件读写操作,继承自std::iostream

Qt输出
  1. QTextStream:Qt框架中的文本流类,支持多种数据源,自动处理字符编码转换,适合处理多字节字符文本。

  2. qDebug:用于输出调试信息,支持多种数据类型,输出到标准错误或配置的其他位置。

  3. qInfo、qWarning、qCritical、qFatal:分别以不同日志级别输出信息,qFatal会导致程序终止。这些函数允许通过Qt的消息处理系统定制日志输出行为。

文章还讨论了各输出方式的适用场景、特点、注意事项及示例代码,帮助开发者根据具体需求选择合适的输出方式。特别是在处理文件输出、调试信息、日志记录等场景时,提供了详细的指导和建议。

目录

1.标准C++输出

1.1 std::cout

结合std::string使用

结合QString(Qt库)使用

使用 std::format(C++20 及以上)

1.2 std::cerr

特点与使用场景

自定义错误类

与日志库结合

1.3 std::clog

特点与适用场景

1.4 std::ofstream

特点及使用场景

注意事项

1.5 std::ostringstream

特点及适用场景

注意事项

与std::ofstream相似的地方

使用示例对比

2. Qt输出方式

2.1 QTextStream

特点

适用场景

编码转换

注意事项

2.2 qDebug

特点

适用场景

注意事项

其他相关函数:qInfo()、qWarning() 和 qCritical()


在Qt框架中,C++可以支持的输出流有很多种方法。除了使用标准的std::cout来在控制台输出字符串之外,Qt 提供了多种其他方式来进行输出,下面分别介绍这些方式,并给出示例代码以及适合的使用场景。

首先上一张大致的导图,从图中可看出输出方式分为两大类:标准C++输出和Qt框架封装的输出方式。

输出流方式  
├── 标准C++输出流  
│   ├── std::cout  
│   ├── std::cerr  
│   ├── std::clog  
│   ├── std::ofstream  
│   ├── std::ostringstream  
│   └── std::fstream  
└── Qt输出流  ├── QTextStream  ├── qDebug  ├── qWarning  ├── qCritical  └── qFatal

1.标准C++输出

1.1 std::cout

std::cout 是 C++ 标准库中常用的输出流对象,用于将数据输出到标准输出(通常是控制台)。以下是一些结合 std::stringQString、以及 C++20 中引入的 std::format 等常用实例代码,展示如何更友好地编码和使用 std::cout

  • 适合使用场景:标准输出,用于打印普通的信息和结果。
  • 特点:缓冲输出,性能较好,支持多种数据类型,是C++标准库中最常用的输出流。
  • C++标准:自C++98起便已成为标准输出流的一部分,广泛应用于各种C++程序中。

结合std::string使用

#include <iostream>  
#include <string>  int main() {  std::string message = "Hello, World!";  std::cout << message << std::endl;  return 0;  
}

结合QString(Qt库)使用

为了使用 QString 与 std::cout 一起工作,你需要将 QString 转换为 std::string。下面是一个简单的例子:

#include <iostream>  
#include <QString>  
#include <string>  int main() {  QString qstr = "Hello, Qt!";  std::string str = qstr.toStdString();  std::cout << str << std::endl;  return 0;  
}

既然可以使用std::string可以输出,为何还需要使用QString呢?

  1. 与 Qt API 的兼容性:Qt 的大部分 API 都使用 QString 作为字符串参数。如果你尝试将 std::string 直接传递给 Qt 函数,你可能需要进行额外的转换,这会增加代码的复杂性。

  2. 国际化支持QString 提供了对 UTF-16 编码的内部支持,这对于处理多语言和国际化文本非常有用。它还提供了许多与文本处理相关的功能,如字符串拆分、搜索和替换,这些功能在处理多语言文本时非常方便。

  3. 跨平台性:Qt 是一个跨平台框架,QString 被设计为在不同平台上提供一致的字符串处理行为。虽然 std::string 也是跨平台的,但它不提供与平台相关的字符串处理功能(如字符编码转换)。

  4. 性能:在某些情况下,QString 的性能可能优于 std::string,特别是在处理大量文本或进行频繁的字符串操作时。这是因为 QString 使用了隐式共享(implicit sharing)和写时复制(copy-on-write)机制来优化内存使用和性能。

使用 std::format(C++20 及以上)

C++20 引入了 std::format,它提供了一个更现代的方式来格式化字符串,避免了使用多个"<<"来使得代码可读性差的问题。以下是一个使用 std::format 的例子:

#include <iostream>  
#include <format>  int main() {  std::string name = "Alice";  int age = 30;  std::string message = std::format("Name: {}, Age: {}", name, age);  std::cout << message << std::endl;  return 0;  
}

或者:

#include <iostream>  
#include <string>  
#include <format>  int main() {  std::string name = "Bob";  double height = 1.85;  std::string message = std::format("Name: {}, Height: {:.2f} meters", name, height);  std::cout << message << std::endl;  return 0;  
}

注意:如果你的编译器还不支持 C++20,你可能需要使用一个支持该标准的编译器,比如最新版本的 GCC、Clang 或 MSVC。

需要注意的:

  • 换行和缩进:合理地使用换行和缩进可以使代码更清晰易读。
  • 避免过长的行:尽量保持每行代码的长度适中,以便于阅读和理解。
  • 使用常量或变量:对于重复使用的字符串或数值,使用常量或变量可以提高代码的可维护性。

1.2 std::cerr

std::cerr 是 C++ 标准库中的一个输出流对象,专门用于输出错误信息和警告消息到标准错误输出(通常是控制台或日志文件)。与 std::cout 不同,std::cerr 不经过缓冲区,这意味着它输出的信息会立即显示,而不会因为缓冲区未刷新而延迟。这一特性在输出错误信息时尤为重要,因为用户需要及时看到错误以便进行调试或采取相应措施。

特点与使用场景

  • 无缓冲:直接输出到标准错误,不经过缓冲区。
  • 默认初始化:与 std::cout 一样,std::cerr 在程序启动时自动初始化,无需手动打开或关闭。
  • 标准错误输出:通常映射到操作系统的标准错误输出流,这使得它易于在命令行或日志文件中捕获错误信息。

使用 std::cerr 输出错误信息非常简单,只需像使用 std::cout 一样使用流操作符即可。例如:

#include <iostream>  int main() {  int result = someFunctionThatMightFail();  if (result != 0) {  std::cerr << "Error: Function failed with code " << result << std::endl;  }  return 0;  
}

在这个例子中,如果 someFunctionThatMightFail 函数返回非零值,表示出错,那么错误信息会立即且无缓冲地输出到标准错误。在使用第三方库或自定义类时,你可能需要将错误信息格式化或与其他信息结合输出。以下是一些建议,以使 std::cerr 的输出更友好和方便:

使用格式化库:C++20 引入了 std::format,可以用于格式化字符串。例如:

#include <iostream>  
#include <format>  int main() {  int errorCode = 42;  std::cerr << std::format("Error: Function failed with code {}", errorCode) << std::endl;  return 0;  
}

对于老版本的 C++,可以使用 printf 风格的格式化,但参考官方文档,它不是类型安全的,不建议使用。

自定义错误类

#include <iostream>  
#include <string>  class MyError {  
public:  int code;  std::string message;  MyError(int c, const std::string& m) : code(c), message(m) {}  
};  std::ostream& operator<<(std::ostream& os, const MyError& err) {  os << "Error: Code=" << err.code << ", Message=" << err.message;  return os;  
}  int main() {  MyError error(42, "Something went wrong");  std::cerr << error << std::endl;  return 0;  
}

与日志库结合

  • 使用像 spdloglog4cpp 或 Boost.Log 这样的日志库,这些库通常提供了更高级的错误日志记录功能,包括日志级别、时间戳、线程信息等。

  • 将 std::cerr 用于简单的错误输出,而将更复杂的日志记录需求交给专业的日志库。

#include <iostream>  
#include "spdlog/spdlog.h" // 示例使用 spdlog  int main() {  // 初始化 spdlog  spdlog::info("Starting application...");  int result = someFunctionThatMightFail();  if (result != 0) {  spdlog::error("Function failed with code {}", result);  // 如果需要,仍然可以使用 std::cerr 进行简单输出  std::cerr << "Function failed! Check logs for details." << std::endl;  }  return 0;  
}

1.3 std::clog

std::clog 是 C++ 标准库中的一个输出流对象,用于输出日志信息。与 std::cout 和 std::cerr 类似,std::clog 也是 std::ostream 的一个实例,因此支持流操作符(如 <<)进行输出操作。

特点与适用场景

  • 日志输出
    • std::clog 主要用于输出程序的日志信息,帮助开发者跟踪程序的运行状态和事件。
  • 日志重定向:由于 std::clog 的输出目标是标准错误设备,它支持重定向。这意味着你可以将日志信息重定向到文件或其他输出设备,以便进行日志文件的生成和分析。
  • 缓冲输出
    • 与 std::cerr 不同,std::clog 是缓冲的。这意味着输出的内容首先存储在内部缓冲区中,直到缓冲区满或显式刷新缓冲区时才会输出到标准错误设备。可以显式刷新缓冲区(如使用 std::clog.flush())或输出换行符(如使用 std::endl)来确保日志信息及时输出。
  • 标准错误设备
    • 默认情况下,std::clog 的输出目标通常是控制台或终端,但也可以重定向到文件或其他输出设备。
#include <iostream>  int main() {  std::clog << "This is a log message." << std::endl;  // 其他程序逻辑...  std::clog << "Another log message." << std::endl;  return 0;  
}

在这个例子中,两条日志信息会被输出到标准错误设备。由于 std::clog 是缓冲的,这些输出可能不会立即显示,直到缓冲区被刷新(如遇到换行符或显式调用 std::clog.flush())。

1.4 std::ofstream

std::ofstream 是 C++ 标准库中的一个输出文件流类,它提供了将内存中的数据写入到磁盘文件的功能。

特点及使用场景

  • 文件输出:专门用于将数据写入文件,支持文本和二进制模式。
  • 继承自std::ostream:作为 std::ostream 的派生类,std::ofstream 继承了所有标准输出流的功能,如使用 << 运算符进行输出。
  • 灵活的打开方式:可以通过构造函数或 open 成员函数以不同的模式打开文件,如写入模式(std::ios::out)、追加模式(std::ios::app)和二进制模式(std::ios::binary)等。
  • 自动资源管理std::ofstream 的析构函数会自动关闭文件,但建议显式调用 close 成员函数以确保数据正确写入并释放系统资源。
#include <fstream> // 包含 ofstream 头文件  
#include <iostream>  int main() {  // 创建 ofstream 对象并打开文件  std::ofstream ofs("example.txt");  // 检查文件是否成功打开  if (ofs.is_open()) {  // 写入数据到文件  ofs << "Hello, World!" << std::endl;  // 关闭文件  ofs.close();  std::cout << "Data written to file successfully." << std::endl;  } else {  std::cerr << "Failed to open the file." << std::endl;  }  return 0;  
}

注意事项

  • 文件打开模式:确保以正确的模式打开文件。例如,如果需要追加数据到文件末尾,应使用 std::ios::app 模式(移动开发)。
  • 错误处理:始终检查文件是否成功打开,并在写入数据后关闭文件。可以使用 is_open 成员函数检查文件是否打开成功,并使用 close 成员函数显式关闭文件。
  • 缓冲机制std::ofstream 是缓冲的,这意味着写入的数据可能暂时存储在内部缓冲区中,直到缓冲区满或显式刷新时才会写入文件。如果需要立即写入数据,可以调用 flush ()或使用 std::endl(它会在输出后自动刷新缓冲区)。
  • 线程安全:在多线程环境中使用 std::ofstream 时,需要注意线程安全问题。多个线程同时写入同一个文件流可能会导致数据不一致或竞态条件。可以使用互斥锁(如 std::mutex)来保护对 std::ofstream 对象的访问。

此外,同std::clog一样,它可实现更复杂的文件输出功能。例如,在日志记录场景中,可以将 std::ofstream 与日志库(如 spdloglog4cpp 或 Boost.Log)结合使用,以便将日志信息写入文件。以下是一个简单的使用 spdlog 和 std::ofstream 的示例:

#include <fstream>  
#include <spdlog/spdlog.h>  
#include <spdlog/sinks/basic_file_sink.h>  int main() {  // 创建一个 ofstream 对象并打开文件  std::ofstream ofs("app.log");  // 检查文件是否成功打开  if (ofs.is_open()) {  // 创建一个自定义的 file_sink,将输出重定向到 ofstream 对象  auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(ofs);  // 创建一个 logger,并将 file_sink 添加到其中  auto logger = std::make_shared<spdlog::logger>("custom_logger", file_sink);  // 设置 logger 的级别(可选)  logger->set_level(spdlog::level::info);  // 将自定义的 logger 注册到 spdlog 全局注册表  spdlog::register_logger(logger);  // 使用 logger 输出日志信息  spdlog::get("custom_logger")->info("This is a log message written to a file using ofstream and spdlog.");  // 关闭文件(注意:在 spdlog 的使用场景中,通常不需要手动关闭文件,因为 spdlog 会管理文件的生命周期)  // ofs.close();  std::cout << "Log message written to file successfully." << std::endl;  } else {  std::cerr << "Failed to open the log file." << std::endl;  }  return 0;  
}

1.5 std::ostringstream

std::ostringstream 是 C++ 标准库中的一个输出字符串流类,它与前面的std::ofstream一样,继承自 std::ostream 并专门用于将数据写入内存中的字符串流。

特点及适用场景

  • 内存中的字符串流
    • std::ostringstream 将所有输出操作存储在一个字符串对象中,而不是直接输出到控制台或文件。
  • 动态字符串拼接
    • 通过使用流操作符 <<,可以方便地将不同类型的数据拼接成一个字符串,无需手动管理格式字符串和类型转换。
  • 继承自 std::ostream
    • 继承了 std::ostream 的所有操作符和功能,如流操作符 <<,用于将各种数据类型流入。
  • 内部缓冲区
    • 使用一个内部缓冲区来存储数据,直到调用 str() 方法获取最终的字符串。
#include <iostream>  
#include <sstream> // 包含 ostringstream 头文件  int main() {  std::ostringstream oss;  // 插入不同类型的数据  int num = 42;  double pi = 3.14159;  std::string text = "Hello, ";  oss << num << " " << pi << " " << text << "World!";  // 获取最终的字符串  std::string result = oss.str();  // 输出结果  std::cout << result << std::endl; // 输出: 42 3.14159 Hello, World!  return 0;  
}

注意事项

  • 缓冲区管理
    • std::ostringstream 使用内部缓冲区来存储数据。在不需要时,应及时清空或重置缓冲区以避免内存泄漏。
  • 区域设置
    • std::ostringstream 可以根据区域设置进行格式化输出。使用 imbue 方法可以设置流的区域信息,如千位分隔符、小数点符号等。
  • 性能考虑
    • 虽然 std::ostringstream 提供了方便的字符串拼接功能,但在性能敏感的场景下,应谨慎使用以避免不必要的性能开销。

1.6 std::fstream

std::fstream 和 std::ofstream 都是 C++ 标准库 <fstream> 中定义的流类,用于文件输入输出操作。它们之间既有相似之处,也存在些许不同。

与std::ofstream相似的地方

  • 继承关系
    • std::ofstream 继承自 std::ostream,专门用于文件输出操作。
    • std::fstream 则继承自 std::iostream,而 std::iostream 是 std::istream 和 std::ostream 的基类。因此,std::fstream 同时具备输入和输出功能。
  • 文件操作
    • 两者都可以通过文件路径来创建文件流对象,并使用相同的成员函数来进行文件的读写操作。
    • 都支持以多种模式打开文件,如文本模式、二进制模式、追加模式等。
  • 流操作符
    • 两者都支持使用流操作符 << 和 >> 进行数据的写入和读取(尽管 std::ofstream 主要用于写入,但理论上也可以读取,只是不常用)。

与std::ofstream不同之处

  • 主要功能
    • std::ofstream 是专门用于文件输出的类,它只能进行写入操作。如果尝试从 std::ofstream 对象中读取数据,将会导致未定义行为。
    • std::fstream 则是一个通用的文件流类,既可以用于文件输入,也可以用于文件输出。通过指定不同的打开模式,可以灵活地切换输入和输出操作。
  • 默认行为
    • std::ofstream 对象在创建时默认以写入方式打开文件。如果文件不存在,将尝试创建新文件;如果文件已存在,将清空文件内容(除非指定了追加模式)。
    • std::fstream 对象在创建时不会默认打开文件,需要通过调用 open 方法或构造函数中的参数来指定打开模式和文件路径。
  • 使用场景
    • std::ofstream 适用于只需要进行文件写入的场景,如生成日志文件、保存配置信息等。
    • std::fstream 则适用于需要同时进行文件读写操作的场景,如修改配置文件、处理数据文件等。

使用示例对比

#include <iostream>  
#include <fstream>  
#include <string>  int main() {  // 使用 std::ofstream 进行文件写入操作  {  std::ofstream ofs("output.txt");  if (ofs.is_open()) {  ofs << "This is a test line written by std::ofstream." << std::endl;  ofs.close();  } else {  std::cerr << "Failed to open output file." << std::endl;  }  }  // 使用 std::fstream 进行文件读写操作  {  std::fstream fs("output.txt", std::ios::in | std::ios::out | std::ios::app);  if (fs.is_open()) {  std::string line;  // 读取文件内容  while (std::getline(fs, line)) {  std::cout << line << std::endl;  }  // 追加写入新内容  fs << "This is an appended line written by std::fstream." << std::endl;  fs.close();  } else {  std::cerr << "Failed to open file for read/write operations." << std::endl;  }  }  return 0;  
}

2. Qt输出方式

2.1 QTextStream

特点

QTextStream是Qt框架中用于文本输入输出操作的类。它提供了方便的方法来处理文本数据,支持多种数据源,如文件、标准输入输出设备以及QString对象。QTextStream内部使用Unicode编码,能够自动处理字符编码转换问题,并且支持多种文本格式化选项。

适用场景

QTextStream适用于需要进行文本处理的场景,如文件读写、控制台输入输出、日志记录等。它特别适合于处理包含多字节字符(如中文、日文等)的文本数据,因为它能够自动处理字符编码转换,避免了手动编码解码的繁琐。

#include <QFile>  
#include <QTextStream>  
#include <QDebug>  int main() {  // 打开文件进行写入  QFile file("output.txt");  if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {  QTextStream out(&file);  out << "Hello, Qt!" << endl;  file.close();  } else {  qDebug() << "Failed to open file for writing:" << file.errorString();  }  // 打开文件进行读取  if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {  QTextStream in(&file);  QString line;  while (!in.atEnd()) {  line = in.readLine();  qDebug() << line;  }  file.close();  } else {  qDebug() << "Failed to open file for reading:" << file.errorString();  }  return 0;  
}

编码转换

QTextStream默认使用本地编码读写文件,但可以通过setCodec方法来设置特定的编码格式。比如设置为Windows 默认控制台输出使用的GBK方式,解决汉字乱码问题。

QTextStream out(&file);  
out.setCodec("GBK");

这样,当使用<<操作符向QTextStream写入数据时,它将会使用UTF-8编码格式。同样地,如果从文件中读取数据并使用UTF-8编码格式解码,可以这样做:

QTextStream in(&file);  
in.setCodec("UTF-8");

注意事项

  • 编码一致性:在读写文本文件时,需要确保使用的编码格式一致,否则可能会导致乱码问题。
  • 错误处理:在进行文件操作时,可能会遇到各种错误(如文件不存在、权限不足等)。因此,应该适时检查QFile对象的错误状态,并通过file.error()file.errorString()方法获取错误码和错误描述。
  • 性能考虑:在处理大量文本数据时,考虑到I/O性能,尽量减少不必要的读写操作,可以合理利用缓冲技术,一次性读写较大的数据块。

2.2 qDebug

qDebug() 是 Qt 框架中用于输出调试信息的便捷函数。它可以将各种类型的数据以文本形式输出到标准错误输出(stderr)或配置的其他位置(如文件)。

特点

  • 多类型支持qDebug() 可以输出基本数据类型(如 int、float、double、char*)、字符串(QString)、以及复杂的自定义类型(如果它们支持流输出或提供了相应的重载函数)。
  • 自动转换:输出时,qDebug() 会自动调用类型的 toString() 方法(如果存在)或适当的转换函数,将数据类型转换为字符串表示形式。
  • 灵活输出:支持使用操作符 << 来连接要输出的项,类似于标准 C++ 输出流 std::cout
  • 格式化定制:默认情况下,qDebug() 的输出格式是简单的文本形式,但可以通过格式化字符串或使用 QString::arg() 方法来定制输出格式。

适用场景

  • 调试信息输出:在开发过程中,qDebug() 常用于输出调试信息,帮助开发者快速定位问题。
  • 日志记录:虽然 qDebug() 主要用于调试,但在某些情况下,它也可以用作简单的日志记录工具。
#include <QCoreApplication>  
#include <QDebug>  int main(int argc, char *argv[]) {  QCoreApplication a(argc, argv);  // 输出基本数据类型  qDebug() << "Int:" << 42;  qDebug() << "Float:" << 3.14f;  qDebug() << "Double:" << 3.14159;  qDebug() << "Char pointer:" << "Hello, qDebug!";  // 输出QString  QString name = "World";  qDebug() << "QString:" << name;  // 输出复杂类型(以QPoint为例)  QPoint p(10, 20);  qDebug() << "QPoint:" << p;  return a.exec();  
}

注意事项

  • 编码转换qDebug() 默认使用程序的当前编码输出调试信息。如果需要输出特定编码的文本,可能需要手动进行编码转换。
  • 性能考虑:虽然 qDebug() 非常方便,但在生产环境中频繁使用可能会影响性能。因此,建议在发布版本时去掉或限制调试信息的输出。
  • 条件编译:为了方便在调试和发布版本之间切换,可以使用条件编译指令(如 #ifdef DEBUG)来控制 qDebug() 的输出。

2.3 其他相关函数:qInfoqWarning、qCritical、qFatal

qInfo()qWarning() 和 qCritical()、qFatal()它们分别以不同的日志级别输出信息,并允许通过 Qt 的消息处理系统进一步定制日志输出行为。

函数用途输出级别程序行为影响发布版本保留
qInfo输出提示信息提示
qWarning输出警告信息警告
qCritical输出错误信息错误
qFatal处理严重错误,终止程序致命错误程序终止

qInfoqWarningqCriticalqFatal 是 Qt 框架中提供的用于输出不同级别信息的函数。它们分别用于输出提示、警告、错误和致命错误信息,帮助开发者或用户了解程序的运行状态和潜在问题。在使用时,应根据信息的严重性和程序的需求选择合适的函数。特别是在发布版本中,应谨慎使用 qInfoqWarning 和 qCritical,以免影响程序性能或泄露敏感信息。而 qFatal 则应在确实遇到无法恢复的致命错误时使用,以确保程序的安全终止。


http://www.ppmy.cn/devtools/127837.html

相关文章

迅为RK3562开发板/核心板240PIN引脚全部引出,产品升级自如

可应用于人脸跟踪、身体跟踪、视频监控、自动语音识别(ASR)、图像分类驾驶员辅助系统(ADAS)、车牌识别、物体识别等。 iTOP-3562开发板/核心板采用瑞芯微RK3562处理器&#xff0c;内部集成了四核A53Mali G52架构&#xff0c;主频2GHZ&#xff0c;内置1TOPSNPU算力&#xff0c;R…

docker/docker-compose里面Command和entrypoint的关系

在Docker中&#xff0c;ENTRYPOINT和CMD都是用于指定容器启动时要执行的命令或程序的关键指令。它们之间的关系如下&#xff1a; 1. **ENTRYPOINT**&#xff1a; - ENTRYPOINT用于指定容器启动时要执行的主要命令或程序。它可以设置容器的主要可执行文件&#xff0c;在运行…

为什么要做PFAS测试?PFAS检测项目详细介绍

PFAS测试之所以重要&#xff0c;主要归因于PFAS&#xff08;全氟和多氟化合物&#xff09;的广泛存在、持久性、生物累积性和潜在的毒性。这些特性使得PFAS在环境和人体中可能长期存在&#xff0c;并对生态系统和人类健康构成威胁。以下是对PFAS检测项目的详细介绍以及进行PFAS…

关于懒汉饿汉模式下的线程安全问题

1.java标准库中的线程安全 java标准库中有很多的都是线程不安全的&#xff0c;这些类可能会涉及到多线程修改共享数据&#xff0c;又没有任何加锁措施&#xff0c;如下所示&#xff1a; 上面的这些类中都没有进行任何的加锁限制&#xff0c;因此线程不安全&#xff0c;但是还有…

Maplibre-gl\Mapbox-gl改造支持对矢量瓦片加密

Maplibre-gl是Mapbox-gl剔除自带地图服务之后的一个分支,代码很相似。Maplibre-gl\Mapbox-gl使用的pbf格式的矢量瓦片,数据量小,渲染效果好。但也存在着信息泄露的风险。但如果想使用这个开发框架的前端渲染效果,还必须要使用这个格式。最近研究了一下如何对矢量瓦片进行加…

【国产化信创平台】Linux系统设置程序 开机自启

目录 一、创建编辑自启服务文件 步骤1&#xff1a;创建服务文件 步骤2&#xff1a;编辑服务文件 步骤3&#xff1a;重新加载systemd并启用服务 二、自启动展示​编辑 一、创建编辑自启服务文件 要在Linux系统中配置一个开机启动服务&#xff0c;你需要创建一个 systemd 服…

vue3如何运用组合式写法,封装表格列表请求数据的逻辑

1.代码如下&#xff1a; import { getPageList } from "/api/cloudExhibitionHall" import { ref, watch } from "vue"// 特殊参数传参 const role JSON.parse(localStorage.getItem(current-role) || {}) const tenantId role.tenantId ? role.tenant…

Java Spring的常用注解详解和案例示范

1. Spring 常用注解概述 1.1 Component Component 是 Spring 的基础注解之一&#xff0c;它用于将类标记为 Spring 容器中的一个组件。通过 Component 注解&#xff0c;Spring 会自动将该类注册为一个 Bean&#xff0c;供依赖注入使用。 使用示例&#xff1a; Component pu…