我有多个分号分隔的.csv
文件:
sample.csv
sample1.csv
...etc.
每个都有两个记录、一个标题和数据。
示例sample.csv
:
record-type-cd;record-creation-dt;product-bank-swift-cd;term-deposit-id;saving-global-servicing-bank-name;product-bank-name;customer-account-iban;customer-id;term-deposit-reference;customer-id;term-deposit-reference;payin-iban;payout-iban
ACC;2023-08-18;BBLUK;ABCDEFG-3;check24toprovide;Testcase;DE335666666666666;ABCDEFG-1;2800123456720890;ABCDEFG-1;2800123456720890;DE66110000007000110910000;BE66110000007000110910100
对于每个文件,我需要根据其数据记录的第一、第二和第四字段重命名每个文件。
对于上面的例子,那就是:
ACC2023-08-18ABCDEFG-3.csv
当我使用以下代码时,它给出delimiter__.csv
新名称:
@echo off
setlocal enabledelayedexpansion
REM Specify the input .csv file name and path
set "inputFile=sample.csv"
REM Read the 2nd line of the .csv file
set /a lineNumber=0
for /f "usebackq skip=1 delims=" %%a in ("%inputFile%") do (
set /a lineNumber+=1
if !lineNumber! equ 1 (
set "line=%%a"
goto processLine
)
)
:processLine
REM Set the delimiter used in the .csv file
set "delimiter=;"
REM Split the line into separate columns
set "colIndex=0"
for %%b in ("%line:%delimiter%=" "%") do (
set /a colIndex+=1
set "col!colIndex!=%%~b"
)
REM Get the required columns from the line
set "newFileName=!col1!_!col2!_!col4!.csv"
REM Rename the input file
ren "%inputFile%" "!newFileName!"
echo File renamed to: !newFileName!
pause
可以用于此任务:
前两个命令行完全定义了所需的执行环境
goto :EOF
,所需的命令扩展!
文件名中的 CSV 文件。接下来在后台执行:
%ComSpec% /c dir *.csv /A-D /B 2>nul
启动运行
%SystemRoot%\System32\cmd.exe
其内部命令DIR/A-D
(属性而不是目录)*.csv
/B
。通过使用将其重定向到设备NUL,可以抑制当前目录上不包含 CSV 文件的错误消息输出
2>nul
。重定向运算符>
必须在批处理文件的FOR命令行中转义,才能通过处理批处理文件将其解释为文字字符,而不是解释为重定向cmd.exe
运算符。处理批处理文件的Windows命令处理器实例捕获在后台执行的命令进程的输出,并在启动
cmd.exe
完成并自行关闭后处理捕获的行。cmd.exe
捕获的输出是现在加载到处理批处理文件的内存中的文件名列表。在执行文件重命名之前,必须将 CSV 文件的所有文件名加载到命令进程的内存中,这一点很重要,否则可能会发生简单的循环,例如某些 CSV 文件根本不被处理,而其他文件则被
for %%B in (*.csv) do
处理多次。标准FOR*.csv
循环指示文件系统在每次迭代时返回与通配符模式匹配的下一个文件名,这对于在每次执行命令REN后与文件系统中与更改匹配的文件系统中的文件名列表相同的目录中的文件进行重命名是有问题的。使用FOR /F选项
eol=|
,将 CSV 文件在文件名开头可以具有的delims=
默认行尾字符更改为文件名不能包含的垂直线,以及默认水平制表符和普通分隔符列表;
空格到空的分隔符列表。这两个选项可确保进一步处理时不会忽略任何 CSV 文件名,并将完整的文件名分配给循环变量B
,即使是类似; sample file with leading space and semicolon.csv
.对于每个文件名,调用子例程
ReadData
,将文件名传递给包含在其中的子例程,"
以处理包含空格或这些字符之一的正确文件名&()[]{}^=;!'+,`~
。整个FOR循环包含在一个命令块中,该命令块从
(
行首开始,以 after 匹配结束,)
用于"%%B"
在同一命令行上使用无条件命令运算符&
,并在同一命令行上指定goto EndBatch
在重命名所有 CSV 文件后继续批处理文件处理位于标签线下方EndBatch
。这可以避免重命名所有 CSV 文件后陷入子例程。使用子例程重命名数百甚至数千个 CSV 文件的效率非常低。但是批处理文件的处理使用所使用的代码进行了一些优化,因为标签总是立即在批处理文件的下一行上
ReadData
找到。cmd.exe
这减少了文件重命名任务的文件系统访问。在子例程中
ReadData
,又使用了一个FOR /F循环,该循环打开 CSV 文件,跳过 CSV 文件顶部的标题行,读取第二行,使用分号作为分隔符将其拆分为子字符串,并分配第一个、第二个和第四个分号分隔循环变量G
,H
和 的字符串I
。注 1: _ 第二行不能以分号开头,即第一个数据列中有空值。
注 2: _ 第二行也不应该有空的第二个、第三个或第四个数据值,因为FOR /F解释
;;
为一个分隔符而不是两个分隔符。换句话说,对于前四个数据列,第二个数据行必须始终具有四个非空值。
使用第一、第二和第四数据值的 CSV 文件的新文件名被分配给环境变量,
NewFileName
并且通过在同一命令行上在无条件命令运算符之后另外使用退出循环的&
命令来退出 CSV 文件的处理goto RenameFile
即使 CSV 文件有多于两行。这也会导致关闭打开的 CSV 文件,cmd.exe
这在这里很重要,因为 CSV 文件应该使用下一个命令行重命名,而这在任何进程(包括cmd.exe
处理批处理文件)仍然打开的情况下是不可能的。(
在以匹配开头和结尾的命令块内不可能存在标签)
,这就是使用子例程的原因,该子例程goto RenameFile
可用于退出循环并使用标签下方的行继续批处理文件处理RenameFile
。接下来,如果当前 CSV 文件还没有所需的文件名,则通过不区分大小写的字符串比较进行检查。这种情况使得可以在同一目录中多次运行批处理文件,而不会在当前目录中的一个或多个 CSV 文件已经具有所需的文件名时显示错误消息。
否则,如果当前文件名不等于新文件名,则当前 CSV 文件将重命名为其新名称。如果当前 CSV 文件由另一个进程打开,或者当前目录中已存在与当前文件的新文件名同名的文件/文件夹,则文件重命名可能会失败。在这种情况下会输出一条错误消息。
子例程退出,
goto :EOF
导致批处理文件处理返回到第一个FOR /F循环,该循环分别处理下一个捕获的行和 CSV 文件名。要了解所使用的命令及其工作原理,请打开命令提示符窗口,执行以下命令,并完整、仔细地阅读每个命令显示的帮助页面。
dir /?
echo /?
endlocal /?
for /?
goto /?
if /?
ren /?
setlocal /?
也可以看看: