批处理脚本:在FOR循环中更快地回显到csv文件?
我编写了一个脚本,将文本文件中的分号分隔符替换为逗号,但它也在第9列的文本周围加引号,因为第9列包含逗号。当我输出到新的文本文件时,它的处理速度非常慢,可能需要4-5分钟,它读取的文本文件是50MB。有没有更快或更有效的方法来做到这一点?以下是我的FOR循环:批处理脚本:在FOR循环中更快地回显到csv文件?,csv,batch-file,for-loop,Csv,Batch File,For Loop,我编写了一个脚本,将文本文件中的分号分隔符替换为逗号,但它也在第9列的文本周围加引号,因为第9列包含逗号。当我输出到新的文本文件时,它的处理速度非常慢,可能需要4-5分钟,它读取的文本文件是50MB。有没有更快或更有效的方法来做到这一点?以下是我的FOR循环: FOR /f "usebackq tokens=1-9* delims=;" %%a IN ("%FILENAME%") DO ( SET C10=%%j ECHO(%%a,%%b,%%c,%%d,%%e,%%f,%%g,%%h,"%%i
FOR /f "usebackq tokens=1-9* delims=;" %%a IN ("%FILENAME%") DO (
SET C10=%%j
ECHO(%%a,%%b,%%c,%%d,%%e,%%f,%%g,%%h,"%%i",!C10:;=,! >> "%MYPATH%\Filename %MMDDYYYY%.csv")
还是我应该学习python
谢谢。使脚本运行“更快”的一件事是避免每次写入操作都打开和关闭输出文件
>%MYPATH%\Filename%MMDDYYYY%.csv”(
对于/f“usebackq tokens=1-9*delims=;”%%a IN(“%FILENAME%”)DO(
设置C10=%%j
回声(%%a、%%b、%%c、%%d、%%e、%%f、%%g、%%h、%%i”、!C10:;=,!
)
)
不要重定向每一行,而是重定向整个
for
命令。如果要更改分隔符以在Excel中正确打开csv,则无需执行此操作。有一个(未记录的)技巧可以告诉Excel,使用哪个字符作为分隔符:
(echo Sep=;) > new.csv
type old.csv >> new.csv
move /y new.csv old.csv
注意:Excel读取
Sep=;
,并使用该分隔符导入文件的其余部分,但它不是电子表格的一部分,因此如果使用Excel再次保存,则Sep=;
将丢失(Excel使用、
或;
作为分隔符,具体取决于安装语言).Squashman有一个好主意,使用my进行转换。该实用程序是一个混合脚本,同时使用批处理和JScript。该实用程序比任何纯批处理解决方案都快得多,并且从XP开始,它在任何Windows机器上本机运行-不需要第三方exe
该实用程序实际上是为了在批处理文件中通过FOR/F方便地解析CSV文件而生成的。1.0版存在一个问题,这使得使用该实用程序转换CSV格式以用于其他用途不太理想-转义引号文本被取消转义,因此“”变为“。此转换对于/F解析很有用,但它不是有效的CSV格式
我修改了该实用程序,使其具有保留引号文本转义的选项
parseCSV /I:; /Q:E <input.csv >output.csv
FOR命令在开始处理之前读取整个文件。我个人使用Dave Benham的Parse CSV。这是一个混合脚本,应该可以更快地处理文件。如果想要速度,请不要使用批处理。使用文本编辑器编辑文本有什么错?例如,Vim会在几秒钟内完成,这主要取决于文件所在的存储设备。@AlexP:文本编辑器很好(也是首选)如果你必须只做一次。如果你必须定期做,那就糟透了。@Squashman-看我的答案-我接受了你的想法,修改了实用程序,使它现在可以正确地进行转换,即使输入包含引号文本。哦,我必须试着记住这个。可能会有用的。嗯。我知道sep选项但我不认为它可以更改实际数据的分隔符。我通常使用它来指定分隔符是管道,这样当我打开具有csv扩展名的文件时,Excel知道使用管道作为分隔符。@Squashman-Stephan建议完全按照您的描述使用它。他假设文件分隔符不需要是phys如果OP只是想在Excel中打开文件,则可能会发生更改。没错,此答案并没有回答实际问题。但人们认为必须重新格式化数据的最常见原因之一是,数据可以在Excel中打开,这是重新格式化数据的一个很好的替代方法。OP没有说明重新格式化的目的,因此这个答案可能与OP有关,也可能与OP无关。@dbenham:绝对方便-我们经常使用它(不同的本地化)但请记住:据我所知,这不是
csv
定义的一部分。我不知道其他电子表格程序是否会处理它,甚至微软可能会决定在未来版本的Excel中不支持它。什么是“sep”,我如何在我的脚本中实际实现它?是“old.csv”我的文件?我仍然是一个noob批处理脚本编写者,我会如何在脚本中实际使用它,在>>之前是什么?@MPineda,代码是您问题中代码的直接替换。在>
之前,您应该拥有与您相同的代码,至少启用延迟扩展并初始化使用的变量。我明白了,只是尝试了一下它工作完美,不到5秒,谢谢!
@if (@X)==(@Y) @end /* harmless hybrid line that begins a JScrpt comment
::************ Documentation ***********
::parseCSV.bat version 1.2
:::
:::parseCSV [/option]...
:::
::: Parse stdin as CSV and write it to stdout in a way that can be safely
::: parsed by FOR /F. All columns will be enclosed by quotes so that empty
::: columns may be preserved. It also supports delimiters, newlines, and
::: escaped quotes within quoted values. Two consecutive quotes within a
::: quoted value are converted into one quote by default.
:::
::: Available options:
:::
::: /I:string = Input delimiter. Default is a comma (,)
:::
::: /O:string = Output delimiter. Default is a comma (,)
:::
::: The entire option must be quoted if specifying poison character
::: or whitespace literals as a delimiters for /I or /O.
:::
::: Examples: pipe = "/I:|"
::: space = "/I: "
:::
::: Standard JScript escape sequences can also be used.
:::
::: Examples: tab = /I:\t or /I:\x09
::: backslash = /I:\\
:::
::: /E = Encode output delimiter literal within value as \D
::: Encode newline within value as \N
::: Encode backslash within value as \S
:::
::: /D = escape exclamation point and caret for Delayed expansion
::: ! becomes ^!
::: ^ becomes ^^
:::
::: /L = treat all input quotes as quote Literals
:::
::: /Q:QuoteOutputFormat
:::
::: Controls output of Quotes, where QuoteOutputFormat may be any
::: one of the following:
:::
::: L = all columns quoted, quote Literals output as " (Default)
::: E = all columns quoted, quote literals Escaped as ""
::: N = No columns quoted, quote literals output as "
:::
::: The /Q:E and /Q:N options are useful for transforming data for
::: purposes other than parsing by FOR /F
:::
::: /U = Write unix style lines with newline (\n) instead of the default
::: Windows style of carriage return and linefeed (\r\n).
:::
:::parseCSV /?
:::
::: Display this help
:::
:::parseCSV /V
:::
::: Display the version of parseCSV.bat
:::
:::parseCSV.bat was written by Dave Benham. Updates are available at the original
:::posting site: http://www.dostips.com/forum/viewtopic.php?f=3&t=5702
:::
::************ Batch portion ***********
@echo off
if "%~1" equ "/?" (
setlocal disableDelayedExpansion
for /f "delims=: tokens=*" %%A in ('findstr "^:::" "%~f0"') do echo(%%A
exit /b 0
)
if /i "%~1" equ "/V" (
for /f "delims=:" %%A in ('findstr /bc:"::%~nx0 version " "%~f0"') do echo %%A
exit /b 0
)
cscript //E:JScript //nologo "%~f0" %*
exit /b 0
************ JScript portion ***********/
var args = WScript.Arguments.Named,
stdin = WScript.Stdin,
stdout = WScript.Stdout,
escape = args.Exists("E"),
literalQ = args.Exists("L"),
escapeQ = (args.Item("Q")&&args.Item("Q").toUpperCase()=="E"),
quoteCol = (args.Item("Q")&&args.Item("Q").toUpperCase()=="N") ? '' : '"',
delayed = args.Exists("D"),
inDelim = args.Item("I") ? eval('"'+args.Item("I")+'"') : ",",
outDelim = args.Item("O") ? eval('"'+args.Item("O")+'"') : ",",
newline = args.Exists("U") ? "\n" : "\r\n",
quote = false,
ln, c, n, out;
while (!stdin.AtEndOfStream) {
ln=stdin.ReadLine();
out="";
if (!quote) stdout.Write(quoteCol);
for (n=0; n<ln.length; n++ ) {
c=ln.charAt(n);
if (c == '"') {
if (literalQ) {
if (escapeQ) c+='"';
} else if (quote && ln.charAt(n+1) == '"') {
n++;
if (escapeQ) c+='"';
} else {
quote=!quote;
continue;
}
}
else if (c == inDelim && !quote) c=quoteCol+outDelim+quoteCol;
else if (escape) {
if (c == outDelim) c="\\D";
if (c == "\\") c="\\S";
}
else if (delayed) {
if (c == "!") c="^!";
if (c == "^") c="^^";
}
out+=c;
}
out += (quote) ? ((escape) ? "\\N" : newline) : quoteCol+newline;
stdout.Write(out);
}