手头攒了一堆文件要整理,或者想把某个文件夹里的文件做个清单,又或者是准备批量改名却不知道从哪下手——这时候你最需要的就是先把所有文件名提取出来。我最初遇到这个需求,是给一个摄影素材文件夹做索引,几百个 RAW 文件按日期、地点混在一起,不列个清单根本没法管理。后来发现,提取文件名这件事远不止“看一眼”那么简单,它背后涉及命令行、脚本、编码处理、权限问题,一套组合拳下来,几乎能覆盖所有日常办公和开发场景。这篇文章就把我这些年用过的方法、踩过的坑、顺手总结的脚本一次性讲清楚。
1. 为什么需要提取文件名,以及方法选型的整体思路
1.1 提取文件名的典型需求场景
很多人觉得“提取文件名”是个伪需求,直接在资源管理器里看不就行了?实际工作中完全不是这么回事。文件数量少的时候肉眼可见,一旦超过一两百个,滚动列表就变得极其低效,更别说还要做统计、排序、筛选、后续编辑这些操作。
我遇到的典型场景有四类。第一类是资料归档与审计,比如把项目文件、合同扫描件、历史照片整理成 Excel 清单,文件名列表就是基础素材。第二类是数据迁移前的备份核对,从旧电脑搬到新电脑,或者把文件从本地拷到网盘,迁移前用脚本生成一份完整的文件名记录,迁移后再生成一份,两份一比对就能确认是否有文件丢失,这比肉眼检查靠谱太多。第三类是批量重命名前的准备,先把现有文件名提取到 Excel,在里面统一编辑、排序、加序号,再配合改名工具批量处理。第四类是做文献索引和素材库管理,搞研究的人经常会建一个“文件清单.txt”放在根目录里,随时能找到自己存了哪些东西。
这就像图书馆的目录卡片,你想知道书架上有什么书,总不能把每本书抽出来翻一遍。文件名提取就是给文件夹做目录卡片,是所有后续整理动作的第一步。理解了这一步的价值,你才会愿意花几分钟把方法学扎实。
1.2 方法选型:不同平台、不同需求怎么选
提取文件名的方案非常多,从最简单的命令行到完整的脚本程序,各有各的适用场景。我做了个对比表格,方便你根据自身情况快速定位:
| 方法 | 适用平台 | 上手门槛 | 灵活度 | 典型输出 |
|---|---|---|---|---|
| cmd 的 dir 命令 | Windows | 极低 | 中 | 纯文件名文本 |
| PowerShell | Windows | 中等 | 高 | 文本、CSV、带属性列表 |
| Shell 命令(ls/find) | Linux、macOS | 中等 | 高 | 文本、CSV |
| Python 脚本 | 跨平台 | 较高 | 极高 | CSV、Excel、任意格式 |
选型的原则很简单:如果你只是偶尔整理一次文件,而且不想记任何命令,那最简单的方式是直接在文件夹里全选文件,按住 Shift 右键选择“复制为路径”,再粘贴到记事本或 Excel 里处理。但这个方法有两个问题,一是只能处理当前层级的文件,子文件夹里的内容拿不到;二是复制出来的内容带完整路径,需要二次提取才能得到纯文件名。
如果这个操作你会反复用到,或者文件量太大,那就值得用命令行或脚本解决。命令行适合一次性操作,依赖系统自带工具,不需要额外安装任何软件;Python 适合需要二次处理的情况,比如你想在文件名列表里加上文件大小、修改时间、文件类型,然后导出成表格。所以说,没有绝对最好的方法,只有最合适当前场景的方案。
2. Windows 下的快速提取方法
2.1 cmd 一行命令搞定:dir /b > list.txt
Windows 用户最省事的办法就是打开命令提示符,定位到目标文件夹后执行一行命令。步骤是这样的:按 Win + R 键,输入 cmd 回车,然后在命令行里执行cd /d 文件夹路径,路径可以直接从资源管理器地址栏复制。切换过去之后,敲入下面这一行:
dir /b > list.txt这条命令的执行结果,是把当前文件夹里的所有文件和子文件夹的名称,逐行写入到一个叫 list.txt 的文件里。参数/b的作用是精简输出格式,只保留文件名,不显示日期、大小、权限这些附加信息。如果只想要文件而排除文件夹,可以加上/a-d,也就是“排除目录属性”的缩写:
dir /b /a-d > list.txt如果你要提取的不只是当前文件夹,还包括里面所有的子文件夹中的文件,那就用带/s参数的递归写法:
dir /s /b > list.txt这里要注意一个小坑:输出的 list.txt 本身也在这个文件夹里,所以执行完命令后打开文件,最后一行大概率会看到 list.txt 自己。这不算什么大问题,手动删掉那一行即可,但如果你用脚本方式自动化处理,建议把输出文件放到别的路径,比如dir /b > "%USERPROFILE%\Desktop\list.txt",这样就不会出现文件清单里包含清单文件本身的尴尬。
cmd 命令看起来简单,但有一个隐含问题容易被忽视:命令提示符默认使用系统 ANSI 编码(中文系统下就是 GBK),如果文件名里带有生僻字或特殊符号,生成的 list.txt 用某些文本编辑器打开可能会显示乱码。这个我在后面第 5 章专门讲,这里先留个印象。
2.2 PowerShell 的进阶玩法:带路径、带大小、筛选类型
如果你觉得 dir 命令输出的信息太少,想顺便拿到文件大小、修改时间,或者按指定条件过滤,那就该用 PowerShell。它比传统 cmd 强大得多,而且就是 Windows 系统自带的,不需要安装额外环境。
在文件夹空白处按住 Shift 键,同时点鼠标右键,菜单里会出现“在此处打开 PowerShell 窗口”的选项,这样打开的话当前路径自动就是目标文件夹,省去了切换目录这一步。然后执行:
Get-ChildItem | Select-Object -ExpandProperty Name | Out-File -Encoding utf8 list.txt这条命令拆开看:Get-ChildItem获取当前文件夹中的全部项目,Select-Object -ExpandProperty Name把所有项目的名称提取成纯字符串列表,Out-File -Encoding utf8 list.txt把结果写入文件,同时明确指定用 UTF-8 编码,避免乱码。
如果想带上完整路径,为后续在 Excel 中做超链接之类操作做准备,这样写:
Get-ChildItem | ForEach-Object { $_.FullName } | Out-File -Encoding utf8 list.txt想加上文件大小和修改时间,然后输出成 CSV 格式直接给 Excel 用,可以这样写:
Get-ChildItem | Select-Object Name, FullName, Length, LastWriteTime | Export-Csv -Encoding UTF8 list.csv -NoTypeInformation筛选指定类型的文件也很方便,比如只要文档类的.docx文件:
Get-ChildItem -Filter *.docx | Select-Object -ExpandProperty Name | Out-File -Encoding utf8 list.txt我在实际使用中最喜欢 PowerShell 的一点,是它处理中文文件名时非常稳定。只要指定了-Encoding utf8,导出的文件在记事本和 Excel 里都能正常显示,不存在乱码困扰。另外,它支持管道操作,意味着你可以在一条命令里把多个操作串联起来,比如先获取文件列表、再按大小排序、最后只取前 50 个文件名——这种灵活性是传统 cmd 给不了的。
2.3 批处理脚本:一键提取多层文件夹里的所有文件名
如果你经常要对不同文件夹执行同样的提取操作,每次都手动敲命令还是太慢。我的做法是写好一个批处理脚本,用的时候双击就行。新建一个文本文件,把扩展名改成.bat,编辑内容如下:
@echo off chcp 65001 >nul for /r "%~dp0" %%i in (*) do echo %%i >> "%~dp0文件列表.txt" echo 提取完成!文件列表已保存到当前文件夹。 pause这个脚本的核心是for /r循环,它会把当前脚本所在目录及其所有子目录里的全部文件找出来,逐行追加到“文件列表.txt”里。这里有个关键细节:脚本中用到了%~dp0,它代表“脚本文件自身所在的完整路径”。为什么要用它?因为批处理脚本默认的工作目录可能不是你想的文件夹——如果从资源管理器双击运行,工作目录通常是脚本所在目录,但如果通过命令行以绝对路径方式调用,工作目录就不一定了。用%~dp0可以确保无论如何执行,遍历和输出都锁定在脚本所在的文件夹,不会跑偏。
chcp 65001的作用是把当前命令行代码页切换为 UTF-8,让脚本处理中文文件名时不容易出错,同时让输出文件保持 UTF-8 编码,方便在现代化编辑器中查看。不过要注意,如果你的系统比较老旧,切换代码页后界面可能显示异常,这属于正常现象,不影响最终生成的文件。
3. Linux 和 macOS 下的文件名提取方法
3.1 ls、find 的基本用法
Linux 和 macOS 用户提取文件名可以说是得天独厚,因为系统的哲学本来就是“一切皆文件”,命令行工具强大到令人发指。最基本的方法是使用ls加重定向:
ls > list.txt这一行命令把当前目录里的所有文件和文件夹名字写入 list.txt。配合-a参数可以包含隐藏文件,-l参数显示详细属性。不过ls有个特点需要注意:它默认只处理当前目录一层,不会递归进入子目录,如果你要提取的是整个目录树里所有层级的文件,就得用find。
find是真正的递归工具。最常用的写法:
find . -type f > list.txt这条命令的含义是:从当前目录(.)开始,查找所有类型为文件(-type f)的项目,把完整路径写入 list.txt。输出结果长这样:
./photos/IMG_001.jpg ./photos/IMG_002.jpg ./docs/readme.md路径前面的./前缀是find默认的路径拼接效果,如果不想要这个前缀,可以用sed过滤掉:
find . -type f | sed 's|^\./||' > list.txt如果你只想要某一种类型的文件,比如所有.mp4视频文件:
find . -type f -name "*.mp4" > list.txt如果想把所有子目录的名称也一并输出,把-type f换成-type d就可以了。这套组合几乎覆盖了所有文件清单需求,而且find的递归遍历在大型目录树中也十分高效。
3.2 应对文件名中的汉字与空格
很多从 Windows 转到 Linux/macOS 的朋友,第一次发现在命令行操作中文文件名时会有点懵。Windows 上中文文件名在资源管理器里很直观,但在 Linux 终端里,文件名就是一串字节序列,系统并不会特别关心里面是汉字还是字母。它把每个文件名当成原始字节来处理,你能正常使用,是因为你的终端设置了 UTF-8 编码,名字中的汉字在显示层被正确解码了。
这里确实有一个真正需要小心的场景:在命令行里引用带空格的文件名。如果你执行find . -type f然后看到类似./我的文件 2024.txt这样的名字,当你想要对这个文件做进一步操作时,必须先给整个路径加上引号,比如cat "./我的文件 2024.txt",否则空格会被当成参数分隔符,命令就会报错。
如果文件名里包含了换行符——这种情况极少,但也存在——普通find输出的清单就会变得混乱,因为换行符把每一个完整文件名拆成了多行。处理这种极端情况,可以借用find -print0配合xargs -0,先把文件名用空字符分隔,再用支持空字符分隔的工具消费:
find . -type f -print0 | xargs -0 -I{} echo "{}"这样就能以安全的方式遍历每一个文件名,哪怕名字里有空格、换行或特殊字符也不会出错。当然,绝大多数人一辈子不会遇到这种文件,但一旦遇到了,这条命令能救命。
3.3 提取到文本并保持编码正确
Linux 终端默认使用 UTF-8 编码,所以用find或ls生成的文件名清单,在 Linux 上打开完全正常。但如果你把这个文件用 U 盘拷到 Windows 电脑上,用记事本打开,可能会看到一堆乱码,因为记事本可能尝试用 ANSI 编码解读内容。解决办法有两个方向。
第一个方向是把 Linux 上生成的文本另存为带 BOM 的 UTF-8。在 Linux 上可以用sed给文件开头加上 BOM 标记:
find . -type f > list.txt sed -i '1s/^/\xef\xbb\xbf/' list.txt这段命令在 list.txt 的开头插入三个字节EF BB BF,也就是 UTF-8 BOM。Windows 记事本碰到这个标记,就会自动识别文件为 UTF-8 编码,不会再乱码。第二个方向是干脆生成 CSV 文件,让 Excel 自己处理编码识别。下面这行命令把文件名和文件大小一起输出成 CSV:
find . -type f -printf "%f,%s\n" > list.csv-printf是 GNU find 的一个特性,%f代表纯文件名(不含路径),%s代表文件字节大小,\n是换行。生成出来的 CSV 在 Excel 里打开基本没有乱码问题,而且每行都带上了文件大小,非常实用。不过要说一句,macOS 自带的 find 是 BSD 版本,不支持-printf,如果你在 Mac 上需要类似效果,用-exec或者干脆用awk处理。
4. 用 Python 实现跨平台提取与批量改名
4.1 os.listdir、os.walk 与 pathlib 的区别
命令行虽然强大,但它有一个天然的短板:很难把提取结果和复杂的后续处理逻辑结合。比如你想把文件名列表生成 Excel 表格,同时在表格里附带文件类型统计;或者你想提取文件名后自动按规则重命名——这些用纯命令行做起来很别扭,写 Python 脚本就顺理成章了。
Python 里最常用的三个写文件遍历的方式:os.listdir、os.walk和pathlib.Path。os.listdir只返回指定目录下的一个层级,包含文件和文件夹的名字,不递归、不带类型信息。要判断某个名称是文件还是文件夹,需要逐个用os.path.isfile再查一次。os.walk是递归遍历的标准方案,每到一个目录,返回三个列表:当前目录路径、子目录列表、文件列表,用来生成完整目录树非常方便。pathlib是 Python 3.4 引入的现代接口,用Path.iterdir()、Path.rglob()等方式可以写出更简洁的代码。
日常项目里,我倾向于这样选:只需要当前层级的名字但代码要简单,选os.listdir;需要递归遍历并区分目录和文件,选os.walk;需要在多个平台运行且更追求代码可读性,选pathlib。
4.2 一份可以直接用的提取脚本
下面这个脚本是我经常用的模板,功能是遍历一个文件夹及其所有子文件夹,把每个文件的文件名、完整路径、大小、修改时间提取出来,输出为 CSV 文件,方便直接拖进 Excel 或者做后续分析。脚本里的关键代码都已经写好,直接保存为.py文件即可运行:
import os from datetime import datetime def list_files_to_csv(folder, output="file_list.csv"): rows = [] for root, dirs, files in os.walk(folder): for name in files: full_path = os.path.join(root, name) try: size = os.path.getsize(full_path) except OSError: size = -1 mtime = datetime.fromtimestamp( os.path.getmtime(full_path) ).strftime("%Y-%m-%d %H:%M:%S") rows.append([name, full_path, size, mtime]) with open(output, "w", encoding="utf-8-sig", newline="") as f: f.write("文件名,完整路径,大小(字节),修改时间\n") for row in rows: f.write(",".join(str(x) for x in row) + "\n") print(f"共提取 {len(rows)} 个文件,结果已保存到 {output}") if __name__ == "__main__": folder = input("请输入要提取的文件夹路径:").strip().strip('"') output = input("请输入输出文件名(默认 file_list.csv):").strip() or "file_list.csv" list_files_to_csv(folder, output)这段代码里有两个细节值得单独说。第一,写入文件时用encoding="utf-8-sig",这是 Python 中带 BOM 的 UTF-8 编码格式,专门为了解决 Excel 直接打开 CSV 乱码的问题。如果你用普通的utf-8,Windows 版 Excel 往往会识别成 ANSI 导致乱码,换成utf-8-sig后 Excel 就可以自动识别,这是我踩过很多次坑之后总结出的经验。第二,代码中额外处理了获取文件大小异常的情况,设置为-1,避免某些权限受限的文件导致整个脚本中断。
生成 CSV 后,你在 Excel 里可以做各种进一步处理:按大小排序、按类型筛选、用完整路径创建超链接,或者把纯文件名复制到新工作表里做重命名对照表,整个流程非常流畅。
4.3 提取之后的批量重命名配套脚本
提取文件名往往不是终点,更多时候我们是想做批量重命名。最实用的一种场景是:先把原文件名提取出来交给领导或甲方确认,然后在 Excel 里编辑好新的名字,再把新旧名字做成两列对照表,让脚本处理剩下的事情。
这里提供一个简洁的批量重命名脚本。它的逻辑是从 Excel 导出的 CSV 里读取两列数据,第一列是原文件名,第二列是新文件名,然后逐个执行重命名操作:
import csv import os def rename_from_csv(csv_path, folder): with open(csv_path, encoding="utf-8-sig", newline="") as f: reader = csv.reader(f) for row in reader: if len(row) < 2: continue old_name, new_name = row[0].strip(), row[1].strip() if not old_name or not new_name: continue old_path = os.path.join(folder, old_name) new_path = os.path.join(folder, new_name) if os.path.exists(old_path) and not os.path.exists(new_path): os.rename(old_path, new_path) print(f"{old_name} -> {new_name}") else: print(f"跳过:{old_name}") if __name__ == "__main__": csv_path = input("请输入 CSV 文件路径:").strip().strip('"') folder = input("请输入目标文件夹路径:").strip().strip('"') rename_from_csv(csv_path, folder)除了这种两列对照式的严谨改名方式,如果只是想简单加个前缀或后缀,比如给所有文件加上日期前缀,也可以直接用一段更简单的脚本。但我的建议是,凡是涉及批量重命名,一定要先提取旧名单、生成预期新名单、再执行脚本,这套流程虽然多了一步,却是最安全的——万一改错了,至少你手里有原始名单可以还原。专业工具走打印之前都有预览,改名也一样,别跳过预览和对照环节。
5. 常见问题与排查技巧实录
5.1 文件名乱码问题:到底是谁的锅
提取文件名时乱码高发,我自己也从前到后排查过很多次。这个问题本质上不是文件名本身的问题,而是“生成文件时写入的编码”和“查看文件时使用的解码方式”不一致造成的。
最常见的情况是这样的:在 Windows 的 cmd 窗口里执行dir /b > list.txt,生成的文件默认用 ANSI 编码(中文系统下即 GBK)。这一步在 cmd 显示时一切正常,因为显示端也是 GBK。但你把 list.txt 拿给同事,同事的电脑可能是英文系统,或者用 VS Code、Sublime 这类默认按 UTF-8 解码的编辑器打开,就会看到“锟斤拷”之类奇怪字符。反过来也有,在 Linux 上用find生成的清单是 UTF-8,拷到 Windows 用老版本记事本打开,同样乱码。
根本解法就一条:明确指定编码,别让系统猜。PowerShell 中指定-Encoding utf8,Python 中指定encoding="utf-8-sig",Linux 生成的文件加 BOM 或转成 UTF-8。只要生成和查看双方达成一致,乱码问题就不存在。如果你不清楚一个现成文件是什么编码,Linux 下可以用file list.txt命令查看它的编码类型,Windows 下可以用记事本打开后点击“文件—另存为”,看右下角编码栏显示的是什么,这是最快的诊断方法。
另外还有一个细节,Windows 命令提示符默认代码页受系统区域设置影响,如果你在 cmd 中执行chcp 65001切换到 UTF-8 代码页,再用dir /b > list.txt生成的文件就会是 UTF-8 编码。但这个命令只对当前窗口有效,关闭重开就会失效。
5.2 权限不足导致无法列出文件夹内容
提取文件名时也经常碰到“打不开文件夹”的情况。查看某些系统文件夹或在局域网共享文件夹里提取文件清单时,系统会弹窗提示“你需要来自 System 的权限才能对此文件夹进行更改”或“你需要来自 Administrators 的权限”。这类提示字面上说的是“更改”,但有时候你只是执行一个读取文件名的命令,也会遇到。
处理方式要看具体场景。如果你确实需要读取这些文件夹的文件名,最常见的做法是以管理员身份运行命令提示符或 PowerShell。具体操作是:在开始菜单中找到“命令提示符”或“PowerShell”,右键点击选择“以管理员身份运行”,然后切换目录、重新执行提取命令。如果是共享文件夹的权限问题,那就得联系管理员,或者由共享所有者调整该文件夹的读取权限。这里我不建议用网上那种一键获取所有权的工具,特别是针对系统目录,修改权限可能导致系统不稳定,得不偿失。
还有一个小技巧:在资源管理器里打开文件夹时如果提示没有权限,不一定代表命令行也读不到。命令行工具运行在哪个权限级别就会以哪个权限访问文件,有时你用管理员身份运行命令行就能列出,不必修改任何文件夹属性。
5.3 导出的文件清单在 Excel 中打开乱码
把提取结果导入 Excel 后乱码,是又一个高频问题,但我可以说,90% 的情况都是用错编码导致的。Excel 对 UTF-8 CSV 的识别有两个阶段:如果文件带 BOM,Excel 一举就能正确识别;如果文件不带 BOM,Excel 会按照系统语言猜测编码,在中文系统上通常猜成 ANSI/GBK,于是 UTF-8 的中文文件名就变成了乱码。
解决办法有三种。第一种是用 Python 生成文件时用utf-8-sig编码,我在前面的脚本中已经这么做了,带 BOM 的 CSV 对 Excel 友好。第二种是手动导入:Excel 依次点“数据 → 从文本/CSV”,在弹出的窗口中选择文件,然后在编码选项里明确选择“UTF-8”,这样无论文件是否带 BOM 都能正确导入。第三种是偷懒方案:把提取结果复制粘贴进 Excel,而不是直接双击打开 CSV,只要源头显示正常,粘贴过去就正常。
我在做大型文件清单时,通常直接用 Python 生成 CSV 文件,再加一句encoding="utf-8-sig"收工。这种组合方案经受了无数次的检验,几乎没有再出现过乱码情况。
5.4 特殊场景速查表
| 问题或场景 | 推荐命令或操作 |
|---|---|
| Windows 当前目录提取文件名 | dir /b > list.txt |
| Windows 递归提取所有层级文件名 | dir /s /b > list.txt |
| Windows 提取文件名加完整路径 | Get-ChildItem | ForEach-Object { $_.FullName } | Out-File -Encoding utf8 list.txt |
| Linux/macOS 递归提取所有文件 | find . -type f > list.txt |
| Linux/macOS 提取特定类型文件 | find . -type f -name "*.jpg" > list.txt |
| 跨平台生成 Excel 兼容清单 | 使用 Python,写入时带上utf-8-sig |
| 文件名含空格需要安全遍历 | Linux 下用find . -type f -print0 | xargs -0 |
| 提取结果乱码 | 先确认生成编码和解码编码是否一致,优先统一为 UTF-8 |
我自己在实际操作中慢慢养成的一个习惯是:凡是重要的文件目录,我都会顺手保留一份提取出来的清单,放到同级目录或者网盘里。很多项目过一段时间后你根本想不起来里面装了什么,有了一份清单,检索效率会高很多。每次收到一个乱糟糟的文件夹,我都是先执行一条命令把文件名提取出来,再看着清单决定怎么整理。这个动作虽然小,但确实帮我节省了大量时间,也希望这些方法能在你的日常工作里派上用场。最后一个建议:把这些命令存成小脚本,放到一个专门放工具的文件夹里,用到时随手能翻到,比你每次现去搜索要靠谱得多。