导入 CSV 并替换相应命名工作表中的数据
Import CSV and replace data in corresponding named sheets
请耐心等待,因为我完全没有编写脚本的经验。
我需要帮助的是一个 Google 应用程序脚本,它自动从我的 google 驱动器导入 10 个 .csv 文件,并覆盖包含一个 'dashboard' 的传播 sheet 中的数据sheet、一个'working' sheet等都是CSV导入的sheet,与csv文件名相同。到目前为止,我已经找到了执行此操作的 trial/paid 扩展程序,但我确实找到了这个可以很好地导入数据的脚本,但它将所有数据附加到一个 sheet 而不是替换 sheets与 csv 具有相同的文件名。
我什至不确定脚本是否是最好的方式或 sheet 中的公式是否可行,但我不确定。
非常感谢您的帮助
// Application constants
const APP_TITLE = 'Trigger-driven CSV import [App Script Sample]'; // Application name
const APP_FOLDER = 'Market Monitor'; // Application primary folder
const SOURCE_FOLDER = 'Inbound CSV'; // Folder for the update files.
const PROCESSED_FOLDER = 'Processed CSV'; // Folder to hold processed files.
const SHEET_REPORT_NAME = 'Copy of Market Monitor'; // Name of destination spreadsheet.
// Application settings
const CSV_HEADER_EXIST = true; // Set to true if CSV files have a header row, false if not.
const HANDLER_FUNCTION = 'updateApplicationSheet'; // Function called by installable trigger to run data processing.
/**
* Installs a time-driven trigger that runs daily to import CSVs into the main application spreadsheet.
* Prior to creating a new instance, removes any existing triggers to avoid duplication.
*
* Called by setupSample() or run directly setting up the application.
*/
function installTrigger() {
// Checks for an existing trigger to avoid creating duplicate instances.
// Removes existing if found.
const projectTriggers = ScriptApp.getProjectTriggers();
for (var i = 0; i < projectTriggers.length; i++) {
if (projectTriggers[i].getHandlerFunction() == HANDLER_FUNCTION) {
console.log(`Existing trigger with Handler Function of '${HANDLER_FUNCTION}' removed.`);
ScriptApp.deleteTrigger(projectTriggers[i]);
}
}
// Creates the new trigger.
let newTrigger = ScriptApp.newTrigger(HANDLER_FUNCTION)
.timeBased()
.atHour(23) // Runs at 11 PM in the time zone of this script.
.everyDays(1) // Runs once per day.
.create();
console.log(`New trigger with Handler Function of '${HANDLER_FUNCTION}' created.`);
}
/**
* Handler function called by the trigger created with the "installTrigger" function.
* Run this directly to execute the entire automation process of the application with a trigger.
*
* Process: Iterates through CSV files located in the source folder (SOURCE_FOLDER),
* and appends them to the end of destination spreadsheet (SHEET_REPORT_NAME).
* Successfully processed CSV files are moved to the processed folder (PROCESSED_FOLDER) to avoid duplication.
* Sends summary email with status of the import.
*/
function updateApplicationSheet() {
// Gets application & supporting folders.
const folderAppPrimary = getApplicationFolder_(APP_FOLDER);
const folderSource = getFolder_(SOURCE_FOLDER);
const folderProcessed = getFolder_(PROCESSED_FOLDER);
// Gets the application's destination spreadsheet {Spreadsheet object}
let objSpreadSheet = getSpreadSheet_(SHEET_REPORT_NAME, folderAppPrimary)
// Creates arrays to track every CSV file, categorized as processed sucessfully or not.
let filesProcessed = [];
let filesNotProcessed = [];
// Gets all CSV files found in the source folder.
let cvsFiles = folderSource.getFilesByType(MimeType.CSV);
// Iterates through each CSV file.
while (cvsFiles.hasNext()) {
let csvFile = cvsFiles.next();
let isSuccess;
// Appends the unprocessed CSV data into the Google Sheets spreadsheet.
isSuccess = processCsv_(objSpreadSheet, csvFile);
if (isSuccess) {
// Moves the processed file to the processed folder to prevent future duplicate data imports.
csvFile.moveTo(folderProcessed);
// Logs the successfully processed file to the filesProcessed array.
filesProcessed.push(csvFile.getName());
console.log(`Successfully processed: ${csvFile.getName()}`);
} else if (!isSuccess) {
// Doesn't move the unsuccesfully processed file so that it can be corrected and reprocessed later.
// Logs the unsuccessfully processed file to the filesNotProcessed array.
filesNotProcessed.push(csvFile.getName());
console.log(`Not processed: ${csvFile.getName()}`);
}
}
// Prepares summary email.
// Gets variables to link to this Apps Script project.
const scriptId = ScriptApp.getScriptId();
const scriptUrl = DriveApp.getFileById(scriptId).getUrl();
const scriptName = DriveApp.getFileById(scriptId).getName();
// Gets variables to link to the main application spreadsheet.
const sheetUrl = objSpreadSheet.getUrl()
const sheetName = objSpreadSheet.getName()
// Gets user email and timestamp.
const emailTo = Session.getEffectiveUser().getEmail();
const timestamp = Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "yyyy-MM-dd HH:mm:ss zzzz");
// Prepares lists and counts of processed CSV files.
let processedList = "";
const processedCount = filesProcessed.length
for (const processed of filesProcessed) {
processedList += processed + '<br>'
};
const unProcessedCount = filesNotProcessed.length
let unProcessedList = "";
for (const unProcessed of filesNotProcessed) {
unProcessedList += unProcessed + '\n'
};
// Assembles email body as html.
const eMailBody = `${APP_TITLE} ran an automated process at ${timestamp}.<br><br>` +
`<b>Files successfully updated:</b> ${processedCount}<br>` +
`${processedList}<br>` +
`<b>Files not updated:</b> ${unProcessedCount}<br>` +
`${unProcessedList}<br>` +
`<br>View all updates in the Google Sheets spreadsheet ` +
`<b><a href= "${sheetUrl}" target=\"_blank\">${sheetName}</a></b>.<br>` +
`<br>*************<br>` +
`<br>This email was generated by Google Apps Script. ` +
`To learn more about this application or make changes, open the script project below: <br>` +
`<a href= "${scriptUrl}" target=\"_blank\">${scriptName}</a>`
MailApp.sendEmail({
to: emailTo,
subject: `Automated email from ${APP_TITLE}`,
htmlBody: eMailBody
});
console.log(`Email sent to ${emailTo}`);
}
/**
* Parses CSV data into an array and appends it after the last row in the destination spreadsheet.
*
* @return {boolean} true if the update is successful, false if unexpected errors occur.
*/
function processCsv_(objSpreadSheet, csvFile) {
try {
// Gets the first sheet of the destination spreadsheet.
let sheet = objSpreadSheet.getSheets()[0];
// Parses CSV file into data array.
let data = Utilities.parseCsv(csvFile.getBlob().getDataAsString());
// Omits header row if application variable CSV_HEADER_EXIST is set to 'true'.
if (CSV_HEADER_EXIST) {
data.splice(0, 1);
}
// Gets the row and column coordinates for next available range in the spreadsheet.
let startRow = sheet.getLastRow() + 1;
let startCol = 1;
// Determines the incoming data size.
let numRows = data.length;
let numColumns = data[0].length;
// Appends data into the sheet.
sheet.getRange(startRow, startCol, numRows, numColumns).setValues(data);
return true; // Success.
} catch {
return false; // Failure. Checks for CSV data file error.
}
}
它是最后一个函数 processCsv_()
尝试更改行:
let sheet = objSpreadSheet.getSheets()[0];
与:
let sheet = objSpreadSheet.getSheetByName(csvFile.getName());
更新
如果你想替换工作表上的所有数据(而不是追加),可能你可以通过更改此行(在相同的函数 processCsv_()
中)来实现:
sheet.getRange(startRow, startCol, numRows, numColumns).setValues(data);
这样:
sheet.clearContents().getRange(1, startCol, numRows, numColumns).setValues(data);
请耐心等待,因为我完全没有编写脚本的经验。 我需要帮助的是一个 Google 应用程序脚本,它自动从我的 google 驱动器导入 10 个 .csv 文件,并覆盖包含一个 'dashboard' 的传播 sheet 中的数据sheet、一个'working' sheet等都是CSV导入的sheet,与csv文件名相同。到目前为止,我已经找到了执行此操作的 trial/paid 扩展程序,但我确实找到了这个可以很好地导入数据的脚本,但它将所有数据附加到一个 sheet 而不是替换 sheets与 csv 具有相同的文件名。 我什至不确定脚本是否是最好的方式或 sheet 中的公式是否可行,但我不确定。 非常感谢您的帮助
// Application constants
const APP_TITLE = 'Trigger-driven CSV import [App Script Sample]'; // Application name
const APP_FOLDER = 'Market Monitor'; // Application primary folder
const SOURCE_FOLDER = 'Inbound CSV'; // Folder for the update files.
const PROCESSED_FOLDER = 'Processed CSV'; // Folder to hold processed files.
const SHEET_REPORT_NAME = 'Copy of Market Monitor'; // Name of destination spreadsheet.
// Application settings
const CSV_HEADER_EXIST = true; // Set to true if CSV files have a header row, false if not.
const HANDLER_FUNCTION = 'updateApplicationSheet'; // Function called by installable trigger to run data processing.
/**
* Installs a time-driven trigger that runs daily to import CSVs into the main application spreadsheet.
* Prior to creating a new instance, removes any existing triggers to avoid duplication.
*
* Called by setupSample() or run directly setting up the application.
*/
function installTrigger() {
// Checks for an existing trigger to avoid creating duplicate instances.
// Removes existing if found.
const projectTriggers = ScriptApp.getProjectTriggers();
for (var i = 0; i < projectTriggers.length; i++) {
if (projectTriggers[i].getHandlerFunction() == HANDLER_FUNCTION) {
console.log(`Existing trigger with Handler Function of '${HANDLER_FUNCTION}' removed.`);
ScriptApp.deleteTrigger(projectTriggers[i]);
}
}
// Creates the new trigger.
let newTrigger = ScriptApp.newTrigger(HANDLER_FUNCTION)
.timeBased()
.atHour(23) // Runs at 11 PM in the time zone of this script.
.everyDays(1) // Runs once per day.
.create();
console.log(`New trigger with Handler Function of '${HANDLER_FUNCTION}' created.`);
}
/**
* Handler function called by the trigger created with the "installTrigger" function.
* Run this directly to execute the entire automation process of the application with a trigger.
*
* Process: Iterates through CSV files located in the source folder (SOURCE_FOLDER),
* and appends them to the end of destination spreadsheet (SHEET_REPORT_NAME).
* Successfully processed CSV files are moved to the processed folder (PROCESSED_FOLDER) to avoid duplication.
* Sends summary email with status of the import.
*/
function updateApplicationSheet() {
// Gets application & supporting folders.
const folderAppPrimary = getApplicationFolder_(APP_FOLDER);
const folderSource = getFolder_(SOURCE_FOLDER);
const folderProcessed = getFolder_(PROCESSED_FOLDER);
// Gets the application's destination spreadsheet {Spreadsheet object}
let objSpreadSheet = getSpreadSheet_(SHEET_REPORT_NAME, folderAppPrimary)
// Creates arrays to track every CSV file, categorized as processed sucessfully or not.
let filesProcessed = [];
let filesNotProcessed = [];
// Gets all CSV files found in the source folder.
let cvsFiles = folderSource.getFilesByType(MimeType.CSV);
// Iterates through each CSV file.
while (cvsFiles.hasNext()) {
let csvFile = cvsFiles.next();
let isSuccess;
// Appends the unprocessed CSV data into the Google Sheets spreadsheet.
isSuccess = processCsv_(objSpreadSheet, csvFile);
if (isSuccess) {
// Moves the processed file to the processed folder to prevent future duplicate data imports.
csvFile.moveTo(folderProcessed);
// Logs the successfully processed file to the filesProcessed array.
filesProcessed.push(csvFile.getName());
console.log(`Successfully processed: ${csvFile.getName()}`);
} else if (!isSuccess) {
// Doesn't move the unsuccesfully processed file so that it can be corrected and reprocessed later.
// Logs the unsuccessfully processed file to the filesNotProcessed array.
filesNotProcessed.push(csvFile.getName());
console.log(`Not processed: ${csvFile.getName()}`);
}
}
// Prepares summary email.
// Gets variables to link to this Apps Script project.
const scriptId = ScriptApp.getScriptId();
const scriptUrl = DriveApp.getFileById(scriptId).getUrl();
const scriptName = DriveApp.getFileById(scriptId).getName();
// Gets variables to link to the main application spreadsheet.
const sheetUrl = objSpreadSheet.getUrl()
const sheetName = objSpreadSheet.getName()
// Gets user email and timestamp.
const emailTo = Session.getEffectiveUser().getEmail();
const timestamp = Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "yyyy-MM-dd HH:mm:ss zzzz");
// Prepares lists and counts of processed CSV files.
let processedList = "";
const processedCount = filesProcessed.length
for (const processed of filesProcessed) {
processedList += processed + '<br>'
};
const unProcessedCount = filesNotProcessed.length
let unProcessedList = "";
for (const unProcessed of filesNotProcessed) {
unProcessedList += unProcessed + '\n'
};
// Assembles email body as html.
const eMailBody = `${APP_TITLE} ran an automated process at ${timestamp}.<br><br>` +
`<b>Files successfully updated:</b> ${processedCount}<br>` +
`${processedList}<br>` +
`<b>Files not updated:</b> ${unProcessedCount}<br>` +
`${unProcessedList}<br>` +
`<br>View all updates in the Google Sheets spreadsheet ` +
`<b><a href= "${sheetUrl}" target=\"_blank\">${sheetName}</a></b>.<br>` +
`<br>*************<br>` +
`<br>This email was generated by Google Apps Script. ` +
`To learn more about this application or make changes, open the script project below: <br>` +
`<a href= "${scriptUrl}" target=\"_blank\">${scriptName}</a>`
MailApp.sendEmail({
to: emailTo,
subject: `Automated email from ${APP_TITLE}`,
htmlBody: eMailBody
});
console.log(`Email sent to ${emailTo}`);
}
/**
* Parses CSV data into an array and appends it after the last row in the destination spreadsheet.
*
* @return {boolean} true if the update is successful, false if unexpected errors occur.
*/
function processCsv_(objSpreadSheet, csvFile) {
try {
// Gets the first sheet of the destination spreadsheet.
let sheet = objSpreadSheet.getSheets()[0];
// Parses CSV file into data array.
let data = Utilities.parseCsv(csvFile.getBlob().getDataAsString());
// Omits header row if application variable CSV_HEADER_EXIST is set to 'true'.
if (CSV_HEADER_EXIST) {
data.splice(0, 1);
}
// Gets the row and column coordinates for next available range in the spreadsheet.
let startRow = sheet.getLastRow() + 1;
let startCol = 1;
// Determines the incoming data size.
let numRows = data.length;
let numColumns = data[0].length;
// Appends data into the sheet.
sheet.getRange(startRow, startCol, numRows, numColumns).setValues(data);
return true; // Success.
} catch {
return false; // Failure. Checks for CSV data file error.
}
}
它是最后一个函数 processCsv_()
尝试更改行:
let sheet = objSpreadSheet.getSheets()[0];
与:
let sheet = objSpreadSheet.getSheetByName(csvFile.getName());
更新
如果你想替换工作表上的所有数据(而不是追加),可能你可以通过更改此行(在相同的函数 processCsv_()
中)来实现:
sheet.getRange(startRow, startCol, numRows, numColumns).setValues(data);
这样:
sheet.clearContents().getRange(1, startCol, numRows, numColumns).setValues(data);