C++ 异常处理机制:异常捕获、自定义异常与实战应用
本文介绍 C++ 异常处理机制,涵盖 try-catch-throw 语法、标准异常库使用及自定义异常类设计。通过实战案例演示文件读写中的异常安全处理,结合 RAII 模式与智能指针避免资源泄漏。同时讲解 noexcept 关键字、异常传播规则及最佳实践,帮助开发者提升代码健壮性与容错能力。

本文介绍 C++ 异常处理机制,涵盖 try-catch-throw 语法、标准异常库使用及自定义异常类设计。通过实战案例演示文件读写中的异常安全处理,结合 RAII 模式与智能指针避免资源泄漏。同时讲解 noexcept 关键字、异常传播规则及最佳实践,帮助开发者提升代码健壮性与容错能力。

try-catch-throw 语句的执行流程,能够正确捕获和处理标准异常noexcept 关键字的使用场景核心重点:try-catch 捕获规则、自定义异常的继承设计、异常安全保障、实战场景中的异常处理策略
异常处理是 C++ 中处理程序运行时错误的机制,核心是'将错误检测与错误处理分离'——在程序出错的地方(如除以零、内存分配失败)'抛出'异常,在合适的地方(如主函数、业务逻辑层)'捕获'并处理异常,避免程序直接崩溃,提升代码健壮性。
生活中的异常类比:
在异常处理出现前,程序通常通过返回值判断是否出错,但存在明显缺陷:
// 传统错误处理:通过返回值判断(缺陷明显)
int divide(int a, int b) {
if (b == 0) {
return -1; // 用 -1 表示错误,但 -1 可能是合法计算结果
}
return a / b;
}
int main() {
int result = divide(10, 0);
if (result == -1) {
cout << "除数不能为 0!" << endl;
} else {
cout << "结果:" << result << endl;
}
return 0;
}
传统错误处理的缺陷:
-1 可能是 divide(-5,5) 的合法结果)异常处理的优势:
C++ 异常处理依赖三个核心关键字:
throw:抛出异常(检测到错误时,触发异常)try:尝试执行可能抛出异常的代码块(异常检测范围)catch:捕获并处理异常(匹配对应的异常类型,执行处理逻辑)核心流程:try 块中执行代码 → 若发生错误,throw 抛出异常 → 程序跳转到最近的匹配 catch 块 → 执行 catch 中的处理逻辑 → 处理完成后,程序从 catch 块后继续执行
try {
// 可能抛出异常的代码块
可能出错的操作;
if (错误条件) {
throw 异常值; // 抛出异常(异常值可是任意类型:int、string、自定义类等)
}
} catch (异常类型 1 异常变量) {
// 处理异常类型 1 的逻辑
} catch (异常类型 2 异常变量) {
// 处理异常类型 2 的逻辑
} catch (...) {
// 捕获所有未匹配的异常(兜底处理)
}
语法解析:
try 块:必须紧跟一个或多个 catch 块,不能单独存在throw 表达式:可抛出任意类型的值(基本类型、字符串、自定义类),抛出后立即终止当前函数执行,跳转到匹配的 catch 块catch 块:按顺序匹配异常类型,匹配成功则执行对应处理逻辑;catch (...) 是万能捕获,需放在所有 catch 块最后catch (int) 可省略变量名),用于获取抛出的异常信息示例:基本异常处理流程(除数为 0 异常)
#include <iostream>
using namespace std;
int divide(int a, int b) {
if (b == 0) {
// 抛出异常:异常类型为 string,携带错误信息
throw string("错误:除数不能为 0!");
}
return a / b;
}
int main() {
int x = 10, y = 0;
try {
cout << "尝试执行除法运算..." << endl;
int result = divide(x, y); // 可能抛出异常
cout << x << " / " << y << " = " << result << endl; // 若抛出异常,此句不执行
} catch (const string& err_msg) {
// 捕获 string 类型异常
cout << "捕获到异常:" << err_msg << endl; // 处理异常
} catch (...) {
// 兜底捕获所有其他异常
cout << "捕获到未知异常!" << endl;
}
cout << "程序继续执行..." << endl; // 异常处理后,程序继续运行
return 0;
}
运行结果:
尝试执行除法运算...
捕获到异常:错误:除数不能为 0!
程序继续执行...
执行流程拆解:
try 块,执行 divide(10, 0)divide 函数检测到 b=0,throw 抛出 string 类型异常try 块执行,跳转到 main 函数中最近的 catch 块catch 块匹配 string 类型异常,执行处理逻辑(打印错误信息)catch 块执行完成后,程序从 catch 块后继续执行(打印'程序继续执行…')catch 块按声明顺序匹配异常类型,匹配规则如下:
catch 声明类型完全一致(如 throw int(5) 匹配 catch (int))catch 块捕获(如自定义异常类继承自 exception,可被 catch (exception&) 捕获)char 可转换为 int,但 int 不能转换为 double)catch (...) 匹配所有未被前面 catch 块捕获的异常,必须放在最后警告:catch 块的声明顺序至关重要,若将基类异常的 catch 块放在派生类之前,会导致派生类异常被基类 catch 块捕获,派生类的 catch 块永远无法执行:
// 错误示例:基类 catch 在前,派生类 catch 无法执行
class BaseException {};
class DerivedException : public BaseException {};
try {
throw DerivedException();
} catch (BaseException& e) {
// 先匹配基类,派生类异常被捕获
cout << "基类异常" << endl;
} catch (DerivedException& e) {
// 永远无法执行
cout << "派生类异常" << endl;
}
C++ 标准库提供了一系列预定义的异常类,均继承自 std::exception 基类,定义在 <exception> 头文件中,常用标准异常如下:
| 异常类 | 描述 | 适用场景 |
|---|---|---|
std::exception | 所有标准异常的基类 | 兜底捕获标准异常 |
std::logic_error | 逻辑错误(编译期可检测,但未避免) | 如无效参数、非法状态 |
std::invalid_argument | 无效参数错误 | 如向函数传递非法参数 |
std::out_of_range | 超出范围错误 | 如数组索引越界、string 下标越界 |
std::runtime_error | 运行时错误(编译期无法检测) | 如除以零、文件打开失败 |
std::overflow_error | 溢出错误 | 如数值计算溢出 |
std::bad_alloc | 内存分配失败错误 | 如 new 分配内存失败 |
示例:使用标准异常类
#include <iostream>
#include <exception> // 包含标准异常头文件
#include <vector>
using namespace std;
int main() {
vector<int> nums = {1, 2, 3};
try {
// 尝试访问超出 vector 范围的元素(触发 out_of_range 异常)
cout << "访问索引 3 的元素:" << nums.at(3) << endl;
// at() 方法会抛出 out_of_range 异常,[] 运算符不会抛出异常
} catch (const out_of_range& e) {
// what() 方法返回异常描述信息(继承自 exception 基类)
cout << "捕获到 out_of_range 异常:" << e.what() << endl;
} catch (const exception& e) {
// 兜底捕获其他标准异常
cout << "捕获到标准异常:" << e.what() << endl;
}
try {
// 模拟内存分配失败(触发 bad_alloc 异常)
while (true) {
new int[1024 * 1024]; // 不断分配内存,直到耗尽
}
} catch (const bad_alloc& e) {
cout << "捕获到 bad_alloc 异常:" << e.what() << endl;
}
return 0;
}
运行结果:
捕获到 out_of_range 异常:vector::_M_range_check: __n (which is 3) >= this->size() (which is 3)
捕获到 bad_alloc 异常:std::bad_alloc
技巧:标准异常类的 what() 方法返回 C 风格字符串(const char*),包含异常的简要描述,可用于日志输出或用户提示。
标准异常类虽能满足常见场景,但实际开发中,我们常需要自定义异常(如业务相关的'用户不存在异常''权限不足异常'),自定义异常类需遵循以下原则:
std::exception 或其派生类),便于统一捕获what() 方法,返回自定义的异常描述信息UserNotFoundException)示例:实现业务相关的自定义异常类
#include <iostream>
#include <exception>
#include <string>
using namespace std;
// 1. 基础业务异常类(继承自 std::exception)
class BusinessException : public exception {
private:
string err_msg; // 异常描述信息
public:
// 构造函数:带错误信息
BusinessException(const string& msg) : err_msg(msg) {}
// 重写 what() 方法(必须是 const noexcept,符合基类接口)
const char* what() const noexcept override {
return err_msg.c_str(); // 返回 C 风格字符串
}
};
// 2. 派生异常类:用户不存在异常
class UserNotFoundException : public BusinessException {
public:
// 构造函数:接收用户 ID,拼接错误信息
UserNotFoundException(int user_id) : BusinessException("用户不存在:ID=" + to_string(user_id)) {}
};
// 3. 派生异常类:权限不足异常
class PermissionDeniedException : public BusinessException {
public:
// 构造函数:接收用户名和操作,拼接错误信息
PermissionDeniedException(const string& username, const string& operation)
: BusinessException("权限不足:用户\"" + username + "\"无法执行\"" + operation + "\"操作") {}
};
// 模拟业务函数:根据用户 ID 查询用户
void query_user(int user_id) {
// 模拟用户不存在的场景
if (user_id < 1000 || user_id > 9999) {
throw UserNotFoundException(user_id); // 抛出用户不存在异常
}
cout << "查询成功:用户 ID=" << user_id << endl;
}
// 模拟业务函数:执行敏感操作
void execute_sensitive_operation(const string& username) {
// 模拟权限校验
if (username != "admin") {
throw PermissionDeniedException(username, "删除数据"); // 抛出权限不足异常
}
cout << "操作成功:用户\"" << username << "\"执行删除数据操作" << endl;
}
int main() {
try {
query_user(123); // 抛出 UserNotFoundException
} catch (const UserNotFoundException& e) {
cout << "业务异常:" << e.what() << endl;
} catch (const BusinessException& e) {
// 捕获其他业务异常
cout << "业务异常:" << e.what() << endl;
} catch (const exception& e) {
// 捕获标准异常
cout << "系统异常:" << e.what() << endl;
}
cout << endl;
try {
execute_sensitive_operation("test"); // 抛出 PermissionDeniedException
} catch (const PermissionDeniedException& e) {
cout << "业务异常:" << e.what() << endl;
} catch (const BusinessException& e) {
cout << "业务异常:" << e.what() << endl;
} catch (const exception& e) {
cout << "系统异常:" << e.what() << endl;
}
return 0;
}
运行结果:
业务异常:用户不存在:ID=123
业务异常:权限不足:用户"test"无法执行"删除数据"操作
std::exception,可与标准异常一起捕获,统一异常处理逻辑注意事项:
what() 方法必须重写为 const noexcept,符合 std::exception 基类的接口规范catch (const Exception& e)),避免拷贝开销,且支持多态匹配noexceptC++11 前,可通过 throw(类型列表) 声明函数可能抛出的异常类型,称为'异常规格说明':
// 声明该函数仅可能抛出 int 和 string 类型异常
void func() throw(int, string) {
// 函数体
}
// 声明该函数不抛出任何异常(等价于 noexcept(true))
void func2() throw() {
// 函数体
}
缺陷:
std::unexpected() 函数,默认终止程序noexcept 关键字noexcept 关键字(C++11 及以上)noexcept 用于声明函数是否可能抛出异常,语法更简洁、功能更明确:
// 声明函数不会抛出任何异常(推荐)
void func() noexcept {
// 函数体
}
// 声明函数可能抛出异常(等价于不写 noexcept)
void func2() noexcept(false) {
// 函数体
}
// 条件式 noexcept:当 T 的移动构造函数不抛出异常时,当前函数也不抛出
template<typename T>
void func3() noexcept(noexcept(T(std::move(T())))) {
// 函数体
}
noexcept 的核心作用:
noexcept,编译器可省略异常处理相关的代码(如栈展开),提升性能std::vector 的 push_back 若元素的移动构造函数是 noexcept,会使用移动语义(更高效),否则使用拷贝语义警告:若 noexcept 函数实际抛出了异常,程序会调用 std::terminate() 终止,无法通过 try-catch 捕获,因此需确保 noexcept 函数确实不会抛出异常。
异常抛出后,若当前函数没有匹配的 catch 块,异常会向上传播到调用该函数的上层函数,直到找到匹配的 catch 块;若传播到 main 函数仍未捕获,程序会调用 std::terminate() 终止。
示例:异常跨函数传播
#include <iostream>
#include <string>
using namespace std;
void func3() {
cout << "func3:抛出异常" << endl;
throw string("来自 func3 的异常");
}
void func2() {
cout << "func2:调用 func3" << endl;
func3(); // 调用可能抛出异常的函数,自身无 catch 块
cout << "func2:执行完毕(不会执行)" << endl;
}
void func1() {
cout << "func1:调用 func2" << endl;
try {
func2(); // 调用 func2,可能传播异常
} catch (const int& e) {
cout << "func1:捕获 int 类型异常" << endl;
}
cout << "func1:执行完毕" << endl;
}
int main() {
cout << "main:调用 func1" << endl;
try {
func1();
} catch (const string& e) {
// 捕获从 func3 传播过来的 string 类型异常
cout << "main:捕获 string 类型异常:" << e << endl;
} catch (...) {
cout << "main:捕获未知异常" << endl;
}
cout << "main:程序结束" << endl;
return 0;
}
运行结果:
main:调用 func1
func1:调用 func2
func2:调用 func3
func3:抛出异常
main:捕获 string 类型异常:来自 func3 的异常
main:程序结束
有时需要在 catch 块中处理部分逻辑后,将异常重新抛出给上层函数处理,使用 throw; (不带参数)实现:
示例:异常重新抛出
#include <iostream>
#include <string>
using namespace std;
void process_data(int data) {
if (data < 0) {
throw string("数据非法:负数不允许");
}
cout << "数据处理成功:" << data << endl;
}
void handle_request(int data) {
try {
process_data(data);
} catch (const string& e) {
// 局部处理:记录异常日志
cout << "日志记录:发生异常 - " << e << endl;
// 重新抛出异常,让上层函数处理
throw;
}
}
int main() {
try {
handle_request(-5);
} catch (const string& e) {
// 上层处理:提示用户
cout << "用户提示:操作失败,原因:" << e << endl;
}
return 0;
}
运行结果:
日志记录:发生异常 - 数据非法:负数不允许
用户提示:操作失败,原因:数据非法:负数不允许
注意事项:
throw; 重新抛出的是原始异常对象,不会创建新的异常对象catch 块外使用 throw;,会抛出 std::bad_exception 异常异常安全是指程序抛出异常时,确保:
// 异常安全问题:内存泄漏
void unsafe_func() {
int* p = new int(10); // 分配内存
process_data(-5); // 可能抛出异常
delete p; // 若抛出异常,此句不执行,内存泄漏
}
std::unique_ptr、std::shared_ptr)会在析构时自动释放内存,即使发生异常也不会泄漏vector、string)均具备异常安全性,避免手动管理资源示例:使用智能指针保证异常安全
#include <iostream>
#include <memory> // 包含智能指针头文件
#include <string>
using namespace std;
void safe_func() {
// 使用 unique_ptr 管理内存,自动释放
unique_ptr<int> p(new int(10));
// 模拟抛出异常
throw string("测试异常安全");
// 无需手动 delete,智能指针析构时自动释放内存
}
int main() {
try {
safe_func();
} catch (const string& e) {
cout << "捕获异常:" << e << endl;
}
// 内存已被智能指针释放,无泄漏
return 0;
}
示例:RAII 模式管理文件资源
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
// RAII 类:管理文件资源
class FileGuard {
private:
ofstream file; // 文件流对象(资源)
public:
// 构造函数:获取资源(打开文件)
FileGuard(const string& filename) : file(filename) {
if (!file.is_open()) {
throw string("文件打开失败:" + filename);
}
cout << "文件打开成功:" << filename << endl;
}
// 析构函数:释放资源(关闭文件)
~FileGuard() {
if (file.is_open()) {
file.close();
cout << "文件关闭成功" << endl;
}
}
// 提供文件写入接口
void write(const string& content) {
file << content << endl;
}
};
void write_file(const string& filename, const string& content) {
FileGuard file(filename); // 构造时打开文件
file.write(content);
throw string("模拟写入过程中异常"); // 抛出异常
// 异常抛出后,FileGuard 对象析构,文件自动关闭
}
int main() {
try {
write_file("test.txt", "Hello, 异常安全!");
} catch (const string& e) {
cout << "捕获异常:" << e << endl;
}
return 0;
}
运行结果:
文件打开成功:test.txt
文件关闭成功
捕获异常:模拟写入过程中异常
结论:即使在写入过程中抛出异常,FileGuard 对象会被析构,文件资源被正确释放,实现了异常安全。
将异常用于正常的控制流(如判断函数返回结果),导致代码效率降低、可读性变差:
// 错误示例:用异常处理正常逻辑
int find_element(const vector<int>& vec, int target) {
for (int i = 0; i < vec.size(); ++i) {
if (vec[i] == target) {
return i;
}
}
throw string("元素未找到"); // 不推荐:元素未找到是正常场景,非异常
}
使用 catch (...) 捕获所有异常,但未做任何处理,导致问题排查困难:
// 错误示例:捕获异常后忽略
try {
risky_operation();
} catch (...) {
// 无任何处理,异常被'吞掉'
}
抛出基本类型(如 int、double)或未继承自 std::exception 的自定义类,导致异常处理不统一:
// 不推荐:抛出 int 类型异常
void func() {
throw 5; // 异常类型不明确,难以统一处理
}
按值捕获异常(catch (BaseException e)),而非按引用捕获,导致派生类异常的特有信息丢失:
// 错误示例:按值捕获导致切片
class DerivedException : public BaseException {
public:
const char* what() const noexcept override {
return "派生类异常";
}
};
try {
throw DerivedException();
} catch (BaseException e) {
// 按值捕获,派生类对象被切片为基类对象
cout << e.what() << endl; // 输出基类的 what() 信息,而非派生类
}
仅在'异常情况'(如内存分配失败、非法参数、IO 错误)使用异常,正常控制流(如元素未找到、用户输入错误)使用返回值或其他方式处理。
std::exception使用 catch (const Exception& e) 捕获异常,避免拷贝开销和对象切片,支持多态匹配。
catch 块顺序catch 块放在前面catch 块放在后面catch (...) 作为兜底,放在最后,并记录日志或终止程序捕获异常后,记录详细的异常信息(如异常类型、错误描述、发生位置、调用栈),便于问题排查。
析构函数若抛出异常,可能导致程序终止(如在栈展开过程中,析构函数抛出异常会调用 std::terminate()):
// 错误示例:析构函数抛出异常
class BadClass {
public:
~BadClass() {
throw string("析构函数异常"); // 危险!
}
};
实现一个文件读写工具类,支持读取文件内容和写入文件内容,要求:
std::exception):FileOpenException(文件打开失败)、FileReadException(文件读取失败)、FileWriteException(文件写入失败)FileHandler,管理文件流资源read_file 和 write_file 方法,抛出对应的自定义异常#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <exception>
using namespace std;
// 1. 自定义文件异常基类(继承自 std::exception)
class FileException : public exception {
protected:
string err_msg; // 异常描述信息
public:
FileException(const string& filename, const string& reason) {
err_msg = "文件操作异常:文件\"" + filename + "\", 原因:" + reason;
}
const char* what() const noexcept override {
return err_msg.c_str();
}
};
// 2. 派生异常:文件打开失败
class FileOpenException : public FileException {
public:
FileOpenException(const string& filename, const string& reason)
: FileException(filename, "打开失败 - " + reason) {}
};
// 3. 派生异常:文件读取失败
class FileReadException : public FileException {
public:
FileReadException(const string& filename, const string& reason)
: FileException(filename, "读取失败 - " + reason) {}
};
// 4. 派生异常:文件写入失败
class FileWriteException : public FileException {
public:
FileWriteException(const string& filename, const string& reason)
: FileException(filename, "写入失败 - " + reason) {}
};
// 5. 文件工具类(RAII 模式)
class FileHandler {
private:
string filename; // 文件名
fstream file_stream; // 文件流(资源)
public:
// 构造函数:打开文件
FileHandler(const string& filename, ios_base::openmode mode) : filename(filename) {
file_stream.open(filename, mode);
// 检查文件是否打开成功
if (!file_stream.is_open()) {
throw FileOpenException(filename, "无法打开文件(可能不存在或权限不足)");
}
cout << "日志:文件\"" << filename << "\"打开成功" << endl;
}
// 析构函数:关闭文件
~FileHandler() {
if (file_stream.is_open()) {
file_stream.close();
cout << "日志:文件\"" << filename << "\"关闭成功" << endl;
}
}
// 读取文件内容(按行读取)
vector<string> read_file() {
vector<string> content;
string line;
// 检查读取状态
if (!file_stream.good()) {
throw FileReadException(filename, "文件流状态异常");
}
// 逐行读取
while (getline(file_stream, line)) {
content.push_back(line);
}
// 检查是否读取失败(非 EOF 导致的失败)
if (file_stream.bad()) {
throw FileReadException(filename, "读取过程中发生 IO 错误");
}
cout << "日志:文件\"" << filename << "\"读取完成,共" << content.size() << "行" << endl;
return content;
}
// 写入文件内容(覆盖写入)
void write_file(const vector<string>& content) {
// 检查写入状态
if (!file_stream.good()) {
throw FileWriteException(filename, "文件流状态异常");
}
// 逐行写入
for (const string& line : content) {
file_stream << line << endl;
// 检查写入是否成功
if (file_stream.fail()) {
throw FileWriteException(filename, "写入数据失败(可能磁盘已满)");
}
}
// 刷新缓冲区,确保数据写入磁盘
file_stream.flush();
if (file_stream.fail()) {
throw FileWriteException(filename, "刷新缓冲区失败");
}
cout << "日志:文件\"" << filename << "\"写入完成,共" << content.size() << "行" << endl;
}
};
// 辅助函数:打印文件内容
void print_file_content(const vector<string>& content) {
cout << "\n文件内容:" << endl;
for (int i = 0; i < content.size(); ++i) {
cout << "[" << i + 1 << "] " << content[i] << endl;
}
cout << endl;
}
int main() {
string read_filename = "input.txt";
string write_filename = "output.txt";
try {
// 测试读取文件
FileHandler reader(read_filename, ios::in);
vector<string> content = reader.read_file();
print_file_content(content);
// 测试写入文件(修改内容后写入)
vector<string> new_content = {
"=== 新写入的内容 ===",
"原文件共" + to_string(content.size()) + "行",
"这是第一行新内容",
"这是第二行新内容"
};
FileHandler writer(write_filename, ios::out | ios::trunc); // ios::trunc:覆盖写入
writer.write_file(new_content);
// 读取写入后的文件,验证结果
FileHandler verify_reader(write_filename, ios::in);
vector<string> verify_content = verify_reader.read_file();
print_file_content(verify_content);
} catch (const FileOpenException& e) {
cout << "\n错误提示:" << e.what() << endl;
} catch (const FileReadException& e) {
cout << "\n错误提示:" << e.what() << endl;
} catch (const FileWriteException& e) {
cout << "\n错误提示:" << e.what() << endl;
} catch (const exception& e) {
cout << "\n系统错误:" << e.what() << endl;
} catch (...) {
cout << "\n未知错误:发生未预期的异常" << endl;
}
return 0;
}
日志:文件"input.txt"打开成功
日志:文件"input.txt"读取完成,共 3 行
文件内容:
[1] Hello, File Handling!
[2] This is a test file.
[3] C++ Exception Handling.
日志:文件"input.txt"关闭成功
日志:文件"output.txt"打开成功
日志:文件"output.txt"写入完成,共 4 行
日志:文件"output.txt"关闭成功
日志:文件"output.txt"打开成功
日志:文件"output.txt"读取完成,共 4 行
文件内容:
[1] === 新写入的内容 ===
[2] 原文件共 3 行
[3] 这是第一行新内容
[4] 这是第二行新内容
日志:文件"output.txt"关闭成功
错误提示:文件操作异常:文件"input.txt", 原因:打开失败 - 无法打开文件(可能不存在或权限不足)
结论:该文件工具类通过自定义异常类提供了详细的错误信息,基于 RAII 模式保证了文件资源的正确释放,即使发生异常也不会导致资源泄漏,同时通过分层捕获异常,为用户提供了友好的提示,符合异常处理的最佳实践。
try-catch-throw 实现错误检测与处理的分离,提升代码健壮性。out_of_range、bad_alloc),自定义异常类应继承自 std::exception,重写 what() 方法。catch 块需按'派生类在前、基类在后'的顺序声明,catch (...) 作为兜底。通过本文学习,你应能熟练运用异常处理机制解决实际开发中的错误处理问题,编写健壮、可靠的 C++ 代码。下一篇将深入探讨 C++ 的输入输出流(IO 流),包括文件 IO、字符串 IO 等高级应用!

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML 转 Markdown 互为补充。 在线工具,Markdown 转 HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML 转 Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online