I am using the script below, working very well (thanks to Ted Bell).
But I need to adapt it because I need the CSV file saved in the same folder as the spreadsheet.
Could you please help me with this matter?
The code below creates a new folder each time on My Drive.
The CSV is ok regarding its name and its format: with semicolon delimiter.
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var csvMenuEntries = [{
name: "export as csv file",
functionName: "saveAsCSV"
}];
ss.addMenu("CSV Export", csvMenuEntries);
var a1 = ss.getRange("A1").getValue();
var name = "MyCompanyName_"+a1;
ss.rename(name);
};
function saveAsCSV() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ssname = ss.getName();
var sheet = ss.getActiveSheet();
var sheetname = sheet.getSheetName();
//Logger.log("DEBUG: the name of the spreadsheet is "+ssname);//DEBUG
//Logger.log("DEBUG: the sheet name is "+sheetname);// DEBUG
//// create a folder from the name of the spreadsheet
var folder = DriveApp.createFolder(ssname.toLowerCase() + '_' +
sheetname.toLowerCase().replace(/ /g, '_') + '_csv_' + new Date().getTime());
//Logger.log("DEBUG: the folder name is "+folder);//DEBUG
// append ".csv" extension to the sheet name
var fileName = ssname + '_' + sheetname + ".csv";
// convert all available sheet data to csv format
var csvFile = so_4225484202(fileName);
// create a file in the Docs List with the given name and the csv data
folder.createFile(fileName, csvFile);
Browser.msgBox('Files are waiting in a folder named ' + folder.getName());
}
function isValidDate(date) {
return date && Object.prototype.toString.call(date) === "[object Date]" && !isNaN(date);
}
function so_4225484202(filename) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var paramsheet = ss.getSheetByName("Parameters");
var linearray = [];
var rowdata = [];
var csv = "";
var fieldvalue = "";
var param = paramsheet.getRange(2, 2, 2);
var paramValues = param.getValues();
//Logger.log("DEBUG: parameters = "+param.getA1Notation());//DEBUG
var fieldDelimiter = paramValues[0][0];
var textDelimiter = paramValues[1][0];
//Logger.log("DEBUG: field delimiter: "+fieldDelimiter+", text delim:
"+textDelimiter);//DEBUG
var rangeData = sheet.getDataRange();
var lastColumn = rangeData.getLastColumn();
var lastRow = rangeData.getLastRow();
//Logger.log("DEBUG: lastColumn: "+lastColumn+", lastRow: "+lastRow);//DEBUG
// Get array of values in the Data Range
var rangeValues = rangeData.getValues();
// Loop through array and build values for csv
for (i = 0; i < lastRow; i++) {
for (j = 0; j < lastColumn; j++) {
var value = rangeValues[i][j];
var theType = typeof value;
if (theType === "object") {
var testdate = isValidDate(value);
//Logger.log("if typeof is object: testdate: "+testdate);//DEBUG
var testtype = typeof testdate;
if (testtype === "boolean") {
// variable is a boolean
//Logger.log("Its a date");//DEBUG
theType = "date";
} else {
//Logger.log("Its not a date");//DEBUG
}
}
if (theType === "string") {
value = textDelimiter + value + textDelimiter;
}
rowdata.push([value]);
};
//Logger.log("DEBUG: rowdata: "+rowdata);//DEBUG
csv += rowdata.join(fieldDelimiter) + "\n";
var rowdata = [];
};
//Logger.log("DEBUG: csv: "+csv);//DEBUG
return csv;
}
You want to create the CSV file in the same folder of the active Spreadsheet.
You want to achieve this by modifying your script.
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
Modification point:
In order to retrieve the folder of the active Spreadsheet, DriveApp.getFileById(ss.getId()).getParents().next() is used for retrieving the folder.
Modified script:
Please modify the function of saveAsCSV() in your script as follows.
From:
var folder = DriveApp.createFolder(ssname.toLowerCase() + '_' + sheetname.toLowerCase().replace(/ /g, '_') + '_csv_' + new Date().getTime());
To:
var folder = DriveApp.getFileById(ss.getId()).getParents().next();
References:
getId()
getFileById()
getParents()
If I misunderstood your question and this was not the direction you want, I apologize.
Related
I have the following code which I cobbled from answers
function myFunction() {
var sheetName = "QR CODE DATA"; // Sheet name
var folderId = "FOLDER NAME"; // Folder ID
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(sheetName);
var url = "https://api.qrserver.com/v1/create-qr-code/?size=120x120&data=";
var keys = ["-Tipo:", "-UbicaciĆ³n:", "-# registro:", "-ID-C:", "-# Serial:", "-Pas:", "-Di I:", "-Asi:", "-RP:", "-Ar:"];
var values = sheet.getRange(2, 2, sheet.getLastRow() - 1, 11).getValues()
.filter(function(e) {return e.some(function(f) {return f})})
.map(function(row) { row.splice(4, 1); return row;
}); var length = values.length;
var reqs = values.map(function(e) {return {url: url + encodeURIComponent(keys.map(function(f, j) {return f + e[j]}).join("\r"))}});
var res = UrlFetchApp.fetchAll(reqs);
res.forEach(function(r, i) {
var blob = r.getBlob().setName(length == values.length ? "row" + (i + 2) + ".png" : "row" + (length + 1) + ".png");
DriveApp.getFolderById(folderId).createFile(blob); }); }
But this saves the PNG files into the directory as 'Row 2' 'Row 3' etc...
I would like this to use the data in Column A to name the files, but I dont know where to start.
Any help appreciated.
Answer for 1st question:
From your following question,
But this saves all of the files into the directory as 'Row 2' 'Row 3' etc...
I would like this to use the data in Column A to name the files
In this case, how about the following modification?
Modified script:
function myFunction() {
var sheetName = "QR CODE DATA"; // Sheet name
var folderId = "FOLDER NAME"; // Folder ID
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(sheetName);
var url = "https://api.qrserver.com/v1/create-qr-code/?size=120x120&data=";
var keys = ["-Tipo:", "-UbicaciĆ³n:", "-# registro:", "-ID-C:", "-# Serial:", "-Pas:", "-Di I:", "-Asi:", "-RP:", "-Ar:"];
// -- Modified
var filteredValues = sheet.getRange(2, 1, sheet.getLastRow() - 1, 12).getDisplayValues()
.filter(function (e) { return e.some(function (f) { return f }) });
var filenames = filteredValues.map(function (r) { return r.splice(0, 1) });
var values = filteredValues.map(function (row) {
row.splice(4, 1);
return row;
});
// ---
var reqs = values.map(function (e) { return { url: url + encodeURIComponent(keys.map(function (f, j) { return f + e[j] }).join("\r")) } });
var res = UrlFetchApp.fetchAll(reqs);
res.forEach(function (r, i) {
var blob = r.getBlob().setName(filenames[i]); // Modified
DriveApp.getFolderById(folderId).createFile(blob);
});
}
When this script is run, the values are retrieved from the column "A" and they are used as the filenames of the files.
Answer for 2nd question:
I thought that the following question is your 2nd question. When I saw your 2nd question, unfortunately, it is largely different from your 1st question.
What I am trying to do is generate QR Codes from the values of a google sheet. The URL's that I wish to generate a QR Code for are located in Column B of a Sheet. Column A contains the name of the item the QR Code is for, so, I need to create a QR Code File as a PNG or JPEG and save it to a google drive folder, using the URL from column B, with the filename of column A
From this 2nd question, the sample script is as follows.
Sample script:
function myFunction() {
var sheetName = "QR CODE DATA"; // Sheet name
var folderId = "FOLDER NAME"; // Folder ID
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(sheetName);
var values = sheet.getRange("A2:B" + sheet.getLastRow()).getDisplayValues().filter(([a, b]) => a && b);
var reqs = values.map(([, url]) => ({ url }));
var res = UrlFetchApp.fetchAll(reqs);
res.forEach(function (r, i) {
var blob = r.getBlob().setName(values[i][0]);
DriveApp.getFolderById(folderId).createFile(blob);
});
}
I'm trying to create an export to csv apps script but it will not delete existing csv files sitting in the same folder. I would like to either trash them or overwrite them.
Here's the code I've already tried
function saveAsCSV() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
// create a folder from the name of the spreadsheet
// var folder = DriveApp.createFolder(ss.getName().toLowerCase().replace(/ /g,'_') + '_csv_' + new Date().getTime());
// var folder = DriveApp.createFolder(ss.getName().toLowerCase().replace(/ /g,'_') + '_csv_');
for (var i = 0 ; i < sheets.length ; i++) {
var sheet = sheets[i];
// append ".csv" extension to the sheet name
fileName = sheet.getName() + ".csv";
// convert all available sheet data to csv format
var csvFile = convertRangeToCsvFile_(fileName, sheet);
var file = DriveApp.getFileById(ss.getId());
var folder = file.getParents();
folder = folder.next();
// loop through files and delete ones with existing name
var existingfiles = folder.getFiles()
for (var j = 0 ; j<existingfiles.length;j++){
var existingfile = existingfiles[j].next()
if (existingfile.getName()!=ss.getName()){
//to delete
//existingfile.setTrashed(true);
folder.removeFile(existingfile);
}
}
//create new file
folder.createFile(fileName, csvFile);
}
}
I'd expect all files that don't share the same name as the spreadsheet in that folder to get removed, then a csv for each tab to get created. Instead, I get duplicates of each csv file.
Thanks a lot for you help. The while loop helped a bunch. Here's what worked for me in the end.
function saveAsCSV() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var file = DriveApp.getFileById(ss.getId());
var folder = file.getParents();
folder = folder.next();
// loop through files and delete ones with existing name
var xfiles=folder.getFiles();
while(xfiles.hasNext()) {
var fi=xfiles.next();
if(fi.getMimeType()!=MimeType.GOOGLE_SHEETS){fi.setTrashed(true);}
}
// create new csv files
for (var i = 0 ; i < sheets.length ; i++) {
var sheet = sheets[i];
// append ".csv" extension to the sheet name
fileName = sheet.getName() + ".csv";
// convert all available sheet data to csv format
var csvFile = convertRangeToCsvFile_(fileName, sheet);
//create new file
folder.createFile(fileName, csvFile);
}
};
Try this:
function trashOthers() {
var ss=SpreadsheetApp.getActive();
var shts=ss.getSheets();
var fldr=DriveApp.getFileById(ss.getId()).getParents();
var n=0;
while(fldr.hasNext()) {
var folder=fldr.next();
n++;
}
if(n>1){throw('More than one Folder');}
for (var i=0;i<shts.length;i++) {
var sh=shts[i];
var fileName=sh.getName() + ".csv";
var csvFile=convertRangeToCsvFile_(fileName, sh);
var xfiles=folder.getFiles();
while(xfiles.hasNext()) {
xfiles.next().setTrashed(true);
}
folder.createFile(fileName, csvFile);
}
}
Perhaps this is better:
function deleteOthers() {
var ss=SpreadsheetApp.getActiveSpreadsheet();
var shts=ss.getSheets();
var fldr=DriveApp.getFileById(ss.getId()).getParents();
var n=0;
while(fldr.hasNext()) {
var folder=fldr.next();
n++;
}
if(n>1){throw('More than one Folder');}
for (var i=0;i<shts.length;i++) {
var sh=shts[i];
var fileName=sh.getName() + ".csv";
var csvFile=convertRangeToCsvFile_(fileName, sh);
var xfiles=folder.getFiles();
while(xfiles.hasNext()) {
var fi=xfiles.next();
if(fi.getMimeType()!=MimeType.GOOGLE_SHEETS){fi.setTrashed(true);}
}
folder.createFile(fileName, csvFile);
}
}
I used deleteOthers() and trashothers() both are deleting the google form which writes data into csv
I picked this code online and I am trying to check if the value in the column B is 'Done' then the value will be be copied otherwise not. Here is the code I am using:
copy sheet function below will copy the datat from source sheet to destination sheet but what I want that it will only pick the row if the col B value contains Done
function copySheet() {
var sourceSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Source");
var destSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Destination");
var columns_to_be_copied =['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U'];
var columns_to_be_pasted =['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U'];
for (column in columns_to_be_copied) {
var copy_range_string = columns_to_be_copied[column] + ':' + columns_to_be_copied[column];
var paste_range_string = columns_to_be_pasted[column] + ':' + columns_to_be_pasted[column];
var source = sourceSheet.getRange(copy_range_string);
var destination = destSheet.getRange(paste_range_string);
if(findInColumn('A','Done') !== -1) {
copyTo(source,destination );
}
}
}
function copyTo(source,destination) {
var sourceSheet = source.getSheet();
var destSheet = destination.getSheet();
var sourceData = source.getValues();
var dest = destSheet.getRange(
destination.getRow(), // Top row of destination
destination.getColumn(), // left col of destination
sourceData.length, // # rows in source
sourceData[0].length); // # cols in source (elements in first row)
dest.setValues(sourceData);
SpreadsheetApp.flush();
}
function findInColumn(column, data) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sprint");
var column = sheet.getRange(column + ":" + column); // like A:A
var values = column.getValues();
var row = 0;
while (values[row] && values[row][0] !== data) {
row++;
}
if (values[row][0] === data)
return row+1;
else
return -1;
}
As I am a fan of simple and easy to read (even after long time) solutions I would suggest the following script:
function main() {
var sourceSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Source');
var destinationSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Destination');
copyFromTo(sourceSheet, destinationSheet);
}
function copyFromTo(sourceSheet, destinationSheet) {
const ColumnB = 1; //Array indexing starts from 0
const FilterValue = 'Done';
var sourceValues = sourceSheet.getSheetValues(1, 1, 100, 28); //startRow, startColumn, numRows, numColumns
var filteredValues = sourceValues.filter(function(row) {
return row[ColumnB] === FilterValue;
});
destinationSheet.getRange(1, 1, filteredValues.length, filteredValues[0].length).setValues(filteredValues);
}
It's about the same function. I just modified it to facilitate my debugging process. It copies the columns from source to destination if Sprint has "Done" in that column.
function copySheet() {
var srcsh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Source");
var dessh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Destination");
var from = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U'];
var to = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U'];
for(var i=0;i<from.length;i++) {
var fromrg = from[i] + ':' + from[i];
var torg = to[i] + ':' + to[i];
var src = srcsh.getRange(fromrg);
var des = dessh.getRange(torg);
if(findInColumn(from[i],'Done')!== -1){
src.copyTo(des);
}
}
}
function findInColumn(col, data) {
var col=col || 'A';//This is here for initial testing so I could run the function without parameters.
var data=data || 'Done';
var sh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sprint");
var rg = sh.getRange(col + "1:" + col + sh.getMaxRows());//MaxRows is kind of big but I was not sure what else you'd like to do and I dont know what your Sprint sheet looks like.
var vA = rg.getValues();
var rv=-1;
for(var i=0;i<vA.length;i++){
if(vA[i][0]==data){
rv=i+1;
break;
}
}
return rv;
}
I see that you changed the question a bit. This function looks in your sprint sheet as you show in your answer and copies from source to destination only those columns that have the word "Done" on any row of that column. But it checks every column in your "columns_to_be_copied" which I called "from". Originally, that's what your function was trying to do. So I just wanted to be clear what this function is doing. If it's not what you want then leave a comment and I'll delete it.
I have a Google sheet want to export as CSV file. But there are 2 columns in the sheet I don't want to export.
For example, in the picturecolumn, I don't want to export column "N" and "P"
Here are the Apps Script code I wrote for export
function menu() {
var ui = SpreadsheetApp.getUi();
var menu = ui.createMenu('Menu');
var item = menu.addItem('PICC', 'picc');
var item2 = menu.addItem('Export to CSV', 'csv');
item.addToUi();
item2.addToUi()
};
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var csvMenuEntries = [{name: "Download Primary Time File", functionName: "saveAsCSV"}];
//ss.addMenu("Creating a Timetable", csvMenuEntries);
var ui = SpreadsheetApp.getUi();
var menu = ui.createMenu('Menu');
var item = menu.addItem('PICC', 'picc');
var item2 = menu.addItem('Export to CSV', 'csv');
item.addToUi();
item2.addToUi()
};
function saveAsCSV() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("sheet1");
// create a folder from the name of the spreadsheet
var folder = DriveApp.createFolder(ss.getName().toLowerCase().replace(/ /g,'_') + '_csv_' + new Date().getTime());
// append ".csv" extension to the sheet name
fileName = sheet.getName() + ".csv";
// convert all available sheet data to csv format
var csvFile = convertRangeToCsvFile_(fileName, sheet);
// create a file in the Docs List with the given name and the csv data
var file = folder.createFile(fileName, csvFile);
//File downlaod
var downloadURL = file.getDownloadUrl().slice(0, -8);
showurl(downloadURL);
}
function showurl(downloadURL) {
var app = UiApp.createApplication().setHeight('60').setWidth('150');
//Change what the popup says here
app.setTitle("Your timetable CSV is ready!");
var panel = app.createPopupPanel()
//Change what the download button says here
var link = app.createAnchor('Click here to download', downloadURL);
panel.add(link);
app.add(panel);
var doc = SpreadsheetApp.getActive();
doc.show(app);
}
function convertRangeToCsvFile_(csvFileName, sheet) {
// get available data range in the spreadsheet
var activeRange = sheet.getDataRange();
try {
var data = activeRange.getValues();
var csvFile = undefined;
// loop through the data in the range and build a string with the csv data
if (data.length > 1) {
var csv = "";
for (var row = 1; row < data.length; row++) {
for (var col = 0; col < data[row].length; col++) {
if (data[row][col].toString().indexOf(",") != -1) {
data[row][col] = "\"" + data[row][col] + "\"";
}
}
// join each row's columns
// add a carriage return to end of each row, except for the last one
if (row < data.length-1) {
csv += data[row].join(",") + "\r\n";
}
else {
csv += data[row];
}
}
csvFile = csv;
}
return csvFile;
}
catch(err) {
Logger.log(err);
Browser.msgBox(err);
}
}
As you can see, I used for loop to export the rows and columns, how can I make change to let the two columns not showing in the export CSV
How about this modification?
Modification points :
Modify convertRangeToCsvFile_().
From data retrieved by getValues(), it removes the columns "N" and "P".
In order to reflect this, please modify as follows.
From :
var data = activeRange.getValues();
var csvFile = undefined;
To :
var data = activeRange.getValues();
data = data.map(function(e){return e.filter(function(_, i){return i != 13 && i != 15})}); // Added
var csvFile = undefined;
If I misunderstand your question, please tell me. I would like to modify it.
I have an spreadsheet with 4 sheets that I need in .CSV format. By now, I have a script that sends me the .csv files to my email, but I need to automacally save it into a google drive folder, do you have any ideas ?
This is my actual script:
function Csv(){
var ss = SpreadsheetApp.openById('spreadsheetID');
var url1 = "https://docs.google.com/spreadsheets/d/spreadsheetID/gviz/tq?tqx=out:csv&sheet=Sheet1";
var url2 = "https://docs.google.com/spreadsheets/d/spreadsheetID/gviz/tq?tqx=out:csv&sheet=Sheet2";
var url3 = "https://docs.google.com/spreadsheets/d/spreadsheetID/gviz/tq?tqx=out:csv&sheet=Sheet3";
var url4 = "https://docs.google.com/spreadsheets/d/spreadsheetID/gviz/tq?tqx=out:csv&sheet=Sheet4";
var params = {
method : "get",
headers : {"Authorization": "Bearer " + ScriptApp.getOAuthToken()},
muteHttpExceptions: true
};
var blob1 = UrlFetchApp.fetch(url1, params).getBlob();
blob1.setName("File1" +".csv");
var blob2 = UrlFetchApp.fetch(url2, params).getBlob();
blob2.setName("File2" +".csv");
var blob3 = UrlFetchApp.fetch(url3, params).getBlob();
blob3.setName("File3" +".csv");
var blob4 = UrlFetchApp.fetch(url4, params).getBlob();
blob4.setName("File4" +".csv");
MailApp.sendEmail("myemail#gmail.com", "Subject", "Body", {attachments: [blob1,blob2,blob3,blob4]});
}
Thanks!
you can check out the below script. Hope it will help you to manage your sheets as you expected.
/*
* script to export data in all sheets in the current spreadsheet as individual csv files
* files will be named according to the name of the sheet
* author: Shotez
*/
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var csvMenuEntries = [{name: "export as csv files", functionName: "saveAsCSV"}];
ss.addMenu("csv", csvMenuEntries);
};
function saveAsCSV() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
// create a folder from the name of the spreadsheet
var folder = DriveApp.createFolder(ss.getName().toLowerCase().replace(/ /g,'_') + '_csv_' + new Date().getTime());
for (var i = 0 ; i < sheets.length ; i++) {
var sheet = sheets[i];
// append ".csv" extension to the sheet name
fileName = sheet.getName() + ".csv";
// convert all available sheet data to csv format
var csvFile = convertRangeToCsvFile_(fileName, sheet);
// create a file in the Docs List with the given name and the csv data
folder.createFile(fileName, csvFile);
}
Browser.msgBox('Files are waiting in a folder named ' + folder.getName());
}
function convertRangeToCsvFile_(csvFileName, sheet) {
// get available data range in the spreadsheet
var activeRange = sheet.getDataRange();
try {
var data = activeRange.getValues();
var csvFile = undefined;
// loop through the data in the range and build a string with the csv data
if (data.length > 1) {
var csv = "";
for (var row = 0; row < data.length; row++) {
for (var col = 0; col < data[row].length; col++) {
if (data[row][col].toString().indexOf(",") != -1) {
data[row][col] = "\"" + data[row][col] + "\"";
}
}
// join each row's columns
// add a carriage return to end of each row, except for the last one
if (row < data.length-1) {
csv += data[row].join(",") + "\r\n";
}
else {
csv += data[row];
}
}
csvFile = csv;
}
return csvFile;
}
catch(err) {
Logger.log(err);
Browser.msgBox(err);
}
}
After running the script just check your google drive for the folder which is containing the .csv files.