将 CSV 文件转换为 Excel 工作簿

许多服务将数据导出为逗号分隔值 (CSV) 文件。 此解决方案以 .xlsx 文件格式自动将这些 CSV 文件转换为 Excel 工作簿的过程。 它使用 Power Automate 流在 OneDrive 文件夹中查找扩展名为 .csv 的文件,并使用 Office 脚本将数据从 .csv 文件复制到新的 Excel 工作簿中。

解决方案

  1. 将 .csv 文件和空白“模板”.xlsx 文件存储在 OneDrive 文件夹中。
  2. 创建 Office 脚本以将 CSV 数据分析为某个范围。
  3. 创建 Power Automate 流以读取 .csv 文件并将其内容传递给脚本。

示例文件

下载 convert-csv-example.zip 以获取 Template.xlsx 文件和两个示例 .csv 文件。 将文件提取到 OneDrive 中的文件夹中。 此示例假定文件夹名为“output”。

将以下脚本添加到示例工作簿。 在 Excel 中,使用 “自动化>新脚本” 粘贴代码并保存脚本。 将其另存为 转换 CSV ,然后亲自尝试示例!

示例代码:将逗号分隔值插入工作簿

/**
 * Convert incoming CSV data into a range and add it to the workbook.
 */
function main(workbook: ExcelScript.Workbook, csv: string) {
  let sheet = workbook.getWorksheet("Sheet1");

  // Remove any Windows \r characters.
  csv = csv.replace(/\r/g, "");

  // Split each line into a row.
  // NOTE: This will split values that contain new line characters.
  let rows = csv.split("\n");

  /*
   * For each row, match the comma-separated sections.
   * For more information on how to use regular expressions to parse CSV files,
   * see this Stack Overflow post: https://stackoverflow.com/a/48806378/9227753
   */
  const csvMatchRegex = /(?:,|\n|^)("(?:(?:"")*[^"]*)*"|[^",\n]*|(?:\n|$))/g
  rows.forEach((value, index) => {
    if (value.length > 0) {
      let row = value.match(csvMatchRegex);
    
      // Check for blanks at the start of the row.
      if (row[0].charAt(0) === ',') {
        row.unshift("");
      }
  
      // Remove the preceding comma and surrounding quotation marks.
      row.forEach((cell, index) => {
        cell = cell.indexOf(",") === 0 ? cell.substring(1) : cell;
        row[index] = cell.indexOf("\"") === 0 && cell.lastIndexOf("\"") === cell.length - 1 ? cell.substring(1, cell.length - 1) : cell;
      });
    
      // Create a 2D array with one row.
      let data: string[][] = [];
      data.push(row);
  
      // Put the data in the worksheet.
      let range = sheet.getRangeByIndexes(index, 0, 1, data[0].length);
      range.setValues(data);
    }
  });

  // Add any formatting or table creation that you want.
}

