在附加到 Google Sheet 的 Google App 脚本中,我有一个 Excel 文件的文件 ID。我想读取该 Excel 文件的工作表名称。我看到的关于转换的教程将 Excel 文件作为 blob 加载,然后将其作为 Google 表格写入云端硬盘,然后读取它。
有没有一种方法可以做到这一点,而不会创建我需要删除的工件?原因是我担心以下问题:存在错误时的安全性(错误的内容被删除)、额外的处理时间(我需要处理一长串 Excel 文件)以及脚本在插入之间意外中止时的剩余工件并删除。
谢谢!
回答您的问题,教程首先将 Excel 文件转换为 Google Sheet 的原因是与其交互(在您的情况下,收集工作表名称),这是因为 Google API 或 Apps 脚本无法与 Excel 文件作为行进行交互数据,Google 需要使用 Google API 将文件转换为可读的内容。
解决此问题的方法是使用 Excel JavaScript API 读取原始 Excel 文件的信息,您可以在 Apps Script 中使用外部 API,因为它基于 JavaScript,因此您将使用 Apps Script 作为 IDE。
但是,您可以对任何其他支持 JavaScript 的 IDE 执行相同的操作。
此博客中有一些有关如何使用 Excel JavaScript API 列出工作表的示例。
如果您想继续使用 Google API 并使用 Google Apps 脚本内置服务。您需要将文件转换为 Google 表格。
更新答案:
您可以在此处查看有关 Excel Services API 服务的更多信息。
可以通过以下方式从 Google Drive 获取 Excel 文件的数据。由于每个 Excel 文件只是 xml 文件的压缩文件夹,因此您可以获取文件 blob 并将其解压缩。然后您可以解析 xml 文件并获取您需要的数据。这样您就不需要先将 .xls 文件转换为 gsheet。
function getDataFromDrive(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
// getting a MS Excel file in Google Drive
var file = DriveApp.getFileById("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
var blob = file.getBlob();
// if second parameter is not provided all sheets will be parsed
var data = parseMSExcelBlob(blob, ["Orders"]);
// test if everything is good
if( data["Error"] ) return ss.toast(data["Error"], "Something went wrong 🙄", 10);
// here we have the data in 2D array
var tbl = data["Orders"];
// do your stuff
// ...
}
/**
* Parsing MS Excel files and returns values in JSON format.
*
* @param {BlobSource} blob the blob from MS Excel file
* @param {String[]} requiredSheets the array of required sheet names (if omitted returns all)
* @return {Object} Object of sheet names and values (2D arrays)
*/
function parseMSExcelBlob(blob, requiredSheets){
var col_cache = {};
var forbidden_chars = {
"<": "<",
">": ">",
"&": "&",
"'": "'",
""": '"'
};
blob.setContentType("application/zip");
var parts = Utilities.unzip(blob);
var relationships = {};
for( var part of parts ){
var part_name = part.getName();
if( part_name === "xl/_rels/workbook.xml.rels" ){
var txt = part.getDataAsString();
var rels = breakUpString(txt, '<Relationship ', '/>');
for( var i = 0; i < rels.length; i++ ){
var rId = breakUpString(rels[i], 'Id="', '"')[0];
var path = breakUpString(rels[i], 'Target="', '"')[0];
relationships[rId] = "xl/" + path;
}
}
}
var worksheets = {};
for( var part of parts ){
var part_name = part.getName();
if( part_name === "xl/workbook.xml" ){
var txt = part.getDataAsString();
var sheets = breakUpString(txt, '<sheet ', '/>');
for( var i = 0; i < sheets.length; i++ ){
var sh_name = breakUpString(sheets[i], 'name="', '"')[0];
sh_name = decodeForbiddenChars(sh_name);
var rId = breakUpString(sheets[i], 'r:id="', '"')[0];
var path = relationships[rId];
if( path.includes("worksheets") ){
worksheets[path] = sh_name;
}
}
}
}
requiredSheets = Array.isArray(requiredSheets) && requiredSheets.length && requiredSheets || [];
var worksheets_needed = [];
for( var path in worksheets ){
if( !requiredSheets.length || requiredSheets.includes(worksheets[path]) ){
worksheets_needed.push(path);
}
}
if( !worksheets_needed.length ) return {"Error": "Requested worksheets not found"};
var sharedStrings = [];
for( var part of parts ){
var part_name = part.getName();
if( part_name === "xl/sharedStrings.xml" ){
var txt = part.getDataAsString();
txt = txt.replace(/ xml:space="preserve"/g, "");
sharedStrings = breakUpString(txt, '<si>', '</si>');
for( var i = 0; i < sharedStrings.length; i++ ){
var str = breakUpString(sharedStrings[i], '<t>', '</t>')[0];
sharedStrings[i] = decodeForbiddenChars(str);
}
}
}
var result = {};
for( var part of parts ){
var part_name = part.getName();
if( worksheets_needed.includes(part_name) ){
var txt = part.getDataAsString();
txt = txt.replace(/ xml:space="preserve"/g, "");
var cells = breakUpString(txt, '<c ', '</c>');
var tbl = [[]];
for( var i = 0; i < cells.length; i++ ){
var r = breakUpString(cells[i], 'r="', '"')[0];
var t = breakUpString(cells[i], 't="', '"')[0];
if( t === "inlineStr" ){
var data = breakUpString(cells[i], '<t>', '</t>')[0];
data = decodeForbiddenChars(data);
}else if( t === "s" ){
var v = breakUpString(cells[i], '<v>', '</v>')[0];
var data = sharedStrings[v];
}else{
var v = breakUpString(cells[i], '<v>', '</v>')[0];
var data = Number(v);
}
var row = r.replace(/[A-Z]/g, "") - 1;
var col = colNum(r.replace(/[0-9]/g, "")) - 1;
if( tbl[row] ){
tbl[row][col] = data;
}else{
tbl[row] = [];
tbl[row][col] = data;
}
}
var sh_name = worksheets[part_name];
result[sh_name] = squareTbl(tbl);
}
}
function decodeForbiddenChars(txt){
if( !txt ) return txt;
for( var char in forbidden_chars ){
var regex = new RegExp(char,"g");
txt = txt.replace(regex, forbidden_chars[char]);
}
return txt;
}
function breakUpString(str, start_patern, end_patern){
var arr = [], raw = str.split(start_patern), i = 1, len = raw.length;
while( i < len ){ arr[i - 1] = raw[i].split(end_patern, 1)[0]; i++ };
return arr;
}
function colNum(char){
if( col_cache[char] ) return col_cache[char];
var alph = "ABCDEFGHIJKLMNOPQRSTUVWXYZ", i, j, result = 0;
for( i = 0, j = char.length - 1; i < char.length; i++, j-- ){
result += Math.pow(alph.length, j) * (alph.indexOf(char[i]) + 1);
}
col_cache[char] = result;
return result;
}
function squareTbl(arr){
var tbl = [];
var x_max = 0;
var y_max = arr.length;
for( var y = 0; y < y_max; y++ ){
arr[y] = arr[y] || [];
if( arr[y].length > x_max ){ x_max = arr[y].length };
}
for( var y = 0; y < y_max; y++ ){
var row = [];
for( var x = 0; x < x_max; x++ ){
row.push(arr[y][x] || arr[y][x] === 0 ? arr[y][x] : "");
}
tbl.push(row);
}
return tbl.length ? tbl : [[]];
}
return result;
}