决定使用 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

View File

@@ -1,15 +0,0 @@
module xlsxUtils
go 1.25.5
require (
github.com/richardlehane/mscfb v1.0.6 // indirect
github.com/richardlehane/msoleps v1.0.6 // indirect
github.com/tiendc/go-deepcopy v1.7.2 // indirect
github.com/xuri/efp v0.0.1 // indirect
github.com/xuri/excelize/v2 v2.10.1 // indirect
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 // indirect
golang.org/x/crypto v0.48.0 // indirect
golang.org/x/net v0.50.0 // indirect
golang.org/x/text v0.34.0 // indirect
)

View File

@@ -1,18 +0,0 @@
github.com/richardlehane/mscfb v1.0.6 h1:eN3bvvZCp00bs7Zf52bxNwAx5lJDBK1tCuH19qq5aC8=
github.com/richardlehane/mscfb v1.0.6/go.mod h1:pe0+IUIc0AHh0+teNzBlJCtSyZdFOGgV4ZK9bsoV+Jo=
github.com/richardlehane/msoleps v1.0.6 h1:9BvkpjvD+iUBalUY4esMwv6uBkfOip/Lzvd93jvR9gg=
github.com/richardlehane/msoleps v1.0.6/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
github.com/tiendc/go-deepcopy v1.7.2 h1:Ut2yYR7W9tWjTQitganoIue4UGxZwCcJy3orjrrIj44=
github.com/tiendc/go-deepcopy v1.7.2/go.mod h1:4bKjNC2r7boYOkD2IOuZpYjmlDdzjbpTRyCx+goBCJQ=
github.com/xuri/efp v0.0.1 h1:fws5Rv3myXyYni8uwj2qKjVaRP30PdjeYe2Y6FDsCL8=
github.com/xuri/efp v0.0.1/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
github.com/xuri/excelize/v2 v2.10.1 h1:V62UlqopMqha3kOpnlHy2CcRVw1V8E63jFoWUmMzxN0=
github.com/xuri/excelize/v2 v2.10.1/go.mod h1:iG5tARpgaEeIhTqt3/fgXCGoBRt4hNXgCp3tfXKoOIc=
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 h1:+C0TIdyyYmzadGaL/HBLbf3WdLgC29pgyhTjAT/0nuE=
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60=
golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM=
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=

View File

@@ -1 +0,0 @@
package main

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);
}