n8n常用节点详解:文件操作、数据整形与代码执行实战
做自动化这行我遇到最多的问题不是怎么搭一个惊天动地的工作流而是怎么把一个文件从A点挪到B点中间顺手改个格式、加个字段。n8n 的节点体系恰好就是为这类事设计的从文件操作到代码执行几乎覆盖了日常自动化的全部高频场景。这篇是 n8n 入门教程的第 06 篇我想把常用节点的底层逻辑一次讲清楚——节点怎么选、怎么配、怎么排错以及什么时候应该放弃内置节点转手写代码。如果你已经装好了 n8n跑通过一两个简单工作流那这篇绝对适合你。我写这篇有个前提默认你已经理解了 Workflow、Execution、Item、JSON 这些基础概念。如果还没接触过建议先创建一个最简单的 Manual Trigger 加 Edit Fields 节点跑通一次再回来看。下面所有配置以 n8n 1.x 版本为例界面细节可能随版本微调但核心思路不会变。1. 节点是n8n的积木先看懂节点家族的分类逻辑很多人第一次打开 n8n 的节点选择器心里想的都是我到底该搜什么。节点选择器里几百个节点看起来毫无头绪但如果你按职责去分类其实就三类触发节点、操作节点、辅助节点。理解了这三个角色后面所有流程设计都顺了。1.1 触发节点工作流怎么醒过来每个工作流都得有一个起点这个起点就是触发节点。最常见的几个Manual Trigger手动点击执行调试工作流时最常用。Schedule Trigger定时触发支持 Cron 表达式比如每天凌晨跑一次数据同步。Webhook对外暴露一个 URL别人通过 HTTP 请求来唤醒工作流适合接收外部系统的推送。我见过不少新手上来就搭一堆节点唯独忘了这个工作流什么时候启动。实际上触发节点决定了你的自动化是被动响应还是主动巡检。比如文件监听类的需求如果只是在服务器上等文件出现可以考虑用 Cron 轮询目录如果需要别的系统主动告诉你文件来了那就应该是 Webhook。先想清楚触发方式再想处理逻辑顺序不能反。1.2 操作节点与辅助节点干活的和打杂的操作节点是你对接外部系统的入口典型代表是 HTTP Request、数据库节点、邮件节点、Slack 节点。它们负责和世界打交道。而辅助节点是 n8n 内置的 Core Nodes负责数据在流程中间的整形、判断、合并、拆分。它们不直接对接外部系统但决定了整个流程是否顺畅。打个比方操作节点是车间里的机床辅助节点是传送带、机械臂和质检员。机床能干重活但如果没有传送带把料送过来、没有质检员把不合格品挑出去生产线照样停摆。初学 n8n 的人很容易只盯着操作节点看结果发现两个系统之间传过来的数据格式对不上这时候该用的就是辅助节点。在节点选择器左侧除了按服务商找节点还可以按分类浏览比如 File、Data Transformation、Logic、Flow 这几类都是辅助节点的大本营。1.3 配置面板里的三个隐藏入口表达式、属性名、执行方式每个节点双击打开后配置面板里有些东西特别容易被忽略但对实际排错至关重要。第一个是表达式输入。n8n 的字段大多数都支持表达式写法是双大括号比如{{ $json.fileName }}。这意味着字段的值可以不写死而是引用上游节点的数据。很多人都知道字段里能点选参考数据但不知道表达式中还能做字符串拼接、数字运算、三元判断比如{{ $json.prefix - $json.id }}。这是 n8n 里最值得下功夫的地方。第二个是属性名通常叫 Property Name。文件类节点、二进制数据节点几乎都有这个配置。它决定了二进制数据存在 item 的哪个字段里。比如 HTTP Request 节点下载文件后默认把二进制数据放在data这个属性里下一个文件节点就必须指定data两边对不上就会报错。这是我见过最多、也最隐蔽的配置失误之一。第三个是节点的执行方式。部分节点右下角有一个选项可以控制是对所有输入项一起处理还是逐项处理。例如 Function 节点默认逐项处理每条数据而 Code 节点则接收整个数组。理解这个差异才能在写代码时不至于一头雾水。2. 文件操作节点全家桶读、写、转、压缩一条龙文件操作是 n8n 里最贴近日常需求的节点类型。无论是处理报表、整理下载目录还是把接口返回的文件存到服务器都绕不开这组节点。我把最常用的几个先列成一张速查表后面再逐个拆解。节点作用关键配置Read Binary Files从磁盘读取文件为二进制数据PathProperty NamedataWrite Binary Files将二进制数据写入磁盘Data Property NamePathFile NameSpreadsheet File读写 Excel、CSV 文件OperationFile TypeData PropertyConvert to JSON把 CSV/文本转为结构化数据Input Field NameOutput Field NameExtract from File从 PDF、DOCX 等提取文本和图片Property NameCompress压缩或解压 zip 文件OperationProperty Name2.1 本地文件的读写Read/Write Binary Files在 n8n 里文件在节点之间流转时统一以二进制数据Binary Data的形式存在你可以把它理解成一个看不见的文件内容包。要从磁盘上引入一个文件用的就是 Read Binary Files 节点。配置很简单Path 填文件的绝对路径Property Name 保持默认的data就行。Write Binary Files 则相反把上游传过来的二进制数据落盘。这里有两个坑值得注意一是 File Name 字段千万不要写死否则第二次执行会把第一次的文件覆盖掉二是容器环境下Path 必须是你实际挂载到容器里的目录比如/data/output否则 n8n 容器根本看不到宿主机文件。我的习惯是每个工作流在服务器上建一个独立的工作目录比如/data/workflows/report_export/input和output临时文件和最终产物分开。这样做的好处是出了问题你能顺着目录结构快速定位是哪个工作流留下的文件而不是所有任务都堆在一个目录里互相干扰。2.2 二进制数据与 Base64API 和文件之间的桥梁很多人会困惑我通过 HTTP Request 请求一个接口拿回来的是文件但节点面板里看到的却是 Base64 编码的字符串这正常吗正常。因为 JSON 格式本身不能直接承载二进制数据n8n 在内部把二进制数据以 Base64 形式包裹方便在节点之间传递。实际处理时你不需要手动做 Base64 解码。HTTP Request 节点里把 Response Format 设置为 File返回的二进制数据就会自动放进指定的 Property Name 字段比如data。后面直接接 Write Binary Files 或 Spreadsheet File 就能继续处理。如果你要对接的 API 要求把文件内容放在 JSON 字段里上传那就需要反向操作从 Read Binary Files 读出来然后用 Convert to JSON 节点或者 Code 节点把二进制转成 Base64 字符串。这时候你才需要在代码里主动访问item.binary.data之类的字段。核心原则是能靠节点配置完成的数据转换尽量别手写。2.3 Spreadsheet 节点Excel/CSV 处理套路Spreadsheet File 节点是处理报表的利器读写 Excel、CSV 都在它管辖范围。读文件时先确保上游节点已经把文件以二进制形式传进来然后配置 Operation 为 Read from File再指定 File Type 是 csv 还是 excel最后在输出字段名里填上你要把结果放哪比如json。写文件时情况反过来了你需要把结构化数据转成表格格式再以二进制形式交给 Write Binary Files 落盘。中间常见的坑是 CSV 编码问题。默认情况下 n8n 对中文支持没有问题但如果你在 Windows 上用 Excel 打开生成的 CSV中文可能会出现乱码。我的做法是写 CSV 之后再用 Code 节点在文件头部加 UTF-8 BOM或者干脆输出为 xlsx 格式给业务同学。另外读取 Excel 时如果遇到日期字段被解析成数字先别慌那是 Excel 内部的日期序列号。可以在读取之后的 Edit Fields 节点里写表达式做转换{{ $fromMillis(($json.date - 25569) * 86400 * 1000) }}。这类表头看着对数据隐约不对的问题基本都集中在类型转换上。2.4 Extract from File 与 Compress解压和压缩的常见场景每天从外部系统收到的报表其实经常是个 zip 包。处理步骤通常是下载 zip → Compress 节点解压 → 得到内部文件列表 → 逐个读取。Compress 节点的 Operation 选 Extract它会自动解压并把解压出的文件作为多个二进制 item 输出每个 item 的文件名会放在filename字段里。后面接一个 Switch 节点按文件扩展名分流是非常典型的多文件处理流程。Extract from File 节点则用来提取 PDF、Word 等文档里的文本内容适合做合同解析、PDF 发票信息抽取。有一点要注意这个节点依赖系统里的文本提取库某些高级 PDF 或扫描件可能需要额外配置 OCR 能力否则提取出来全是乱码。遇到这种文件我一般建议先确认文本层是否存在不要一上来就怪节点不好用。做压缩操作时常用场景是把多个文件合成一个 zip 发给别人或者上传到网盘。Compress 节点 Operation 选 Compress然后通过表达式把多个二进制 item 的文件名带上它就能自动打包。比起自己写脚本这个节点快得多而且不污染工作流代码。2.5 批处理实例给下载目录里的文件统一改名光说不练不行我分享一个非常实用的真实场景服务器某个目录下每天会落下几个带时间戳但命名混乱的文件需要按规则统一改名并归档到新目录。工作流结构是Schedule Trigger每天凌晨跑一次→ Read Binary Files 读取/data/raw/目录下的所有文件 → Edit Fields 节点根据原文件名计算新文件名 → Write Binary Files 写入/data/archive/。Read Binary Files 读目录时它会把目录下每个文件都变成一条 item文件名在fileName字段里。Edit Fields 节点里我用一个表达式生成新名字比如原始文件叫report-20250211-TMP123.csv我希望改成daily_report_20250211.csv表达式可以这样写// 用表达式的方式在字段里生成新文件名 // 假设原始文件名在 $json.fileName {{ (() { const name $json.fileName || ; const datePart name.match(/(\d{8})/)?.[1] || unknown; return daily_report_ datePart .csv; })() }}这种读目录 → 算新名字 → 写新位置的结构比我早期用 Shell 脚本做要直观得多。更重要的是如果哪天规则变了你只需要改 Edit Fields 里的表达式不需要登录服务器改脚本。3. 数据整形节点拆分、合并、去重与字段映射如果说文件节点解决的是文件和外部系统的问题那么数据整形节点解决的就是数据在流程内部呆得舒不舒服的问题。n8n 里所有数据都是 JSON 数组的形式每个 item 就是一个 JSON 对象。你从 Excel 读出的 100 行就是 100 个 item。而整形节点的作用就是把这 100 个 item 变成你希望它成为的任何形态。3.1 Item Lists 与 Split Out把数组拆成多条记录n8n 里经常出现一个 item 里挂着整个数组的情况。比如调用一个 API 得到{ orders: [ { id: 001, amount: 100 }, { id: 002, amount: 200 } ] }这时如果直接传给下游节点下游节点会把它当成一个对象处理不会自动拆成两条。需要一个动作把orders数组拆开让数组里的每个元素都变成独立的 item。这个操作在 n8n 里叫 Split Out。配置很简单填上要拆的字段路径比如orders它会自动展开成两条数据。反过来如果你想把多个 item 合并成一个数组存在某一个字段里那就用 Item Lists 系列的操作常见的有 Aggregate聚合、Limit截断前 N 条、Sort排序。平时我尤其喜欢 Limit排查问题的时候先截 3 条数据跑通流程确认无误再去掉限制非常节约调试时间。3.2 Merge 节点类似数据库 Join 的操作Merge 节点最常用在两个场景一是把两条数据流简单地拼接在一起所有 item 按顺序合并成一条更大的数据流二是按某个关键字段把两个数据源的信息关联起来类似 SQL 里的 JOIN。第一种场景比如你既读了 Excel 里的用户表又读了 API 返回的订单表想把两个结果汇总后发给下游选 Append 模式就行。第二种场景更复杂一点比如订单表里有userId用户表里有id你想把用户姓名拼到订单记录上那就用 Combine 模式左表选订单流的userId右表选用户流的idMerge 会把匹配上的信息合并成一条记录。这里有个容易踩的坑如果匹配字段在两边的数据类型不一致比如一边是字符串001一边是数字1Merge 永远匹配不上。解决方法是提前用 Edit Fields 或 Code 节点统一字段类型再做关联。我调试这类问题的时候会在 Merge 节点前分别运行两个上游节点肉眼对比两边字段值几乎一眼就能看出问题所在。3.3 去重与字段映射没有现成节点也能用 Code 两行实现你去重、改字段名这类需求n8n 有一些内置节点可用。如果你的版本里能看到 Remove Duplicates 节点可以直接指定判断字段让系统去重。如果找不到也不用慌Code 节点几行就能搞定。字段映射则要提一下 Edit Fields旧版本里叫 Set。它的核心能力是添加、删除、重命名字段。比如上游字段叫user_name你希望下游叫name就可以在 Edit Fields 里写name {{ $json.user_name }}然后把原来的user_name删掉。这个操作虽然简单却是让工作流可读性提升的关键——好的字段命名能让你一个月后回来看流程时不用一层层点开节点回忆这个字段是干嘛的。3.4 组合拳实例多表格合并去重我手头有个实际需求每天收到两个 CSV一份是当天新增用户一份是历史用户需要合并后去掉重复邮箱最后输出一份汇总表。流程是两个 Read Binary Files 分别读两个 CSV → 各自用 Convert to JSON 转成结构化数据 → Merge 节点用 Append 模式合并成一条数据流 → Code 节点按邮箱去重 → Write Binary Files 输出新 CSV。核心去重代码就一段// 按 email 字段去重保留每条数据第一个出现的版本 const seen new Set(); const result []; for (const item of $input.all()) { const email String(item.json.email || ).trim().toLowerCase(); if (email !seen.has(email)) { seen.add(email); result.push({ json: item.json }); } } return result;这个结构从文件读取到代码处理再到文件输出正好串起了这一整章的知识。很多看起来复杂的报表整理需求其实都是这种套路读进来、合并、去重、写出去。4. 逻辑判断节点IF、Switch 与工作流分流自动化流程不是一条直线走到黑的中间必然有如果 A 就做 X否则做 Y的分支。n8n 里承担这个职责的核心节点是 IF 和 Switch。它们本身不做外部操作但通过分流决定了后面哪些节点会被执行。4.1 IF 节点单条件、多条件组合IF 节点通常给两个输出分支True 和 False。配置条件时左侧选字段中间选操作符等于、不等于、包含、大于、小于等右侧填值。支持多个条件叠加条件之间的关系可以是全部满足或任意一个满足。比如我处理订单数据时希望把金额大于 1000 且状态为paid的订单单独拉出来走特批流程。那就配两个条件amount 1000和status paid关系选 ALL。这样只有两个条件同时成立才会走 True 分支。这里有个细节IF 节点的字段类型要保持一致。如果你从 Excel 里读出的amount是字符串1500而条件里写的数值1000它们比较时会因为类型不一致而出现奇怪的结果。遇到这种情况先在上游用 Edit Fields 做一次类型转换再进 IF 判断。4.2 Switch 节点多分支路由IF 只有两个分支遇到根据状态分三路处理的需求就不够用了。Switch 节点可以配置多个分支规则是取值等于某个值就走对应分支。比如物流状态有pending、shipping、delivered三种我就可以配置三路分别走不同的通知逻辑。Switch 节点还支持兜底分支也就是匹配不到任何规则时的默认走向。我强烈建议不管是什么分流场景都留一条兜底分支用于捕获异常数据。否则命中了意外值数据会卡在节点里整个执行直接失败。兜底分支里通常接一个日志节点或直接输出警告方便你事后复盘。4.3 分流落地实例按文件类型归档文件归档是 Switch 最典型的应用场景。我在 2.5 的例子上再进一步读取一个混合目录里面有.csv、.pdf、.zip三种文件希望按类型放到三个子目录。流程是Read Binary Files 读目录 → Switch 节点根据$json.fileName的扩展名做路由 → 三个 Write Binary Files 分支分别写不同类型的目标路径。Switch 的规则配置我通常写成这样第一个规则匹配值填csv表达式用{{ $json.fileName.split(.).pop() }}第二个规则填pdf第三个规则填zip最后再留一个 Default 分支处理未知类型。这样不管目录里混进什么文件工作流都不会中断最多是未知文件落入待人工处理目录。5. 代码执行节点Code 与 Function 到底怎么选文件操作和逻辑分流解决 80% 的问题剩下的 20% 往往需要写点代码。n8n 提供了两个代码执行节点Function 和 Code。这两个名字容易让人混淆但它们的执行模型差别很大。5.1 两者的核心区别节点名执行方式返回要求典型场景Function每条 item 分别执行一次函数返回单个 item逐行字段计算、小幅改写数据Code整个输入数组执行一次函数返回 item 数组批量清洗、去重、聚合、复杂转换换句话说Function 节点里的代码像工厂流水线上的工人来一个零件加工一个零件Code 节点则像仓库管理员可以一次性面对整批货做统计、筛选、重新装箱。具体写代码时Function 节点的写法是直接操作item.json// Function 节点每个 item 单独进来返回修改后的 item item.json.total item.json.price * item.json.quantity; return item;Code 节点则需要你先取整个输入// Code 节点一次处理所有 item return $input.all().map(item { return { json: { ...item.json, total: item.json.price * item.json.quantity } }; });新手最常见的错误就是把 Function 的写法直接抄进 Code 节点结果发现item是 undefined。记住这句话Function 关心单条Code 关心整批。5.2 Code 节点常用写法转换、过滤、去重、聚合Code 节点因为能拿到全量数据所以特别适合做数据透视。我分享几个高频模式你可以直接抄过滤出金额大于 100 的记录return $input.all() .filter(item Number(item.json.amount) 100) .map(item ({ json: item.json }));把多条记录按用户分组并求和const groups {}; for (const item of $input.all()) { const uid item.json.userId; const amount Number(item.json.amount) || 0; groups[uid] (groups[uid] || 0) amount; } return Object.entries(groups).map(([userId, total]) ({ json: { userId, total } }));注意 Code 节点里返回的数组每个元素必须是{ json: 数据对象 }的结构直接返回裸对象会报错。这是我早期踩过的最频繁的坑没有之一。5.3 Function 节点的应用场景与限制Function 节点适合做轻量级字段加工。比如把用户手机号统一格式、把日期字符串转成标准格式用 Function 节点进去一条、出一条逻辑简单出错了也容易定位到具体是哪条数据出了问题。不过 Function 节点有一个明显的限制它无法像 Code 节点那样轻松做跨 item 的统计。比如利用上一个 item 的值计算差值这个需求在 Function 节点里写起来很别扭在 Code 节点里用循环就非常自然。我的选择标准很简单只要需要看全量数据就用 Code否则用 Function。5.4 写代码时要注意的沙箱、异常处理和日志n8n 的代码节点运行在受限的 JavaScript 沙箱环境里不能直接require任意的 Node.js 模块也不能访问网络。如果你需要在流程里调用外部接口那就老老实实把 HTTP Request 节点放在代码节点之前把接口返回的数据喂给代码处理而不是试图在代码里发请求。异常处理也是个值得养成习惯的点。Code 节点一旦抛出异常整个执行就会失败。我建议在涉及外部数据转换的时候用 try-catch 包裹核心逻辑并给每个关键步骤添加日志输出。n8n 里可以用console.log打印调试信息在节点执行详情里能看到。日志写得好排查问题时能省一半时间。try { const data $input.all().map(item { const raw item.json; if (!raw.email) { throw new Error(缺少 email 字段); } return { json: { ...raw, email: String(raw.email).trim() } }; }); return data; } catch (error) { console.log(数据清洗失败:, error.message); throw error; }5.5 实例从 URL 下载 CSV 并清洗入库把前面的知识串起来一个典型场景是从某个 URL 下载 CSV清洗字段后输出为新的 CSV。流程HTTP Request 节点设置 Response Format 为 File得到二进制数据 → Convert to JSON 把 CSV 带出结构化字段 → Code 节点清洗 → Write Binary Files 落盘。Code 节点里的清洗逻辑我会同时做三件事统一列名、去掉空值、修正字段类型return $input.all().map(item { const row item.json; const email String(row.email_address || row.email || ).trim().toLowerCase(); const amount Number(row.amount || row.total || 0); if (!email) return null; // 过滤无效行 return { json: { email, amount, source: row.source || unknown, processedAt: new Date().toISOString() } }; }).filter(Boolean); // 去掉 null这里filter(Boolean)是用来丢弃空数据的惯用写法。跑通之后我再把这个流程挂在 Schedule Trigger 下面每天定时执行一个稳定的数据管线就成型了。6. 调试与排查从节点报错到恢复运行任何一个稍微复杂的工作流都不可能一次跑通。报错不可怕可怕的是不会看报错、不会定位问题。这一章我聊聊在 n8n 里排查问题的完整思路。6.1 每个节点的输入输出都要看得到n8n 的编辑器里每个节点执行后都会保留输入和输出数据。点开节点在 OUTPUT 面板能看到该节点真正输出了什么在 INPUT 面板能看到肚子里消化了什么。我调试的第一步永远是看这两个面板。比如 Code 节点报错说某个字段是 undefined那就先看上游节点的输出数据找到是哪个字段名写错了。大多数情况下问题不是你代码逻辑不对而是字段名和上游不匹配。另一个小技巧是给节点配置样例数据。在节点配置面板底部可以手动构造一条假数据用于测试。这样你不需要重新触发上游任务就能快速验证某个节点对特定数据结构的处理是否正常。我经常拿一条边界数据来测试比如金额为 0、邮箱为空这种极端情况确保流程不会在正式数据上翻车。6.2 常见报错合集与含义报错现象常见原因解决思路The following node types are not available节点的类型未安装或拼写错误检查节点是否安装或从官方节点面板重新添加Code 节点里item未定义把 Function 的写法抄进了 Code 节点Code 节点用$input.all()取数据文件节点报错路径不存在容器内路径与宿主机路径不一致确认挂载目录设置绝对路径CSV 中文乱码缺少 UTF-8 BOM 或编码不一致写文件前加 BOM或改用 xlsxMerge 节点匹配不上两边字段类型或命名不一致统一字段名、统一类型后再合并表达式返回值类型不符表达式返回了对象/数组但字段期望字符串在表达式里加String()或JSON.stringify()这里我要特别强调路径不存在这类问题。很多人以为在服务器上看到某个目录容器里就一定有。实际上 n8n 如果跑在 Docker 里它看到的文件系统是容器内部的必须通过 volume 挂载才能访问宿主机目录。排查这类问题先去容器里ls一下目标路径十次有九次是路径没挂进来。6.3 大数据量时的性能提醒最后一个实操经验关于文件大小和数据量。n8n 的所有数据默认都在内存里流转如果你从 Excel 里一次性读出 50 万行再在 Code 节点里做循环处理内存会被瞬间吃光。我处理大文件时通常会在前面加一个 Limit 节点先截一部分做验证确认逻辑没问题再全量跑。如果确实需要处理非常大的数据集更稳妥的方案是先用代码节点做粗加工把不必要的字段全部删掉只留最终需要的字段再进入下一步。数据在节点之间传递得越精简整个工作流跑得越轻松。我个人的经验是n8n 最舒服的使用姿势是每个节点完成一个小而清晰的任务而不是在一个节点里塞一大堆逻辑。这样既方便排错也方便别人接手你的工作流。最后再分享一个我沿用至今的习惯不要背节点要学会搜节点。你想起我要做个压缩直接在节点搜索框输入 compress 或者 zip大概率能找到正确入口。n8n 的节点命名虽然有时有点绕但搜索功能做得足够好与其费劲记忆不如建立这个需求大概对应哪类节点的直觉。等这种直觉建立起来你会发现从文件操作到代码执行大多数自动化需求都能在 n8n 里用十几分钟拼出一条稳定的流程。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →