如何使用 Google Apps 脚本从 .tar 存档中提取文件
How to extract files from .tar archive with Google Apps Script
大家好,
我正在尝试从 Gmail 获取 tar.gz 附件,提取文件并将其保存到 Google 驱动器。这是我收到的每日自动生成的报告,由于原始大小超过 25mb 而被压缩。
到目前为止我得到了这个:
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Setup");
var gmailLabels = sheet.getRange("B2:B2").getValue(); //I have my Gmail Label stored here
var driveFolder = sheet.getRange("B5:B5").getValue(); //I have my GDrive folder name stored here
// apply label filter, search only last 24hrs mail
var filter = "has:attachment label:" + gmailLabels + " after:" + Utilities.formatDate(new Date(new Date().getTime()-1*(24*60*60*1000)), "GMT", "yyyy/MM/dd");
var threads = GmailApp.search(filter, 0, 1); // check only 1 email at a time
var folder = DriveApp.getFoldersByName(driveFolder);
if (folder.hasNext()) {
folder = folder.next();
} else {
folder = DriveApp.createFolder(driveFolder);
}
var message = threads[0].getMessages()[0];
var desc = message.getSubject() + " #" + message.getId();
var att = message.getAttachments();
for (var z=0; z<att.length; z++) {
var attName = att[z].getName()
var attExt = attName.search('csv')
if (attExt > 0){ var fileType = "csv"; }
else {
var attExt = attName.search('tar.gz');
if (attExt > 0){ var fileType = "gzip"; }
else {
threads[x].addLabel(skipLabel);
continue;
}
}
// save the file to GDrive
try {
file = folder.createFile(att[z]);
file.setDescription(desc);
}
catch (e) {
Logger.log(e.toString());
}
// extract if gzip
if (fileType == 'gzip' ){
var ungzippedFile = Utilities.ungzip(file);
try {
gz_file = folder.createFile(ungzippedFile);
gz_file.setDescription(desc);
}
catch (e) {
Logger.log(e.toString());
}
}
}
一切正常,但在最后一步中它只解压缩了 .gz 文件保存在驱动器中的 .tar 文件。接下来我能用它做什么? .tar 文件包含一个 .csv 文件,我需要在之后提取和处理该文件。
我应该补充一点,我仅限于使用 GAS。
非常感谢任何帮助。
这个答案怎么样?不幸的是,在当前阶段,Google Apps 脚本中还没有从 tar 文件中提取文件的方法。但幸运的是,我们可以从 wiki of tar 中检索到 tar 数据的结构。我使用此结构数据通过 Google Apps 脚本实现了此方法。
1。取消存档 tar 数据:
在你运行这个脚本之前,请将tar文件的文件ID设置为run()
。然后,运行 run()
.
示例脚本:
function tarUnarchiver(blob) {
var mimeType = blob.getContentType();
if (!mimeType || !~mimeType.indexOf("application/x-tar")) {
throw new Error("Inputted blob is not mimeType of tar. mimeType of inputted blob is " + mimeType);
}
var baseChunkSize = 512;
var byte = blob.getBytes();
var res = [];
do {
var headers = [];
do {
var chunk = byte.splice(0, baseChunkSize);
var headerStruct = {
filePath: function(b) {
var r = [];
for (var i = b.length - 1; i >= 0; i--) {
if (b[i] != 0) {
r = b.slice(0, i + 1);
break;
}
}
return r;
}(chunk.slice(0, 100)),
fileSize: chunk.slice(124, 124 + 11),
fileType: Utilities.newBlob(chunk.slice(156, 156 + 1)).getDataAsString(),
};
Object.keys(headerStruct).forEach(function(e) {
var t = Utilities.newBlob(headerStruct[e]).getDataAsString();
if (e == "fileSize") t = parseInt(t, 8);
headerStruct[e] = t;
});
headers.push(headerStruct);
} while (headerStruct.fileType == "5");
var lastHeader = headers[headers.length - 1];
var filePath = lastHeader.filePath.split("/");
var blob = Utilities.newBlob(byte.splice(0, lastHeader.fileSize)).setName(filePath[filePath.length - 1]).setContentTypeFromExtension();
byte.splice(0, Math.ceil(lastHeader.fileSize / baseChunkSize) * baseChunkSize - lastHeader.fileSize);
res.push({fileInf: lastHeader, file: blob});
} while (byte[0] != 0);
return res;
}
// Following function is a sample script for using tarUnarchiver().
// Please modify this to your situation.
function run() {
// When you want to extract the files from .tar.gz file, please use the following script.
var id = "### file ID of .tar.gz file ###";
var gz = DriveApp.getFileById(id).getBlob().setContentTypeFromExtension();
var blob = Utilities.ungzip(gz).setContentTypeFromExtension();
// When you want to extract the files from .tar file, please use the following script.
var id = "### file ID of .tar file ###";
var blob = DriveApp.getFileById(id).getBlob().setContentType("application/x-tar");
// Extract files from a tar data.
var res = tarUnarchiver(blob);
// If you want to create the extracted files to Google Drive, please use the following script.
res.forEach(function(e) {
DriveApp.createFile(e.file);
});
// You can see the file information by below script.
Logger.log(res);
}
2。修改您的脚本:
如果这个脚本用于你的脚本,例如,这个怎么样?使用上述脚本的 tarUnarchiver()
。但我不确定你想如何使用这个脚本。所以请将此视为示例。
示例脚本:
// extract if gzip
if (fileType == 'gzip' ){
var ungzippedFile = Utilities.ungzip(file);
try {
var blob = ungzippedFile.setContentType("application/x-tar"); // Added
tarUnarchiver(blob).forEach(function(e) {folder.createFile(e.file)}); // Added
}
catch (e) {
Logger.log(e.toString());
}
}
- 在这个修改后的脚本中,
ungzippedFile
的 blob(tar 数据)被放入我的脚本和 运行 tarUnarchiver()
。然后,每个文件都创建到文件夹中。
注:
- 当您运行此脚本时,如果出现mimeType相关错误,请将"tar"的mimeType设置为输入blob。
- 如果要检索每个文件的文件路径,请查看
tarUnarchiver()
的回复。您可以从响应中将其视为 fileInf
的 属性。
限制:
使用此脚本时,有如下限制。这些限制是由于 Google 的规范。
- 关于文件大小,当tar数据的大小超过50MB(52,428,800字节)时,会出现与大小限制相关的错误。
- 当提取的文件大小超过 50 MB 时,会发生错误。
- 当提取的文件单个文件大小接近50MB时,有可能出现错误。
- 在我的环境中,我可以确认可以提取 49 MB 的大小。但在只有 50 MB 的情况下
, 发生错误。
参考:
在我的环境中,我可以确认脚本有效。但如果这个脚本不起作用,我深表歉意。届时,能否提供一个示例tar文件?我想检查它并修改脚本。
大家好,
我正在尝试从 Gmail 获取 tar.gz 附件,提取文件并将其保存到 Google 驱动器。这是我收到的每日自动生成的报告,由于原始大小超过 25mb 而被压缩。
到目前为止我得到了这个:
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Setup");
var gmailLabels = sheet.getRange("B2:B2").getValue(); //I have my Gmail Label stored here
var driveFolder = sheet.getRange("B5:B5").getValue(); //I have my GDrive folder name stored here
// apply label filter, search only last 24hrs mail
var filter = "has:attachment label:" + gmailLabels + " after:" + Utilities.formatDate(new Date(new Date().getTime()-1*(24*60*60*1000)), "GMT", "yyyy/MM/dd");
var threads = GmailApp.search(filter, 0, 1); // check only 1 email at a time
var folder = DriveApp.getFoldersByName(driveFolder);
if (folder.hasNext()) {
folder = folder.next();
} else {
folder = DriveApp.createFolder(driveFolder);
}
var message = threads[0].getMessages()[0];
var desc = message.getSubject() + " #" + message.getId();
var att = message.getAttachments();
for (var z=0; z<att.length; z++) {
var attName = att[z].getName()
var attExt = attName.search('csv')
if (attExt > 0){ var fileType = "csv"; }
else {
var attExt = attName.search('tar.gz');
if (attExt > 0){ var fileType = "gzip"; }
else {
threads[x].addLabel(skipLabel);
continue;
}
}
// save the file to GDrive
try {
file = folder.createFile(att[z]);
file.setDescription(desc);
}
catch (e) {
Logger.log(e.toString());
}
// extract if gzip
if (fileType == 'gzip' ){
var ungzippedFile = Utilities.ungzip(file);
try {
gz_file = folder.createFile(ungzippedFile);
gz_file.setDescription(desc);
}
catch (e) {
Logger.log(e.toString());
}
}
}
一切正常,但在最后一步中它只解压缩了 .gz 文件保存在驱动器中的 .tar 文件。接下来我能用它做什么? .tar 文件包含一个 .csv 文件,我需要在之后提取和处理该文件。
我应该补充一点,我仅限于使用 GAS。
非常感谢任何帮助。
这个答案怎么样?不幸的是,在当前阶段,Google Apps 脚本中还没有从 tar 文件中提取文件的方法。但幸运的是,我们可以从 wiki of tar 中检索到 tar 数据的结构。我使用此结构数据通过 Google Apps 脚本实现了此方法。
1。取消存档 tar 数据:
在你运行这个脚本之前,请将tar文件的文件ID设置为run()
。然后,运行 run()
.
示例脚本:
function tarUnarchiver(blob) {
var mimeType = blob.getContentType();
if (!mimeType || !~mimeType.indexOf("application/x-tar")) {
throw new Error("Inputted blob is not mimeType of tar. mimeType of inputted blob is " + mimeType);
}
var baseChunkSize = 512;
var byte = blob.getBytes();
var res = [];
do {
var headers = [];
do {
var chunk = byte.splice(0, baseChunkSize);
var headerStruct = {
filePath: function(b) {
var r = [];
for (var i = b.length - 1; i >= 0; i--) {
if (b[i] != 0) {
r = b.slice(0, i + 1);
break;
}
}
return r;
}(chunk.slice(0, 100)),
fileSize: chunk.slice(124, 124 + 11),
fileType: Utilities.newBlob(chunk.slice(156, 156 + 1)).getDataAsString(),
};
Object.keys(headerStruct).forEach(function(e) {
var t = Utilities.newBlob(headerStruct[e]).getDataAsString();
if (e == "fileSize") t = parseInt(t, 8);
headerStruct[e] = t;
});
headers.push(headerStruct);
} while (headerStruct.fileType == "5");
var lastHeader = headers[headers.length - 1];
var filePath = lastHeader.filePath.split("/");
var blob = Utilities.newBlob(byte.splice(0, lastHeader.fileSize)).setName(filePath[filePath.length - 1]).setContentTypeFromExtension();
byte.splice(0, Math.ceil(lastHeader.fileSize / baseChunkSize) * baseChunkSize - lastHeader.fileSize);
res.push({fileInf: lastHeader, file: blob});
} while (byte[0] != 0);
return res;
}
// Following function is a sample script for using tarUnarchiver().
// Please modify this to your situation.
function run() {
// When you want to extract the files from .tar.gz file, please use the following script.
var id = "### file ID of .tar.gz file ###";
var gz = DriveApp.getFileById(id).getBlob().setContentTypeFromExtension();
var blob = Utilities.ungzip(gz).setContentTypeFromExtension();
// When you want to extract the files from .tar file, please use the following script.
var id = "### file ID of .tar file ###";
var blob = DriveApp.getFileById(id).getBlob().setContentType("application/x-tar");
// Extract files from a tar data.
var res = tarUnarchiver(blob);
// If you want to create the extracted files to Google Drive, please use the following script.
res.forEach(function(e) {
DriveApp.createFile(e.file);
});
// You can see the file information by below script.
Logger.log(res);
}
2。修改您的脚本:
如果这个脚本用于你的脚本,例如,这个怎么样?使用上述脚本的 tarUnarchiver()
。但我不确定你想如何使用这个脚本。所以请将此视为示例。
示例脚本:
// extract if gzip
if (fileType == 'gzip' ){
var ungzippedFile = Utilities.ungzip(file);
try {
var blob = ungzippedFile.setContentType("application/x-tar"); // Added
tarUnarchiver(blob).forEach(function(e) {folder.createFile(e.file)}); // Added
}
catch (e) {
Logger.log(e.toString());
}
}
- 在这个修改后的脚本中,
ungzippedFile
的 blob(tar 数据)被放入我的脚本和 运行tarUnarchiver()
。然后,每个文件都创建到文件夹中。
注:
- 当您运行此脚本时,如果出现mimeType相关错误,请将"tar"的mimeType设置为输入blob。
- 如果要检索每个文件的文件路径,请查看
tarUnarchiver()
的回复。您可以从响应中将其视为fileInf
的 属性。
限制:
使用此脚本时,有如下限制。这些限制是由于 Google 的规范。
- 关于文件大小,当tar数据的大小超过50MB(52,428,800字节)时,会出现与大小限制相关的错误。
- 当提取的文件大小超过 50 MB 时,会发生错误。
- 当提取的文件单个文件大小接近50MB时,有可能出现错误。
- 在我的环境中,我可以确认可以提取 49 MB 的大小。但在只有 50 MB 的情况下 , 发生错误。
参考:
在我的环境中,我可以确认脚本有效。但如果这个脚本不起作用,我深表歉意。届时,能否提供一个示例tar文件?我想检查它并修改脚本。