Board logo

标题: [文本处理] 批处理如何获取/提取大文本中含有指定字符串的最后一行内容? [打印本页]

作者: iq301    时间: 2015-2-5 18:00     标题: 批处理如何获取/提取大文本中含有指定字符串的最后一行内容?

本帖最后由 pcl_test 于 2017-4-10 13:58 编辑

有个文档每天由服务器生成,文档size非常大,有1G以上。我要找出文档里面符合  Date/Time 的行,并显示最后一行出来.

由于文档太大了。用bat速度好慢,

求助 :由于ISO原因,不允许使用第三方软件。只能自己编程。请问大家有没办法解决?谢谢

文档内容样式:

asdadffdasfsafasfasdfffadsfsafasdf

Date/Time: 2015-02-05 18:05:50

fsdfsadfsdfsdfdf

adfsfsdfasfffdsfafasdf

asdadffdasfsafasfasdfffadsfsafasdf

Date/Time: 2015-02-05 19:05:50

fsdfsadfsdfsdfdf

adfsfsdfasfffdsfafasdf
作者: CrLf    时间: 2015-2-5 20:19

  1. @echo off
  2. for /f "delims=" %%a in ('findstr "^Date/Time:" 文档.log') do set DateTime=%%a
  3. echo 取得的结果为 %DateTime%
  4. pause
复制代码

作者: iq301    时间: 2015-2-6 05:19

回复 2# CrLf


    文本txt档,非常大,用bat非常非常的慢。。bat可能吃不消,请问有没别的语言能达到快速的效果?比如:JAVA C++ VBS 这些语言我都i不会。。
作者: CrLf    时间: 2015-2-6 06:49

什么系统
作者: CrLf    时间: 2015-2-6 06:54

本帖最后由 CrLf 于 2015-2-6 07:33 编辑

试试这样,希望sort 受得了
  1. @echo off
  2. findstr "^Date/Time:" 文档.log | sort /65535 /o tmp.txt
  3. set /p DateTime=<tmp.txt
  4. echo 取得的结果为 %DateTime%
  5. pause
复制代码

作者: 慕夜蓝化    时间: 2015-2-6 08:17

本帖最后由 慕夜蓝化 于 2015-2-6 17:14 编辑

原来是要取得最后一行的吗 = =
  1. @echo off
  2. type "a.txt"|find "Date/Time" >$
  3. for /f "delims=" %%i in ('type "$"^|find /v /c ""') do (
  4.     set/a n=%%i-1
  5. )
  6. for /f "skip=%n% delims=" %%a in ('type "$"') do (
  7.     echo,%%a
  8. )
  9. del /f/q "$"
  10. pause
复制代码

作者: terse    时间: 2015-2-6 11:21

  1. @if(0)==(0) echo off
  2. cscript -nologo -e:jscript %0 <d.txt
  3. pause & exit/b
  4. @end
  5. var text = WScript.StdIn.ReadAll();
  6. var f = text.match(/Date\/Time:.*/ig);
  7. if (f) {WSH.Echo(f[f.length - 1])}
复制代码

作者: CrLf    时间: 2015-2-6 11:44

回复 7# terse


    感觉像 js 和 powershell  这种所有字符串都是对象的语言处理大文件的消耗应该很大,猜过去用  vbs 的 instrRev 也许更快
    火车上,没法验证,哪位有兴趣做个实验?挺好奇的
作者: Demon    时间: 2015-2-6 13:06

1G ReadAll
作者: CrLf    时间: 2015-2-6 16:08

改用 ReadLine(10000) 应该就不怕占内存了
作者: terse    时间: 2015-2-6 18:12

回复 8# CrLf
试了 POWERSHELL 方案 没测试大文件
测试一 110MB 文件 效率比JS略高
等楼主测试吧
  1. $file = "c:d.txt"
  2. ([io.file]::ReadAllLines($file) -match "Date/Time:")[-1]
复制代码

作者: CrLf    时间: 2015-2-6 19:19

本帖最后由 CrLf 于 2015-2-6 19:54 编辑

回复 11# terse


    用顶楼数据生成了 468M 大小的文件做了一组测试,结果让我大跌眼镜,gawk 和 sed 竟然这么慢
gawk 耗时58.6s,内存占用可忽略不计
  1. @echo off
  2. set t=%time%
  3. gawk "/^Date\/Time:/{$a=$0}END{print $a}" tmp.txt
  4. echo %t%  %time%
  5. pause
复制代码
sed 耗时未知(太久了,等不起),内存占用可忽略不计
  1. @echo off
  2. set t=%time%
  3. sed -n "/^Date\/Time:/h;${g;p}" tmp.txt
  4. echo %t%  %time%
  5. pause
复制代码
find /c + skip 耗时79.7s,内存占用可忽略不计
  1. @echo off
  2. set t=%time%
  3. find "Date/Time:"<tmp.txt>$
  4. for /f %%a in ('find /c /v ""^<$') do set /a n=%%a-1
  5. for /f "skip=%n% delims=" %%a in ($) do echo %%a
  6. echo %t%  %time%
  7. pause
复制代码
sort + set /p 耗时24.7s,内存占用中等
  1. @echo off
  2. set t=%time%
  3. findstr "^Date\/Time:" tmp.txt | sort /+65535 /o tmp2.txt
  4. set /p DateTime=<tmp2.txt
  5. echo 取得的结果为 %DateTime%
  6. echo %t%  %time%
  7. pause
复制代码
bat + js 耗时29.5s,内存占用高(约是文件体积的五倍)
  1. @if(0)==(0) echo off
  2. set t=%time%
  3. cscript -nologo -e:jscript %0 <tmp.txt
  4. echo %t%  %time%
  5. pause & exit/b
  6. @end
  7. var text = WScript.StdIn.ReadAll();
  8. var f = text.match(/Date\/Time:.*/ig);
  9. if (f) {WSH.Echo(f[f.length - 1])}
复制代码
纯 js 耗时65.26s,内存占用高(约是文件体积的两倍)
  1. var start = new Date()
  2. var fso = new ActiveXObject('Scripting.FileSystemObject')
  3. var ts = fso.OpenTextFile('tmp.txt',1)
  4. var text = ts.ReadAll()
  5. var f = text.match(/Date\/Time:.*/ig);
  6. if (f) {WSH.Echo(f[f.length - 1])}
  7. var end = new Date()
  8. WSH.Echo((end - start)/1000)
复制代码
纯 vbs 耗时49.354s,内存占用高(约是文件体积的两倍,和 js 相当)
  1. start = timer
  2. Set fso = CreateObject("Scripting.FileSystemObject")
  3. Set ts = fso.OpenTextFile("tmp.txt",1)
  4. text = ts.ReadAll
  5. i = instrRev(text,vbLf & "Date/Time:")
  6. text = mid(text,i)
  7. text = split(text,vbCrLf)(0)
  8. end2 = timer
  9. WSH.Echo(text & vbcrlf & (end2 - start))
复制代码
powershell io.file::ReadAllLines 耗时29.6s,内存占用高(约是文件体积的五倍)
  1. $start = get-date
  2. $file = "C:\Users\Administrator\Desktop\tmp.txt"
  3. ([io.file]::ReadAllLines($file) -match "Date/Time:")[-1]
  4. $end = get-date
  5. $end - $start
复制代码
powershell select-string 耗时140.8s,内存占用高(约是文件体积的五倍)
  1. $start = get-date
  2. $file = "C:\Users\Administrator\Desktop\tmp.txt"
  3. $a = select-string $file -pattern '^Date/Time:'
  4. $a[-1]
  5. $end = get-date
  6. $end - $start
复制代码
js while+Read 耗时22.675s,内存占用低,但本质是对最后 100000~200000 个字节进行搜索,所以...
  1. var start = new Date()
  2. var fso = new ActiveXObject('Scripting.FileSystemObject')
  3. var ts = fso.OpenTextFile('tmp.txt',1)
  4. var arr = ['','']
  5. var i=0
  6. while(!ts.AtEndOfStream){
  7. arr[i=!i]=ts.Read(100000)
  8. }
  9. var f = (arr[!i]+arr[i]).match(/Date\/Time:.*/ig);
  10. var end = new Date()
  11. if (f) {WSH.Echo(f[f.length - 1])}
  12. WSH.Echo((end - start)/1000)
复制代码
改用 skip 实现只取最后的 10000 字节,耗时21.96s,内存占用低,缺点和前一个方法一样,为了效率,并非全文搜索
  1. var start = new Date()
  2. var fso = new ActiveXObject('Scripting.FileSystemObject')
  3. var file = fso.GetFile('tmp.txt')
  4. var ts = file.OpenAsTextStream(1)
  5. var skip = file.Size-10000
  6. if(skip>0)ts.Skip(skip)
  7. var text = ts.ReadAll()
  8. var f = text.match(/Date\/Time:.*/ig);
  9. var end = new Date()
  10. if (f) {WSH.Echo(f[f.length - 1])}
  11. WSH.Echo((end - start)/1000)
复制代码

作者: iq301    时间: 2015-2-6 20:15

各位亲,非常谢谢你们无私的帮助,原文件行数超过30W行。这样的约1.5G文本有10个。操作系统是WIN7 。如果占用内存太大,电脑会不会直接挂掉。。。
作者: caruko    时间: 2015-2-11 15:00

建议用C写个程序,用 fseek 将位置指针从最后往前移动,读取指定长度的字符对比,直到找到符合的 字符。




欢迎光临 批处理之家 (http://bbs.bathome.net/) Powered by Discuz! 7.2