Power Automate 流:创建新的 .xlsx 文件

  1. 登录到 Power Automate 并创建新的 计划云流

  2. 将流设置为每隔“1”“天 重复 ”,然后选择“ 创建”。

  3. 获取模板 Excel 文件。 这是所有已转换 .csv 文件的基础。 在流生成器中 + ,选择按钮和 “添加操作”。 选择OneDrive for Business连接器的“获取文件内容”操作。 提供“Template.xlsx”文件的文件路径。

    • 文件:/output/Template.xlsx
  4. 重命名 “获取文件内容” 步骤。 在操作任务窗格中选择当前标题“获取文件内容”。 将名称更改为“获取 Excel 模板”。

    操作任务窗格中已完成OneDrive for Business连接器,已重命名为“获取 Excel 模板”。

  5. 添加一个操作,用于获取“output”文件夹中的所有文件。 选择OneDrive for Business连接器的“在文件夹中列出文件”操作。 提供包含 .csv 文件的文件夹路径。

    • 文件夹:/output

    操作任务窗格中已完成OneDrive for Business连接器。

  6. 添加条件,以便流仅对 .csv 文件运行。 添加 “条件” 控件操作。 对 Condition 使用以下值。

    • 选择一个值名称 (文件夹) 中的“列出文件” 中的 动态内容。 请注意,此动态内容具有多个结果,因此 For each 控件括在 Condition 中。
    • 下拉列表中的 (结尾)
    • 选择值:.csv

    操作任务窗格中已完成的条件控件。

  7. 流的其余部分位于 “如果是 ”部分下,因为我们只想对 .csv 文件进行操作。 通过添加使用OneDrive for Business连接器的“获取文件内容”操作的操作来获取单个 .csv 文件。 使用文件夹中列出文件中动态内容的 ID

    • 文件id (“ 列出文件夹中的文件 ”步骤) 中的动态内容
  8. 将新的 “获取文件内容 ”步骤重命名为“获取 .csv 文件”。 这有助于将此文件与 Excel 模板区分开来。

    操作任务窗格中已完成的“获取 .csv 文件”操作。

  9. 使用 Excel 模板作为基内容制作新的 .xlsx 文件。 添加使用 OneDrive for Business 连接器的“创建文件”操作的操作。 使用以下值。

    • 文件夹路径:/output
    • 文件名名称不带扩展名.xlsx (从“列出文件夹中的文件”中选择“名称”,并在) 后手动键入“.xlsx”
    • 文件内容获取 Excel 模板) 的文件内容 (动态内容

    操作任务窗格中已完成的“创建文件”步骤。

  10. 运行脚本以将数据复制到新工作簿中。 添加 Excel Online (Business) 连接器的 “运行”脚本 操作。 对操作使用以下值。

    • 位置:OneDrive for Business
    • 文档库:OneDrive
    • 文件创建文件) (动态内容的 ID
    • 脚本:转换 CSV
    • csv获取 .csv 文件) (动态内容

    操作任务窗格中已完成的“运行脚本”步骤。

  11. 保存流。 流设计器应如下图所示。

    已完成流的关系图,其中显示了每个控件的前面有三个步骤,每个控件的 内有一个条件控件,在条件的真实路径下显示三个步骤。

  12. 使用流编辑器页上的“ 测试 ”按钮,或通过“我的流”选项卡运行 。请务必在出现提示时允许访问。

  13. 应在“输出”文件夹中找到新的 .xlsx 文件,以及原始 .csv 文件。 新工作簿包含与 CSV 文件相同的数据。

疑难解答

脚本测试

若要在不使用 Power Automate 的情况下测试脚本,请在使用前为其 csv 分配一个值。 添加以下代码作为函数的第一行, main 然后选择“ 运行”。

  csv = `1, 2, 3
         4, 5, 6
         7, 8, 9`;

分号分隔的文件和其他备用分隔符

某些区域使用分号 (';') 分隔单元格值,而不是逗号。 在这种情况下,需要更改脚本中的以下行。

  1. 将逗号替换为正则表达式语句中的分号。 这从 let row = value.match开始。

    let row = value.match(/(?:;|\n|^)("(?:(?:"")*[^"]*)*"|[^";\n]*|(?:\n|$))/g);
    
  2. 将逗号替换为空白第一个单元格检查中的分号。 这从 if (row[0].charAt(0)开始。

    if (row[0].charAt(0) === ';') {
    
  3. 将逗号替换为行中的分号,从显示的文本中删除分隔字符。 这从 row[index] = cell.indexOf开始。

       row[index] = cell.indexOf(";") === 0 ? cell.substr(1) : cell;
    

注意

如果文件使用制表符或任何其他字符来分隔值,请将上述替换中的 替换为 ;\t 或正在使用的任何字符。

大型 CSV 文件

如果文件包含数十万个单元格,则可以达到 Excel 数据传输限制。 需要强制脚本定期与 Excel 同步。 执行此操作的最简单方法是在处理一批行后调用 console.log 。 添加以下代码行以执行此操作。

  1. 在 之前 rows.forEach((value, index) => {,添加以下行。

      let rowCount = 0;
    
  2. 在 之后 range.setValues(data);,添加以下代码。 请注意,根据列数,可能需要减少 5000 到较小的数字。

      rowCount++;
      if (rowCount % 5000 === 0) {
        console.log("Syncing 5000 rows.");
      }
    

警告

如果 CSV 文件非常大,则可能 在 Power Automate 中出现超时问题。 在将 CSV 数据转换为 Excel 工作簿之前,需要将 CSV 数据划分为多个文件。

重音符和其他 unicode 字符

具有 unicode 特定字符的文件(例如重音元音,如 é)需要使用正确的编码进行保存。 对于 .csv 文件,Power Automate 的 OneDrive 连接器文件创建默认为 ANSI。 如果要在 Power Automate 中创建 .csv 文件,则需要在逗号分隔值之前 (BOM) 添加字节顺序标记 。 对于 UTF-8,请将写入 .csv 文件操作的文件内容替换为表达式 concat(uriComponentToString('%EF%BB%BF'), <CSV Input>) (其中 <CSV Input> 是原始 CSV 数据) 。

请注意,此示例不会在流中创建 .csv 文件,因此需要在流的自定义部分进行此更改。 如果不控制这些文件的创建方式,也可以使用 BOM 读取和重写 .csv 文件。

周围引号

此示例删除任何引号 (“”) 周围的值。 这些通常添加到逗号分隔值,以防止将数据中的逗号视为分隔标记。 在 Excel 中打开并保存为 .xlsx 文件的 .csv 文件永远不会向读者显示这些引号。 如果希望保留引号并将它们显示在最终电子表格中,请将脚本的第 27-30 行替换为以下代码。

// Remove the preceding comma.
row.forEach((cell, index) => {
  row[index] = cell.indexOf(",") === 0 ? cell.substring(1) : cell;
});