决定使用 CPP 库处理 xls 问题

This commit is contained in:
qwe
2026-05-28 00:24:18 +08:00
parent 061c6d2b93
commit 7c50f8d5d5
6 changed files with 148 additions and 34 deletions

24
lib_cpp/CMakeLists.txt Normal file
View File

@@ -0,0 +1,24 @@
cmake_minimum_required(VERSION 3.14)
project(xlsx_reader VERSION 1.0.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
set(CMAKE_VISIBILITY_INLINES_HIDDEN ON)
include(FetchContent)
add_subdirectory(third_party/OpenXLSX)
set(OPENXLSX_STATIC ON CACHE BOOL "Build OpenXLSX as static library")
FetchContent_MakeAvailable(OpenXLSX)
add_library(xlsx_reader SHARED src/xlsx_reader.cpp)
target_include_directories(xlsx_reader PUBLIC include)
target_link_libraries(xlsx_reader PRIVATE OpenXLSX::OpenXLSX)
target_compile_definitions(xlsx_reader PRIVATE XLSX_BUILD_SHARED)

View File

@@ -0,0 +1,28 @@
#ifndef XLSX_READER_H
#define XLSX_READER_H
#if defined(_WIN32)
#if defined(XLSX_BUILD_SHARED)
#define XLSX_API __declspec(dllexport)
#else
#define XLSX_API __declspec(dllimport)
#endif
#elif defined(__GNUC__) || defined(__clang__)
#define XLSX_API __attribute__((visibility("default")))
#else
#define XLSX_API
#endif
#ifdef __cplusplus
extern "C" {
#endif
XLSX_API char* xlsx_read_first_sheet(const char* filepath);
XLSX_API void xlsx_free_string(char* str);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,96 @@
#include "xlsx_reader.h"
#include <OpenXLSX/OpenXLSX.hpp>
#include <cstdlib>
#include <cstring>
#include <string>
static std::string jsonEscape(const std::string& s) {
std::string out;
out.reserve(s.size() + 2);
for (char c : s) {
switch (c) {
case '"': out += "\\\""; break;
case '\\': out += "\\\\"; break;
case '\n': out += "\\n"; break;
case '\t': out += "\\t"; break;
case '\r': out += "\\r"; break;
default:
if (static_cast<unsigned char>(c) < 0x20) {
char buf[8];
std::snprintf(buf, sizeof(buf), "\\u%04x",
static_cast<unsigned char>(c));
out += buf;
} else {
out += c;
}
}
}
return out;
}
static std::string cellAsString(const OpenXLSX::XLCell& cell) {
using namespace OpenXLSX;
auto& val = cell.value();
switch (val.type()) {
case XLValueType::Integer:
return std::to_string(val.get<int64_t>());
case XLValueType::Float:
return std::to_string(val.get<double>());
case XLValueType::String:
return val.get<std::string>();
case XLValueType::Boolean:
return val.get<bool>() ? "true" : "false";
case XLValueType::Empty:
default:
return {};
}
}
extern "C" XLSX_API char* xlsx_read_first_sheet(const char* filepath) {
if (!filepath) return nullptr;
try {
OpenXLSX::XLDocument doc;
doc.open(filepath);
auto wks = doc.workbook().worksheet(1);
std::string json;
json += '[';
bool firstRow = true;
for (auto& row : wks.rows()) {
if (!firstRow) json += ',';
json += '[';
bool firstCell = true;
for (auto& cell : row.cells()) {
if (!firstCell) json += ',';
json += '"';
json += jsonEscape(cellAsString(cell));
json += '"';
firstCell = false;
}
json += ']';
firstRow = false;
}
json += ']';
doc.close();
char* result = static_cast<char*>(std::malloc(json.size() + 1));
if (result) {
std::memcpy(result, json.c_str(), json.size() + 1);
}
return result;
} catch (const std::exception&) {
return nullptr;
}
}
extern "C" XLSX_API void xlsx_free_string(char* str) {
std::free(str);
}