我想使用Windows命令提示符找到文本文件的总行数(> 60 GB)。
我用过:
findstr /R /N "^" file.txt | find /C ":"
但是,返回的结果是负数。它溢出了吗?该文件不超过50亿行。对于整数(4字节),其最大范围是从-2,147,483,648到2,147,483,647。那么,我需要设计一个脚本来通过将结果除以1000来计算数字?
如果是,请帮助我如何设计Windows批处理文件。
答案 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