需求:遍历一个文件夹,得到一个 json 对象,键是文件名,值是文件夹内各文件的信息。
问题
问题:代码明明写得没问题,但是运行时却报错。
初始代码如下。这里为了简化问题,将文件的路径作为 json 对象键值对的值。
main.cpp
CMake 配置文件CMakeLists.txt
:
cmake_minimum_required(VERSION 3.25)
# 设置 vcpkg 工具链文件(如果没有通过命令行指定)
# 如果在 CMakeList.txt 文件中设置 CMAKE_TOOLCHAIN_FILE,请确保在调用 project() 之前设置变量。
set(CMAKE_TOOLCHAIN_FILE "C:/Users/Aoyu/.vcpkg-clion/vcpkg/scripts/buildsystems/vcpkg.cmake")
project(Test)
set(CMAKE_CXX_STANDARD 23)
find_package(nlohmann_json CONFIG REQUIRED)
add_executable(Test main.cpp)
target_link_libraries(Test PRIVATE nlohmann_json::nlohmann_json)
运行报错:
Debug Error!
Program: D:\ClionProjects\Test2\cmake-build-debug\Test.exe
abort() has been called
(Press Retry to debug the application)
调试后发现是j.dump(4)
抛出的异常。在代码中捕获异常,异常的描述信息:
[json.exception.type_error.316] invalid UTF-8 byte at index 0: 0xB9
后面经过不断测试,确定是文件路径中存在中文字符导致的。但是这只是表层原因,真正的原因是,程序不是以 UTF8 编码处理中文。
解决办法
如果在 Windows 平台下使用 MSVC 编译器编译程序,让编译器以 UTF-8 模式编译源代码,确保源代码文件中的中文字符能被正确解析。
CMakeLists.txt
# ...
if(WIN32)
# 添加 UTF-8 编码支持
add_compile_options("$<$<C_COMPILER_ID:MSVC>:/utf-8>")
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
endif()
project(Test)
# ...
在程序的 main()
函数开头,添加:
main.cpp
下面是同样的代码,额外加上了更多注释。
main.cpp
在这个程序中,真正起作用的是CMakeLists.txt
中的配置和这句代码std::locale::global(std::locale(".UTF-8"));
。
其他的代码加上也不冗余,可以让程序更稳健。比如这句代码std::setlocale(LC_ALL, ".UTF-8");
会在使用 C 第三方库时发挥作用,如这里cpp.q2k1k.24.1121.0121。
演示
程序现在可以正确处理文件路径中的中文了,例如:
{
"8.png": "haha\\8.png",
"haha": "haha",
"t.cpp": "t.cpp",
"t.o": "t.o",
"t5.tex": "t5.tex",
"t6.cpp": "t6.cpp",
"你好": "你好",
"哈哈哈.txt": "你好\\哈哈哈.txt"
}
补充
注意到 Windows 下路径的分隔符是\\
,能否改为使用/
呢?
把relative_path.string()
改为relative_path.generic_string()
即可:
{
"8.png": "haha/8.png",
"haha": "haha",
"t.cpp": "t.cpp",
"t.o": "t.o",
"t5.tex": "t5.tex",
"t6.cpp": "t6.cpp",
"你好": "你好",
"哈哈哈.txt": "你好/哈哈哈.txt"
}