【问题标题】:Copy lines from .csv file into another .csv file using batch script使用批处理脚本将 .csv 文件中的行复制到另一个 .csv 文件中
【发布时间】:2017-05-18 04:13:35
【问题描述】:

我正在从设备(输出)创建 .csv 文件,需要将此文件中的特定行数复制到另一个具有相同格式的 .csv 文件中。

幸运的是,它们的格式相同,因此每个文件都有相同的行要复制(第 68 到 107 行)。我已经尝试过使用其他来源的代码,但到目前为止我所能做的就是复制数据但无法将其插入到另一个文件中。任何帮助都会很棒!

@echo off

Set "InputFile=C:\*****\Desktop\Dev\Test\Default.csv"
Set "OutPutFile=C:\*****\Desktop\Dev\Test\OutputData.csv"
Set FromLine=68
Set ToLine=107

Call:ExtractLinesFromTextFile "%InputFile%" %FromLine% %ToLine% > 
"%OutPutFile%"

Exit /b

:ExtractLinesFromTextFile <InputFile> <FromLine> <ToLine>
(
echo Wscript.echo(ExtractLinesFromTextFile("%~1",%2,%3^)^)
echo Function ExtractLinesFromTextFile(TextFile,FromLine,ToLine^)
echo If FromLine ^<= ToLine Then
echo With CreateObject("Scripting.FileSystemObject"^).OpenTextFile(TextFile^)
echo Do Until .Line = FromLine Or .AtEndOfStream
echo .SkipLine
echo Loop
echo Do Until .Line ^> ToLine Or .AtEndOfStream
echo ExtractLinesFromTextFile = ExtractLinesFromTextFile ^& (.ReadLine ^& 
vbNewLine^)
echo Loop
echo End With
echo End If
echo End Function
)>"%~n0.vbs"
Cscript /Nologo "%~n0.vbs" "%~1" %~2 %~3
If Exist "%~n0.vbs" Del "%~n0.vbs"
Exit /b

【问题讨论】:

  • 编写一个除了创建和调用 VBScript 之外什么都不做的批处理文件是完全没有意义的。去掉批处理代码,直接写VBScript。

标签: csv batch-file vbscript


【解决方案1】:

为了说明您不想批量执行此操作的原因,这是在 VBScript 中将第 68 到 107 行复制到另一个文件的代码:

inputFilename  = "C:\path\to\input.csv"
outputFilename = "C:\path\to\output.csv"
fromLine = 68
toLine   = 107

Set fso = CreateObject("Scripting.FileSystemObject")
Set inFile  = fso.OpenTextFile(inputFilename)
Set outFile = fso.OpenTextFile(outputFilename, 2, True)

Do Until inFile.AtEndOfStream Or inFile.Line > toLine
  line = inFile.ReadLine
  If inFile.Line >= fromLine Then outFile.WriteLine line
Loop

inFile.Close
outFile.Close

为了说明为什么您也不想在 VBScript 中执行此操作,这与 PowerShell 中的操作相同:

$inputFile  = 'C:\path\to\input.csv'
$outputFile = 'C:\path\to\output.csv'
$fromLine   = 68
$toLine     = 107

$skip       = $fromLine - 1
$numLines   = $toLine - $skip

Get-Content $inputFile | Select-Object -Skip $skip -First $numLines |
    Set-Content $outputFile

可以简化为:

$inputFile  = 'C:\path\to\input.csv'
$outputFile = 'C:\path\to\output.csv'
$skip       = 67
$numLines   = 40

Get-Content $inputFile | Select-Object -Skip $skip -First $numLines |
    Set-Content $outputFile

如果需要,您甚至可以保留 CSV 标头:

$inputFile  = 'C:\path\to\input.csv'
$outputFile = 'C:\path\to\output.csv'
$skip       = 66
$numLines   = 40

Import-Csv $inputFile | Select-Object -Skip $skip -First $numLines |
    Export-Csv $outputFile -NoType

【讨论】:

  • 是的,我现在看到我这样做的效率非常低。感谢您的帮助!
【解决方案2】:

绝对不需要使用创建和调用 VBScript 的批处理文件。


您可以通过这样的纯批处理脚本完成任务:

@echo off
setlocal EnableExtensions EnableDelayedExpansion

rem // Define constants here:
set "_FILEIN=!USERPROFILE!\Desktop\Dev\Test\Default.csv"
set "_FILEOUT=!USERPROFILE!\Desktop\Dev\Test\OutputData.csv"
set /A "_LINEFROM=68"
set /A "_LINETO=107"

rem // Count number of lines of input file:
for /F %%C in ('^< "!_FILEIN!" find /C /V ""') do (
    rem // Read and write files using redirection:
    < "!_FILEIN!" > "!_FILEOUT!" (
        rem // Iterate through all available lines:
        for /L %%I in (1,1,%%C) do (
            rem // Read a single line:
            set "LINE=" & set /P LINE=""
            rem // Check position (line number) of current line:
            if %%I GEQ %_LINEFROM% if %%I LEQ %_LINETO% (
                rem // Return current line conditionally:
                echo(!LINE!
            )
        )
    )
)

endlocal
exit /B

请注意,纯批处理文件解决方案可能会受到行长和文件大小的限制。上述方法无法处理超过 1023 字节的行和超过 2147483647 行的文件。


这是另一种速度较慢的纯批处理脚本解决方案:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Define constants here:
set "_FILEIN=%USERPROFILE%\Desktop\Dev\Test\Default.csv"
set "_FILEOUT=%USERPROFILE%\Desktop\Dev\Test\OutputData.csv"
set /A "_LINEFROM=68"
set /A "_LINETO=107"

rem // Write file using redirection:
> "%_FILEOUT%" (
    rem // Read file using a loop, prefixed with line index:
    for /F "delims=" %%L in ('findstr /N "^" "%_FILEIN%"') do (
        rem // Extract line number:
        2> nul set /A "IDX=%%L"
        rem // Read current line:
        set "LINE=%%L"
        setlocal EnableDelayedExpansion
        rem // Check position (line number) of current line:
        if !IDX! GEQ %_LINEFROM% if !IDX! LEQ %_LINETO% (
            rem // Return current line conditionally:
            echo(!LINE:*:=!
        )
        endlocal
    )
)

endlocal
exit /B

这种方法不能处理超过 8191 - 7 = 8184 字节的行和超过 2147483647 行的文件。

【讨论】:

  • 为什么不使用for /f 在冒号处解析/拆分?这将在 cmd (for /f "skip=67tokens=1* delims=:" %A in ('findstr /N "^" ^&lt;InFile.csv') Do @if %A LEQ 107 @Echo %B)&gt;OutFile.csv 中提供一个衬里
  • 我想提供一个通用的解决方案;使用for /F "delims=:" 的方法从行中删除了前导冒号,因为后续分隔符被视为一个......
  • 感谢您的帮助!我最近一直在玩批处理文件,因此我认为我可以使用它,但使用其他格式可能更好。
猜你喜欢
  • 1970-01-01
  • 2013-09-07
  • 2020-11-27
  • 2016-03-26
  • 1970-01-01
  • 2012-12-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多