update at 2026-02-14 11:20:38
This commit is contained in:
@@ -270,6 +270,13 @@ function parseXlsxBuffer(buffer) {
|
||||
return toRawTable(rows);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断 payload 是否为 ArrayBuffer 形态。
|
||||
*/
|
||||
function isArrayBufferLike(payload) {
|
||||
return !!payload && typeof payload === 'object' && typeof payload.byteLength === 'number';
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断二进制是否为 Zip 容器(xlsx)魔数:50 4B。
|
||||
*/
|
||||
@@ -298,25 +305,60 @@ function isOleMagic(bufferLike) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将二进制内容按 UTF-8 解码为文本,供 CSV 解析使用。
|
||||
*/
|
||||
function decodeUtf8Text(payload) {
|
||||
if (typeof payload === 'string') {
|
||||
return payload;
|
||||
}
|
||||
if (!isArrayBufferLike(payload)) {
|
||||
return String(payload || '');
|
||||
}
|
||||
|
||||
const bytes = new Uint8Array(payload);
|
||||
if (typeof TextDecoder === 'function') {
|
||||
try {
|
||||
return new TextDecoder('utf-8').decode(bytes);
|
||||
} catch (error) {
|
||||
// 继续走下方兼容解码分支
|
||||
}
|
||||
}
|
||||
|
||||
let binary = '';
|
||||
const chunkSize = 0x8000;
|
||||
for (let i = 0; i < bytes.length; i += chunkSize) {
|
||||
const chunk = bytes.subarray(i, i + chunkSize);
|
||||
binary += String.fromCharCode.apply(null, chunk);
|
||||
}
|
||||
try {
|
||||
return decodeURIComponent(escape(binary));
|
||||
} catch (error) {
|
||||
return binary;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 按文件名后缀自动分流解析器。
|
||||
*/
|
||||
function parseTableByFileName(fileName, payload) {
|
||||
const lowerName = String(fileName || '').toLowerCase();
|
||||
if (lowerName.endsWith('.csv')) {
|
||||
return parseCsvText(String(payload || ''));
|
||||
}
|
||||
if (lowerName.endsWith('.xlsx') || lowerName.endsWith('.xls')) {
|
||||
const isBinaryPayload = isArrayBufferLike(payload);
|
||||
|
||||
// 优先按文件魔数识别 Excel,避免后缀错误导致误判 CSV。
|
||||
if (isBinaryPayload && (isZipMagic(payload) || isOleMagic(payload))) {
|
||||
return parseXlsxBuffer(payload);
|
||||
}
|
||||
|
||||
// 兜底:后缀不可用时,通过文件魔数自动识别 Excel。
|
||||
if (payload && typeof payload === 'object' && typeof payload.byteLength === 'number') {
|
||||
if (isZipMagic(payload) || isOleMagic(payload)) {
|
||||
return parseXlsxBuffer(payload);
|
||||
}
|
||||
if (lowerName.endsWith('.xlsx') || lowerName.endsWith('.xls')) {
|
||||
return parseXlsxBuffer(payload);
|
||||
}
|
||||
throw new Error('仅支持 .csv / .xlsx / .xls 文件');
|
||||
if (lowerName.endsWith('.csv')) {
|
||||
return parseCsvText(decodeUtf8Text(payload));
|
||||
}
|
||||
|
||||
// 后缀缺失时,默认按 CSV 尝试解析(文本/二进制都支持)。
|
||||
return parseCsvText(decodeUtf8Text(payload));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user