Answers / Question 12

Import every CSV in a Google Drive folder into one sheet

An Apps Script that reads every CSV in a Drive folder, keeps a single header row, skips blank lines and writes everything to one tab in a single call.

The problem

Exports arrive as separate CSV files in a Drive folder, and you want them combined into one tab automatically rather than importing each file by hand.

Inspired by a public question on Stack Overflow. The problem above is described in our own words and the solution below is ours.

The fix

  1. Copy the folder ID (the long code at the end of the folder's URL) into folderId.
  2. Paste the code into Extensions → Apps Script in the destination spreadsheet.
  3. Run mergeCsvs and approve. It rebuilds the Merged tab each time.
Code.gsApps Script
// Combine every CSV in one Drive folder into a single tab, keeping one header row.
const CSV_MERGE = {
  folderId: 'PASTE_FOLDER_ID',   // the long ID at the end of the folder's URL
  sheetName: 'Merged'
};

function combineCsvRows(tables) {
  let header = null;
  const out = [];
  tables.forEach(function (rows) {
    if (!rows.length) return;
    if (!header) { header = rows[0]; out.push(header); }
    for (let i = 1; i < rows.length; i++) {                         // skip each file's own header
      if (rows[i].some(function (c) { return String(c).trim() !== ''; })) out.push(rows[i]);
    }
  });
  const width = out.reduce(function (m, r) { return Math.max(m, r.length); }, 0);
  return out.map(function (r) { return r.concat(Array(width - r.length).fill('')); });   // setValues needs a rectangle
}

function mergeCsvs() {
  const files = DriveApp.getFolderById(CSV_MERGE.folderId).getFilesByType(MimeType.CSV);
  const tables = [];
  while (files.hasNext()) tables.push(Utilities.parseCsv(files.next().getBlob().getDataAsString()));
  const out = combineCsvRows(tables);
  const ss = SpreadsheetApp.getActive();
  const sh = ss.getSheetByName(CSV_MERGE.sheetName) || ss.insertSheet(CSV_MERGE.sheetName);
  sh.clearContents();
  if (out.length) sh.getRange(1, 1, out.length, out[0].length).setValues(out);
}

Two bugs this avoids

Good to know

The script's logic is unit-tested against a simulated spreadsheet before publishing. Always try new automations on a copy of your sheet first.