使用Windows命令提示符查找大型文本文件的总行数时出错

时间:2014-11-20 22:44:40

标签: windows batch-file windows-7 cmd findstr

我想使用Windows命令提示符找到文本文件的总行数(> 60 GB)。

我用过:

 findstr /R /N "^" file.txt | find /C ":"

但是,返回的结果是负数。它溢出了吗?该文件不超过50亿行。对于整数(4字节),其最大范围是从-2,147,483,648到2,147,483,647。那么,我需要设计一个脚本来通过将结果除以1000来计算数字?

如果是,请帮助我如何设计Windows批处理文件。

2 个答案:

答案 0 :(得分:1)

您可以尝试使用JScript解决方案。 JavaScript编号为always a 64-bit float data type,最多15位为整数。但是需要一段时间。使用此脚本计算100兆XML文件中的行数需要大约15秒。

编辑:由于float数据类型不够大,我修改了脚本以使用数组作为计数器,然后将结果输出为连接字符串。只要fso.OpenTextFile().SkipLine()没有阻塞(为什么没有解决方案,但尝试使用其他语言,可能是Python或Perl?),这个应该工作,并希望它赢了&对性能的打击过于昂贵。我在4.3 gig ISO文件上测试了它,大约需要8分钟。

@if (@a==@b) @end /*

:: countlines.bat
:: usage: countlines.bat filetocount.log

:: batch portion does nothing remarkable
:: but relaunches itself with jscript interpreter
@echo off

cscript /nologo /e:jscript "%~f0" "%~f1"

goto :EOF

:: end of batch / begin JScript */

var fso, f, file = WSH.Arguments(0), longVal = [0],
ForReading = 1, ForWriting = 2, b4 = new Date();

// inherits global array longVal[]
// increments each element from right to left
function inc() {
    for (var i=longVal.length - 1; i>=0; i--) {
        if (++longVal[i] == 10) {
            longVal[i] = 0;
            if (!i) {
                longVal.splice(0, 0, 0);
                i++;
            }
            continue;
        }
        else break;
    }
}

fso = new ActiveXObject("Scripting.FileSystemObject");
f = fso.OpenTextFile(file, ForReading);
while (!f.AtEndOfStream) {
    f.SkipLine();
    inc();
}
WSH.Echo(longVal.join(''));
f.Close();

var stopwatch = 'Line count completed in ' + ((new Date() - b4) / 1000.0) + 's';
WSH.StdErr.WriteLine(stopwatch);

答案 1 :(得分:1)

这是一个用于计算线条的bat文件。是的,你正在达到32位的int限制,同样的事情会发生在set / a计算......所以某种分裂当然是个好主意。

@echo off
setlocal ENABLEDELAYEDEXPANSION

set Singles=0
set Thousands=0
for /f "tokens=1,* delims=:" %%a in ('findstr /nr "^" "%1"') do (
    rem echo %%a   %%b
    set /a Singles+=1
    if !Singles! equ 1000 (
        set /a Thousands+=1
        set Singles=0
    )
)
set Singles=x000%Singles%
echo %Thousands%.%Singles:~-3% thousand lines

我包含了rem行,以便您可以根据需要检查findstr的输出。

---好吧所以bat文件解决方案很慢---

这是一个vbs,可能会尽可能快(甚至可能接近或优于findstr / find时间?) 要运行:您可以使用:scriptname.vbs filename将结果输出到屏幕,或cscript -nologo scriptname.vbs filename在命令提示符下输出。

这是如何工作的简短摘要。文本流具有Line属性,该属性是32位signed int。只要我们检测到从+到 - 和 - 到+的每个开关,我们就可以使用最终的file.Line属性计算总行数。

if WScript.Arguments.Count = 0 then
    WScript.Echo "Missing filename parameter"
    WScript.Quit
end if

Const ForReading = 1, ForWriting = 2, ForAppending = 8
Const bytesToSkip = 2000000000
Dim fso, MyFile, count, direction, position, totalSize
Set fso = CreateObject("Scripting.FileSystemObject")

' Open the file to count.
Set MyFile = fso.OpenTextFile(WScript.Arguments(0), ForReading)

totalSize = fso.GetFile(WScript.Arguments(0)).Size
count=0
direction=1
position=0

' Jump through the file in big blocks
Do While position < totalSize
    MyFile.Skip(bytesToSkip) 'If going past of the end of the file, this doesn't error the first time
    position = position + bytesToSkip

    if MyFile.Line = 0 and direction=-1 Then
        ' Have wrapped back to 0
        count=count+1
        direction=1
    elseif direction <> abs(MyFile.Line)/MyFile.Line Then
        'Count each change from + to - or - to +
        count=count+1
        direction=direction*(-1)
    end if
    REM WScript.Echo direction & "    " & position & "    " & MyFile.Line & "    " & count
Loop

' Do final calculations
if MyFile.Line = 0 Then
    Count = Count*(2^31)
elseif direction = 1 Then
    count=Count*(2^31) + MyFile.Line
elseif direction = -1 Then
    count=Count*(2^31) + (2^31 + MyFile.Line)
end if

MyFile.Close

WScript.Echo "Total Lines = " & count