Board logo

标题: [文本处理] 请老师抽空帮写一个批处理文本合并去重复(已解答,谢谢各位老师的帮助!) [打印本页]

作者: PCL0769    时间: 2021-10-4 07:36     标题: 请老师抽空帮写一个批处理文本合并去重复(已解答,谢谢各位老师的帮助!)

本帖最后由 PCL0769 于 2021-10-12 17:03 编辑

01文件夹内有以下文本
1.txt
2.txt
3.txt
4.txt
......
N.txt
02文件夹内有以下文本
1.txt
2.txt
3.txt
4.txt
......
N.txt
03文件夹内有以下文本
1.txt
2.txt
3.txt
4.txt
......
N.txt
04文件夹内有以下文本
1.txt
2.txt
3.txt
4.txt
......
N.txt

05文件夹内有以下文本
........
有N个文件夹
请帮忙写一个将以上N个文件夹中的N个同名的文本合并然后生成一个新的文件夹,文件夹中同样生成合并后同名的文本
合并文件夹内有以下文本
1.txt
2.txt
3.txt
4.txt
......
N.txt

以下是原文档中的小部分格式内容,需要在合并后新生成的文本中去除不完整的行,去重复去特定行的语句,谢谢!
SZ300951        20210226        4727036
SZ300999        20210226        -201125534
SZ301000       20210原文本中少部分会有这种不完整的行,在合并后新生成的文本中将不完整的行去除)
SZ300          (原文本中少部分会有这种不完整的行,在合并后新生成的文本中将不完整的行去除)
SZ138811-QQ84299        20210226        0 (原文本中少部分会有此行,20210226 原文本中是按日期的一个变量,现需在新合并后生成的文本中将此行去除)

合并时能不能将记事本中的字符替换,替换条件如下:
SH替换成1|
SZ替换成0|   
SZ300951        20210226之间的空格替换成|   
20210226        4727036之间的空格替换成|

合并后的最终文本内容格式:
0|000001|20210104|45971388
1|600004|20210104|22269128


另:
以下是完整的两行。
SZ300951        20210226        4727036
SZ300999        20210226        -201125534

以下是不完整的两行,如果不好写就忽略此条件也行
SZ301000       20210
或者
SZ300   

以下是多余无用的行,此行内容不需要     (20210226 是按日期变化的变量)
SZ138811-QQ84299        20210226       0

不完整的行是原记事本偶尔某几个记事本中才会出现,不是所有的都会出现。
生成新的合并记事本时将这些不完整的去除,不完整的行不生成到这个新的合并记事本中。

请老师抽空帮写一个批处理,谢谢!
作者: newswan    时间: 2021-10-4 11:21

不完整的行,只有 1 列 2 列? 还是 列中 数据不完整?
作者: PCL0769    时间: 2021-10-4 12:09

本帖最后由 PCL0769 于 2021-10-4 12:55 编辑

回复 2# newswan
老师好!
SZ300951        20210226        4727036
SZ300999        20210226        -201125534
以上是完整的两行。

以下是不完整的两行,如果不好写就忽略此条件也行
SZ301000       20210
或者
SZ300   

以下是多余无用的行,此行内容不需要     (20210226 是按日期变化的变量)
SZ138811-QQ84299        20210226       0

不完整的行是原记事本偶尔某几个记事本中才会出现,不是所有的都会出现。
生成新的合并记事本时将这些不完整的去除,不完整的行不生成到这个新的合并记事本中
作者: newswan    时间: 2021-10-4 13:28

本帖最后由 newswan 于 2021-10-4 13:41 编辑

用了第三方命令 sed
  1. @echo off
  2. setlocal ENABLEDELAYEDEXPANSION
  3. set sour=aaa
  4. set dest=bbb
  5. del %dest%\*.txt
  6. set exclude=20210226
  7. for /f "usebackq tokens=* delims=" %%a in (`dir /s /b "%sour%\*.txt"`) do (
  8.     sed -r -n -e "/\w+\s+\w+\s+\w+/p" -e "/%exclude%/d" "%%~fa">> "%dest%\%%~na.txt"
  9. )
  10. for /f "usebackq tokens=* delims=" %%a in (`dir /s /b "%dest%\*.txt"`) do (
  11.     set _file_=%%~fa
  12.     for /f "usebackq tokens=* delims=" %%a in ("%_file_%") do (
  13.         set __%%a=%%a
  14.     )
  15.    
  16.     (
  17.         for /f "usebackq tokens=2 delims==" %%a in (`set __`) do (
  18.             echo %%a
  19.         )
  20.     ) > "%_file_%"
  21.     rem notepad"%_file_%"
  22. )
复制代码

作者: newswan    时间: 2021-10-4 13:36

findstr 支持正则太差,所以用了sed
作者: PCL0769    时间: 2021-10-4 13:41

回复 4# newswan
老师好!
是BAT吗?双击后只是闪了一下,没运行。
作者: newswan    时间: 2021-10-4 13:42

本帖最后由 newswan 于 2021-10-4 13:44 编辑

回复 6# PCL0769


可能 没有 sed
论坛里下载一个,放到 c:\windows
http://www.bathome.net/thread-36408-1-1.html
作者: PCL0769    时间: 2021-10-4 13:50

本帖最后由 PCL0769 于 2021-10-4 14:03 编辑

回复 7# newswan
老师好!
看到链接了,
正式版 - http://www.bathome.net/s/tool/index.html
测试版 - http://bcn.bathome.net/s/tool/index.html
是下载其中任一一个都行吗?谢谢老师!
没找到sed下载,都是SED应用方面的,因为级别不够一小时只能跟5帖

还是闪退,没运行
作者: newswan    时间: 2021-10-4 13:53

回复 8# PCL0769


    http://bcn.bathome.net/tool/4.8/sed.exe
作者: newswan    时间: 2021-10-4 14:16

我测试正确的,你自己调试一下

set sour=aaa    源路径
set dest=bbb    目的路径

set exclude=20210226   排除列表
作者: PCL0769    时间: 2021-10-4 14:33

回复 11# newswan
找不到 C:\*.txt
文件名、目录名或卷标语法不正确。

@echo off
setlocal ENABLEDELAYEDEXPANSION

set sour=C:\Users\Administrator\Desktop\15单\新建文件夹
set dest=C:\Users\Administrator\Desktop\15单\新建文件夹2

del %dest%\*.txt

for /f "usebackq tokens=* delims=" %%a in (`dir /s /b "%sour%\*.txt"`) do (
    sed -r -n -e "/\w+\s+\w+\s+\w+/p" -e "/%exclude%/d" "%%~fa">> "%dest%\%%~na.txt"
)

for /f "usebackq tokens=* delims=" %%a in (`dir /s /b "%dest%\*.txt"`) do (
    set _file_=%%~fa
    for /f "usebackq tokens=* delims=" %%a in ("%_file_%") do (
        set __%%a=%%a
    )
   
    (
        for /f "usebackq tokens=2 delims==" %%a in (`set __`) do (
            echo %%a
        )
    ) > "%_file_%"
    notepad "%_file_%"
)
作者: newswan    时间: 2021-10-4 14:44

本帖最后由 newswan 于 2021-10-4 15:34 编辑
  1. @echo off
  2. setlocal ENABLEDELAYEDEXPANSION
  3. set sour=C:\Users\admin\Desktop\New folder (2)\aaa
  4. set dest=C:\Users\admin\Desktop\New folder (2)\bbb
  5. set exclude=20210226
  6. del "%dest%\*.txt"
  7. for /f "usebackq tokens=* delims=" %%a in (`dir /s /b "%sour%\*.txt"`) do (
  8.     sed -r -n -e "/\w+\s+\w+\s+\w+/p" -e "/%exclude%/d" "%%~fa">> "%dest%\%%~na.txt"
  9. )
  10. for /f "usebackq tokens=* delims=" %%a in (`dir /s /b "%dest%\*.txt"`) do (
  11.     for /f "usebackq tokens=* delims=" %%a in ("%%~fa") do (
  12.         set __%%a=%%a
  13.     )
  14.    
  15.     (
  16.         for /f "usebackq tokens=2 delims==" %%a in (`set __`) do (
  17.             echo %%a
  18.         )
  19.     ) > "%%~fa"
  20.     notepad.exe "%%~fa"
  21. )
复制代码

作者: newswan    时间: 2021-10-4 15:12

本帖最后由 newswan 于 2021-10-4 15:32 编辑

powershell 好一些
  1. $sour = "aaa"
  2. $dest = "bbb"
  3. $exclude = "20210227"
  4. Remove-Item $dest\*.txt
  5. Get-ChildItem -path $sour *.txt -Recurse | foreach-object {
  6.     ( get-content $_.fullname ) -match "\w+\s+\w+\s+[-]?\w+" -notmatch $exclude | out-file -append $dest\$_
  7. }
  8. Get-ChildItem -path $dest *.txt | foreach-object {
  9.     $a = get-content $_.fullname | sort-object -unique
  10.     $a | out-file $dest\$_
  11.     notepad.exe $dest\$_
  12. }
复制代码

作者: newswan    时间: 2021-10-4 15:33

本帖最后由 newswan 于 2021-10-4 15:37 编辑

目录是这样的
  1. ├───aaa
  2. │   ├───01
  3. │   └───02
  4. └───bbb
复制代码
刚才 网站 拒绝登陆
作者: qixiaobin0715    时间: 2021-10-4 15:50

探讨关于在for循环中使用set name几个问题。
我也在关注如何解决此帖中问题,基本想法和你类似。其中有几个问题未考虑成熟:
1.当没有变量引导符时,比如set __,可以显示所有以__开头的变量,并以通常顺序显示;
2.当循环设置变量,并使用这些变量处理完成后,再次循环设置变量时,前面设置的变量并不会自动消失,还会存在,直到将它们设置为空值或是退出cmd后。
所以,使用set name来处理帖子中的问题时,如果没有顺序要求应当可行。并且要考虑在下次循环前清空前面的变量值。
我自己未想到解决的办法。
作者: newswan    时间: 2021-10-4 16:04

本帖最后由 newswan 于 2021-10-4 16:08 编辑

回复 15# qixiaobin0715


欠考虑,如果是单文件去重,需要清除变量

谢谢!!!
作者: newswan    时间: 2021-10-4 16:07

本帖最后由 newswan 于 2021-10-4 18:52 编辑
  1. @echo off
  2. setlocal ENABLEDELAYEDEXPANSION
  3. set sour=C:\Users\admin\Desktop\New folder (2)\aaa
  4. set dest=C:\Users\admin\Desktop\New folder (2)\bbb
  5. set exclude=20210226
  6. del "%dest%\*.txt"
  7. for /f "usebackq tokens=* delims=" %%a in (`dir /s /b "%sour%\*.txt"`) do (
  8.     sed -r -n -e "/\w+\s+\w+\s+\w+/p" -e "/%exclude%/d" "%%~fa">> "%dest%\%%~na.txt"
  9. )
  10. for /f "usebackq tokens=* delims=" %%a in (`dir /s /b "%dest%\*.txt"`) do (
  11.     for /f "usebackq tokens=2 delims==" %%a in (`set __ 2^>nul`) do (
  12.         set %%a=
  13.     )
  14.     for /f "usebackq tokens=* delims=" %%a in ("%%~fa") do (
  15.         set __%%a=1
  16.     )
  17.    
  18.     (
  19.         for /f "usebackq tokens=2 delims==" %%a in (`set __`) do (
  20.             echo %%a
  21.         )
  22.     ) > "%%~fa"
  23.     notepad.exe "%%~fa"
  24. )
复制代码

作者: PCL0769    时间: 2021-10-4 18:02

本帖最后由 PCL0769 于 2021-10-4 18:12 编辑

回复 15# qixiaobin0715
老师好!
现在用老师你上次帮写的D:/ABC合并,然后用vbs  SZ替换为0|   SH 替换为1|  空格替换成| SZ138...-QQ...替换成空格(此处还是留有不全的一行数据)。
分两步完成,首先用bat合并 ,然后vbs替换,这么做的结果是会留有不完整的行数据

0|301075|20210930|44406634
1|601077|20210930|-67302759
0||20210930|0 (0|后面的空格就是SZ139...-QQ...替换后的空数值)

newswan老师好!
楼上的代码还是闪退。
谢谢!
作者: newswan    时间: 2021-10-4 18:54

我这里运行是正确的,你自己调试吧
作者: PCL0769    时间: 2021-10-4 19:13

回复 19# newswan
老师好!刚刚传了部分文本到云盘。
链接:
https://pan.baidu.com/s/1hqJLvFBn6n1Y-g9518TVyw
提取码:
9ewg
作者: newswan    时间: 2021-10-4 20:58

回复 20# PCL0769


数据量很大,powershell 效率高些
  1. $sour = "D:\share\tech\New folder (2)\aaa"
  2. $dest = "D:\share\tech\New folder (2)\ccc"
  3. $exclude = "20210227"
  4. Remove-Item $dest\*.txt
  5. get-date
  6. Get-ChildItem -path $sour *.txt -Recurse | foreach-object {
  7.     $_.fullname
  8.     ( get-content $_.fullname ) -match "\w+\s+\w+\s+[-]?\w+" -notmatch $exclude -replace "SZ","1" -replace "SH","0" -replace "\s+","|" | out-file -append $dest\$_
  9. }
  10. get-date
  11. Get-ChildItem -path $dest *.txt | foreach-object {
  12.     $_.fullname
  13.     $a = get-content $_.fullname | sort-object -unique
  14.     $a | out-file $dest\$_
  15. }
  16. get-date
复制代码

作者: Batcher    时间: 2021-10-4 21:41

回复 18# PCL0769


建议以后不要再说“不行”、“一闪而过”、“没有反应”之类的话,因为这对于想要给你进一步帮助的人来说没有任何意义。希望大家都能学会的一个知识点是:如何查看代码的报错信息。

如果你在执行.bat脚本,请参考Q-01观察一下哪行代码在报错以及详细的报错信息:
https://mp.weixin.qq.com/s/6lbb97qUOs1sTyKJfN0ZEQ

如果你在执行.ps1脚本,请参考:
http://bbs.bathome.net/thread-31071-1-1.html
作者: PCL0769    时间: 2021-10-4 22:56

回复 22# Batcher
好的谢谢老师提醒,以后注意。
双击运行时,只见到闪了一下,来不及看批处理出现什么问题就退出界面,小白一枚,还请老师见谅!
作者: PCL0769    时间: 2021-10-4 23:07

本帖最后由 PCL0769 于 2021-10-4 23:08 编辑

回复 21# newswan
老师好!谢谢!
请教老师,后缀是用bat吗?
源数据放在桌面C:\Users\Administrator\Desktop\15单\金额16\补数据文件夹下
这里是不是要这么修改:
$sour = "C:\Users\Administrator\Desktop\15单\金额16\补数据\aaa"
$dest = "C:\Users\Administrator\Desktop\15单\金额16\补数据\ccc"
按这修改后还是闪退,是不是在最后加上PUSH就不会出现闪退,实在太快退出界面不知道没运行起来是什么原因。
作者: newswan    时间: 2021-10-4 23:48

本帖最后由 newswan 于 2021-10-5 00:56 编辑

回复 24# PCL0769

使用 powershell 看这里
http://www.bathome.net/thread-59270-1-1.html

如果批处理,用第三方命令 sort 排序去重,效率高。
  1. ├───aaa    <--- 数据源
  2.      ├───01
  3.      └───02
复制代码

作者: qixiaobin0715    时间: 2021-10-5 11:26

回复 21# newswan
确实是这样。批处理代码倒是写出来了,真是慢的让人忍受不了。
作者: newswan    时间: 2021-10-5 12:00

本帖最后由 newswan 于 2021-10-5 12:23 编辑

回复 26# qixiaobin0715

去重 效率比较
gnu:sort = vbs > powershell > 批处理

第三方命令,有的和  windows 自带命令重名
第三方命令保存到单独目录,然后把这个路径添加到 %path% 的前面部分
比如
  1. set Path=C:\msys64\usr\bin;%Path%
复制代码

作者: qixiaobin0715    时间: 2021-10-5 12:27

回复 27# newswan
批处理处理大文本文件速度确实慢,就楼主提供的文件测试,for /f 变量替换速度也不行。
作者: newswan    时间: 2021-10-5 13:12

本帖最后由 newswan 于 2021-10-5 13:15 编辑

回复 28# qixiaobin0715


vbs 不会,但是 powershell 效率低,是很无语的。ms 一向是这样
批处理+第三方 有时候也麻烦。
作者: PCL0769    时间: 2021-10-5 13:19

本帖最后由 PCL0769 于 2021-10-5 13:40 编辑

回复 29# newswan
老师好!
下面是从论坛组装的VBS替换
Set WshShell = CreateObject("Wscript.Shell")
WshShell.Run "cmd /c dir /s/b *.txt > list.txt",vbHide
Wscript.Sleep 1000
sFile = "list.txt"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set oFile = objFSO.OpenTextFile(sFile,1)
Do While Not oFile.AtEndOfStream
strLine = oFile.ReadLine
If Len(strLine) > 0 Then
Set File = objFSO.OpenTextFile(strLine, 1)
aryLines = File.ReadAll
File.Close
aryLines = Replace(aryLines, "SZ", "0|")
aryLines = Replace(aryLines, "SH", "1|")

Set File = objFSO.OpenTextFile(strLine, 2)
File.Write aryLines
File.Close
End If
Loop
oFile.Close
objFSO.DeleteFile sFile
Set objFSO = Nothing

这个替换效率还行,就是得分两步,一:bat合并  二:vbs替换
vbs将不完整的行和那个手机号QQ号的删除就搞不懂怎么组装

用这个VBS替换,目前一共有36个文件夹的内容,替换的话在10分钟内就完成了

只要转换的内容不出错,多花点时间没关系,最初的原始数据是个三列cvs,1月份到现在的数据拆分转换成现在的01-09文件夹,电脑不关机总运行了3天3夜。速度慢点没关系,只要数据转换不出错就行
作者: xczxczxcz    时间: 2021-10-5 14:47

无聊 写了个 PS 跑了下, 50秒
作者: PCL0769    时间: 2021-10-5 14:55

回复 31# xczxczxcz
老师好!
PS又是什么?
恳请老师详解,谢谢!
作者: qixiaobin0715    时间: 2021-10-5 15:36

一分钟不到解决,真乃高手也!
作者: qixiaobin0715    时间: 2021-10-5 15:48

我用纯批写了一个,且未去重,测试目录用了22分钟,一直未好意思发。
作者: newswan    时间: 2021-10-5 16:07

gnu命令: sed sort
  1. @echo off
  2. setlocal ENABLEDELAYEDEXPANSION
  3. set path=%pathgnu%;%path%
  4. echo %path%
  5. set sour=新建文件夹
  6. set dest=bbb1
  7. set exclude=QQ
  8. del /q "%dest%\*.*"
  9. echo %~nx0 %time% 1 >>time.txt
  10. for /f "usebackq tokens=* delims=" %%a in (`dir /s /b "%sour%\*.txt"`) do (
  11.     echo "%%~fa"
  12.     type "%%~fa" | sed -r -e "/\S+\s+\S+\s+\S+/^!d" -e "/%exclude%/d" -e "s/SZ/1/" -e "s/SH/0/" -e "s/\s+/^|/g"  >> "%dest%\%%~na.tmp"
  13. )
  14. echo,
  15. echo %~nx0 %time% 2 >>time.txt
  16. echo,
  17. for /f "usebackq tokens=* delims=" %%a in (`dir /s /b "%dest%\*.tmp"`) do (
  18.     echo "%%~fa"
  19.     type "%%~fa" | sort.exe -u >>"%%~dpna.txt"
  20. )
  21. echo %~nx0 %time% 3 >>time.txt
  22. echo,
  23. del %dest%\*.tmp
复制代码

作者: newswan    时间: 2021-10-5 16:08

gnu 命令 sed awk
  1. @echo off
  2. setlocal ENABLEDELAYEDEXPANSION
  3. set path=%pathgnu%;%path%
  4. echo %path%
  5. set sour=新建文件夹
  6. set dest=bbb2
  7. set exclude=QQ
  8. del /q "%dest%\*.*"
  9. echo %~nx0 %time% 1 >>time.txt
  10. for /f "usebackq tokens=* delims=" %%a in (`dir /s /b "%sour%\*.txt"`) do (
  11.     echo "%%~fa"
  12.     type "%%~fa" | sed -r -e "/\S+\s+\S+\s+\S+/^!d" -e "/%exclude%/d" -e "s/SZ/1/" -e "s/SH/0/" -e "s/\s+/^|/g"  >> "%dest%\%%~na.tmp"
  13. )
  14. echo,
  15. echo %~nx0 %time% 2 >>time.txt
  16. echo,
  17. for /f "usebackq tokens=* delims=" %%a in (`dir /s /b "%dest%\*.tmp"`) do (
  18.     echo "%%~fa"
  19.     type "%%~fa" | awk " { arr[$0]++ ; if ( arr[$0] == 1 ) { print $0 } } "  >>"%%~dpna.txt"
  20. )
  21. echo %~nx0 %time% 3 >>time.txt
  22. echo,
  23. del %dest%\*.tmp
复制代码

作者: newswan    时间: 2021-10-5 16:10

效率 比较
sed + sort
1.bat 16:01:09.17 1
1.bat 16:02:06.45 2
1.bat 16:02:21.43 3
sed + awk
2.bat 16:03:13.41 1
2.bat 16:04:11.68 2
2.bat 16:04:26.42 3

两种办法 效率相同,但是 ps 就差很多了。
作者: qixiaobin0715    时间: 2021-10-5 16:16

速度够快。
作者: idwma    时间: 2021-10-5 17:24

回复 21# newswan


    可以试试net静态类,这里只把读写改了就快了很多,如果把替换部分也改了应该还能再加速
  1. Get-ChildItem -path $sour *.txt -Recurse | foreach-object {
  2.     $_.fullname
  3.     $b=( [IO.File]::ReadAllLines($_.fullname) ) -match "\w+\s+\w+\s+[-]?\w+" -notmatch $exclude -replace "SZ","1" -replace "SH","0" -replace "\s+","|"
  4.     $a=$dest,$_.name -join '\'
  5.     [IO.File]::WriteAllLines($a,$b)
  6. }
复制代码

作者: newswan    时间: 2021-10-5 17:33

本帖最后由 newswan 于 2021-10-5 21:07 编辑

回复 39# idwma


谢谢指点
net 没学过。。。
合并效率一样了,去重,还是很慢
  1. $sour = "D:\share\tech\New folder\新建文件夹"
  2. $dest = "D:\share\tech\New folder\ccc2"
  3. $exclude = "QQ"
  4. Remove-Item $dest\*.*
  5. ( $MyInvocation.MyCommand.Name + "  1  " + (get-date -Format "HH:mm:ss.ff").tostring() ) | out-file -Encoding ascii -append time.txt
  6. Get-ChildItem -path $sour *.txt -Recurse | foreach-object {
  7.     $_.fullname
  8.     $filename = Join-Path -path $dest -ChildPath ($_.basename + ".tmp")
  9.     $a=( [IO.File]::ReadAllLines($_.fullname) )
  10.     $a = $a -match "\S+\s+\S+\s+\S+" -notmatch $exclude -replace "SZ","1" -replace "SH","0" -replace "\s+","|"
  11.     [IO.File]::AppendAllLines([string]$filename , [string[]]$a)
  12. }
  13. ( $MyInvocation.MyCommand.Name + "  2  " + (get-date -Format "HH:mm:ss.ff").tostring() ) | out-file -Encoding ascii -append time.txt
  14. Get-ChildItem -path $dest *.tmp | foreach-object {
  15.     $_.fullname
  16.     $filename = Join-Path -path $dest -ChildPath ($_.basename + ".txt")
  17.     $ht = @{}
  18.     $a = ( [IO.File]::ReadAllLines($_.fullname) )
  19.     $a = $a | foreach-object {
  20.         if ( -not ( $ht.ContainsKey($_) ) )
  21.         {
  22.             $_
  23.             $ht.add($_,"1")
  24.         }
  25.     }
  26.     $a | out-file -Encoding utf8 $filename
  27. }
  28. ( $MyInvocation.MyCommand.Name + "  3  " + (get-date -Format "HH:mm:ss.ff").tostring() ) | out-file -Encoding ascii -append time.txt
复制代码

作者: PCL0769    时间: 2021-10-6 07:55

回复 31# xczxczxcz
老师好!能将这个PS发出来吗?谢谢!
作者: idwma    时间: 2021-10-6 16:16

本帖最后由 idwma 于 2021-10-6 16:17 编辑

回复 40# newswan

去重的部分抄前辈的试试看快不快http://www.bathome.net/thread-25194-2-1.html
  1. Get-ChildItem -path $dest *.tmp | foreach-object {
  2.     $reader = New-Object -TypeName System.IO.StreamReader -ArgumentList $_.fullname
  3.     $aa=New-Object System.Collections.Generic.HashSet[string]
  4.     $_.fullname
  5.     $filename = Join-Path -path $dest -ChildPath ($_.basename + ".txt")
  6.     while ( $read = $reader.ReadLine() ) {
  7.         out-null -InputObject $aa.add($read)
  8.     }
  9.     [IO.File]::WriteAllLines($filename,$aa)
  10. }
复制代码

作者: newswan    时间: 2021-10-6 20:22

回复 42# idwma


谢谢,这个用时是 unix 工具的 6 倍,比前面的要好多了
作者: newswan    时间: 2021-10-6 20:23

一段时间不用,很多都不熟悉了啊
作者: went    时间: 2021-10-6 20:26

可以尝试下多线程,线程数越多越快,取决你的cpu
数据处理函数可以自行优化
  1. #&cls&cd /d "%~dp0" & @powershell -c "Get-Content '%~0' | Select-Object -Skip 1 | Out-String | Invoke-Expression" & pause&exit
  2. cls
  3. $t1 = Get-Date
  4. $src_dir = '新建文件夹'
  5. $dst_dir = 'out'
  6. [void][System.IO.Directory]::CreateDirectory($dst_dir)
  7. #线程函数 处理数据
  8. $HandleGroupJob = {
  9.     #线程参数
  10.     param($dst_dir,$groupInfo)
  11.     Write-Host $groupInfo.Name
  12.     #汇总去重并筛选
  13. $set = New-Object 'System.Collections.Generic.HashSet[string]'
  14.     & { $groupInfo.Group | foreach { [IO.File]::ReadAllLines($_.FullName)} } | foreach {
  15. if($_ -match '\S+\s+\d+\s+-?\d{2,}'){
  16. [void]$set.Add(($_ -replace 'SH','1|' -replace 'SZ','0|' -replace '\s+','|'))
  17. }
  18. }
  19.     #输出
  20.     Out-File -InputObject $set -FilePath ('{0}\{1}' -f $dst_dir,$groupInfo.Name)
  21. $set = $null
  22.     return ($groupInfo.Name + ' 已完成')
  23. }
  24. #多线程设置
  25. $pool = [runspacefactory]::CreateRunspacePool(1,10) #最多10个线程并发
  26. $pool.Open()
  27. $threads = New-Object 'System.Collections.ArrayList'
  28. $results = New-Object 'System.Collections.ArrayList'
  29. '开始创建线程...'
  30. Get-ChildItem -Recurse -Path $src_dir -Filter '*.txt' | Group-Object {$_.Name} | foreach {
  31.     $_.Name
  32.     $thread = [powershell]::Create()
  33.     $thread.RunspacePool = $pool
  34.     [void]$thread.AddScript($HandleGroupJob)
  35.     [void]$thread.AddArgument($dst_dir)
  36.     [void]$thread.AddArgument($_)
  37.     [void]$threads.Add($thread)
  38.     [void]$results.Add($thread.BeginInvoke())
  39. }
  40. '-------------------------------'
  41. '等待线程结束'
  42. while($true){
  43.     $all_done = $true
  44.     for($i = 0; $i -lt $results.Count; $i++){
  45.         if($results[$i] -ne $null){
  46.             if($results[$i].IsCompleted){
  47.                 $threads[$i].EndInvoke($results[$i])
  48. $threads[$i].Dispose()
  49. $threads[$i] = $null
  50.                 $results[$i] = $null
  51. [System.GC]::Collect()
  52.             } else {
  53.                 $all_done = $false
  54.             }
  55.         }
  56.     }
  57.     if($all_done){ break }
  58.     Start-Sleep -Milliseconds 500
  59. }
  60. #关闭线程池
  61. $pool.Close()
  62. '-------------------'
  63. '{0}  -> {1}' -f $t1,(Get-Date)
复制代码

作者: went    时间: 2021-10-6 20:30

回复 45# went


    线程不要设置过多,不然cpu容易爆满
作者: idwma    时间: 2021-10-6 20:44

回复 44# newswan


    看went的代码发现一个[void],把空输出改成这个瞬间起飞呀
  1. Get-ChildItem -path $dest *.tmp | foreach-object {
  2.     $reader = New-Object -TypeName System.IO.StreamReader -ArgumentList $_.fullname
  3.     $aa=New-Object System.Collections.Generic.HashSet[string]
  4.     $_.fullname
  5.     $filename = Join-Path -path $dest -ChildPath ($_.basename + ".txt")
  6.     while ( $read = $reader.ReadLine() ) {
  7.         [void]$aa.add($read)
  8.     }
  9.     [IO.File]::WriteAllLines($filename,$aa)
  10. }
复制代码

作者: went    时间: 2021-10-6 21:01

回复 47# idwma


     估计是[void]直接强转成了$null才不会输出
作者: newswan    时间: 2021-10-7 20:49

相当于
  1. $null =
复制代码

作者: WHY    时间: 2021-10-8 15:47

本帖最后由 WHY 于 2021-10-10 21:55 编辑

Test.vbs
  1. Rem On Error Resume Next
  2. Dim srcDir, dstDir
  3. srcDir = "E:\Test\新建文件夹"           '源文件夹路径,需替换为实际路径
  4. dstDir = "E:\Test\新建文件夹1"          '目标文件夹路径
  5. Dim wsc
  6. Set wsc = CreateObject("WScript.Shell")
  7. If WSH.Arguments.Count = 0 Then
  8.     wsc.Run "cscript " & chr(34) & WSH.ScriptFullName & chr(34) & " ARG", 0
  9.     WScript.Quit
  10. End If
  11. Dim dic1, fso
  12. Set dic1 = CreateObject("Scripting.Dictionary")
  13. Set fso  = CreateObject("Scripting.FileSystemObject")
  14. Dim reg
  15. Set reg     = New RegExp
  16. reg.Pattern = "[ \t]+"
  17. reg.Global  = True
  18. Dim objExec
  19. If Not fso.FolderExists(srcDir) Then MsgBox "源文件夹不存在" : WSH.Quit
  20. wsc.Run "cmd /c md " & chr(34) & dstDir & chr(34) & " 2>nul", 0              '创建目标文件夹
  21. Set objExec = wsc.Exec( "cmd /c dir /b /a-d /s " & chr(34) & srcDir & "\*.txt" & chr(34) )  '遍历源文件夹
  22. Rem 字典dic1,key=文件名,value=文件路径
  23. Dim strFilePath, strFileName
  24. Do Until objExec.StdOut.AtEndOfStream
  25.     strFilePath = objExec.StdOut.ReadLine
  26.     strFileName = fso.GetFile(strFilePath).Name
  27.     strFileName = LCase(strFileName)
  28.     If Not dic1.Exists(strFileName) Then
  29.         dic1.Add strFileName, strFilePath
  30.     Else
  31.         dic1.Item(strFileName) = dic1.Item(strFileName) & vbLf & strFilePath
  32.     End If
  33. Loop
  34. Rem 遍历字典dic1
  35. Dim key
  36. For Each key In dic1.Keys
  37.     GetFileContent key, Split( Dic1.Item(key), vbLf )
  38. Next
  39. Function GetFileContent(fileName, ByRef arrFilePath)
  40.     Dim dic2, i, objFile, strLine
  41.     Set dic2 = CreateObject("Scripting.Dictionary")
  42.     For i = 0 To UBound(arrFilePath)
  43.         Set objFile = fso.OpenTextFile(arrFilePath(i), 1)
  44.         Do Until objFile.AtEndOfStream
  45.             strLine = objFile.ReadLine
  46.             strLine = reg.Replace(strLine, "|")                                       '空格替换为"|"
  47.             If UBound(Split(strLine, "|")) >= 2 And InStr(strLine, "-QQ") <= 0 Then   '如果大于等于3列、不含 "-QQ"
  48.                 strLine = Replace(Replace(strLine,"SZ", "0|"),"SH", "1|")             '替换 "SZ" 和 "SH"
  49.                 If Not dic2.Exists(strLine) Then                                      '字典dic2,用于去重复
  50.                     dic2.Add strLine, True
  51.                 End If
  52.             End If
  53.         Loop
  54.         objFile.Close
  55.         Set objFile = Nothing
  56.     Next
  57.     fso.OpenTextFile(dstDir & "\" & fileName, 2, True).Write( Join(dic2.Keys, vbCrLf) )    '保存
  58.     Set dic2 = Nothing
  59. End Function
  60. MsgBox "Done"
复制代码
Test.PS1
  1. $dt = get-Date;
  2. $srcDir = 'E:\Test\新建文件夹';
  3. $dstDir = 'E:\Test\新建文件夹1';
  4. If (![IO.Directory]::Exists($dstDir)){ $null = md $dstDir }
  5. $dic = New-Object 'System.Collections.Generic.Dictionary[string, [Collections.ArrayList]]';
  6. forEach( $file In (dir $srcDir -Recurse -Filter '*.txt') ){
  7.     $Name = $file.BaseName.ToUpper();
  8.     $Path = $file.FullName;
  9.     if( !$dic.ContainsKey($Name) ){
  10.         $dic.Add($Name, @($Path));
  11.     } else {
  12.         [void]$dic[$Name].Add($Path);
  13.     }
  14. }
  15. forEach( $key In $dic.Keys ){
  16.     $Hash = @{};
  17.     for( $i=0; $i -lt $dic[$key].Count; $i++ ){
  18.         $arr = [IO.File]::ReadAllLines($dic[$key][$i], [Text.Encoding]::Default);
  19.         $arr = $arr -match '^(?:(?!-QQ)\S)+\s+\S+\s+\S+';
  20.         $arr = $arr -replace '\s+', '|' -replace 'SZ', '0|' -replace 'SH', '1|';
  21.         $Count = $arr.Count;
  22.         for( $j=0; $j -lt $Count; $j++ ){
  23.             if( !$Hash.ContainsKey($arr[$j]) ){
  24.                 $Hash.Add($arr[$j], $True);
  25.             }
  26.         }
  27.     }
  28.     [IO.File]::WriteAllLines( $dstDir + '\' + $key + '.txt', $Hash.Keys );
  29. }
  30. ((get-Date) - $dt).TotalSeconds;
复制代码

作者: newswan    时间: 2021-10-8 17:52

本帖最后由 newswan 于 2021-10-8 17:54 编辑

同名文件分组,流式处理
需要 sed awk sort
  1. @echo off
  2. setlocal ENABLEDELAYEDEXPANSION
  3. set sour=新建文件夹
  4. set dest=%~n0
  5. set exclude=QQ
  6. set "_cmd_=dir /s /b %sour%\*.txt | sed -r -e "s/^.+[\]//" | sort -u"
  7. set _cmdsed_=-r -e "/%exclude%/d" -e "/^\S+\s+\S+\s+\S+$/^!d" -e "s/SZ/1/" -e "s/SH/0/" -e "s/\s+/^|/g"
  8. set _cmdawk_=" { arr[$0]++ ; if ( arr[$0] == 1 ) { print $0 } } "
  9. for /f "usebackq tokens=* delims=" %%a in (`cmd /c "%_cmd_%"`) do (
  10.     echo %%a
  11.     (
  12.         for /f "usebackq tokens=* delims=" %%b in (`dir /s /b "%sour%\%%a"`) do (
  13.             type "%%~fb"
  14.         ) | sed -r -e $a\
  15.     ) | sed !_cmdsed_! | awk !_cmdawk_! > "%dest%\%%~nxa"
  16. )
复制代码
ps: linux 的 sort 不是 windows自带的
作者: xczxczxcz    时间: 2021-10-9 11:55

原VSCODE调试50秒,
今优化了两点:I/O读取和范型数据处理,现缩短至平均24秒(23.7XX~24.2XX)。(按顶楼的要求和网盘文件)

视频被百度转码变成卡顿了

第一个视频为前台处理:约24秒
https://pan.baidu.com/s/1VXnS_n6mE457iUp-rLk8Hg

第二个视频为后台处理:约28秒
https://pan.baidu.com/s/1S6Dl1KqAus_QpBVkTcOYWw
作者: newswan    时间: 2021-10-9 12:47

本帖最后由 newswan 于 2021-10-9 12:55 编辑

回复 52# xczxczxcz


可以在vbs里加个计时器,完成后显示时长
这样时间比较准确
作者: newswan    时间: 2021-10-9 12:50

  1. @echo off
  2. setlocal ENABLEDELAYEDEXPANSION
  3. chcp 936
  4. set path=%pathgnu%;%path%
  5. set sour=新建文件夹
  6. set dest=%~n0
  7. set exclude=QQ
  8. if exist %dest% rd /s /q %dest%
  9. if not exist %dest% mkdir %dest%
  10. call :C_timer
  11. set "_cmd_=dir /s /b %sour%\*.txt | sed -r -e "s/^.+[\]//" | sort -u"
  12. set _cmdsed_=-r -e "/%exclude%/d" -e "/^\S+\s+\S+\s+\S+$/^!d" -e "s/SH/0/" -e "s/SZ/1/" -e "s/\s+/^|/g"
  13. set _cmdawk_=" { arr[$0]++ ; if ( arr[$0] == 1 ) { print $0 } } "
  14. for /f "usebackq tokens=* delims=" %%a in (`cmd /c "%_cmd_%"`) do (
  15.     echo %%a
  16.     (
  17.         for /f "usebackq tokens=* delims=" %%b in (`dir /s /b "%sour%\%%a"`) do (
  18.             type "%%~fb"
  19.         ) | sed -r -e $a\
  20.     ) | sed !_cmdsed_! | awk !_cmdawk_! > "%dest%\%%~nxa"
  21. )
  22. call :C_timer sum
  23. exit/b
  24. rem del %dest%\*.tmp
  25. :C_timer
  26. if not defined _ti_ set _ti_=-1
  27. set/a _ti_+=1
  28. set _tb_=%_te_%
  29. set _te_=%time%
  30. if %_ti_% EQU 0 (
  31.     set _tb_=%_te_%
  32. )
  33. set/a _tdiff_=(9%_te_:~0,2%-9%_tb_:~0,2%)*360000+(9%_te_:~3,2%-9%_tb_:~3,2%)*6000+(9%_te_:~6,2%%_te_:~9,2%-9%_tb_:~6,2%%_tb_:~9,2%)
  34. set/a _tdiff_=%_tdiff_:-=8640000-%
  35. set/a _tdiffSum_+=%_tdiff_%
  36. if "%_ti_%" == "0" (
  37.     (echo,) >>time.txt
  38.     (echo %~nx0  %_ti_%  %_te_%) >>time.txt
  39. ) else (
  40.     (echo %~nx0  %_ti_%  %_te_%  %_tdiff_:~0,-2%.%_tdiff_:~-2%) >>time.txt
  41. )
  42. if %1.==sum. (
  43.     (echo %~nx0                  %_tdiffSum_:~0,-2%.%_tdiffSum_:~-2%) >>time.txt
  44. )
  45. goto :eof
复制代码

作者: xczxczxcz    时间: 2021-10-9 13:24

回复 54# newswan


    要vbs计时器作什么, StopWatch类不香吗?
作者: newswan    时间: 2021-10-9 13:28

本帖最后由 newswan 于 2021-10-9 13:33 编辑

回复 55# xczxczxcz


我的意思是加到vbs代码里,运行完毕显示用时
MsgBox "Done 用时 xx.xx "
作者: xczxczxcz    时间: 2021-10-9 13:43

回复 56# newswan


    要显示对话框的话用 VisualBasic 的对话框不更好!
作者: xczxczxcz    时间: 2021-10-9 13:45

还可以调用 winform  windows的对话框,更简单
作者: xczxczxcz    时间: 2021-10-9 13:51

回复 50# WHY


    看你的VBS灰常工整,灰常适合教师类工作,偶测了下时间为 1分45秒。感觉把那个字典拿掉可能会提升一些速度。字典对效率影响还是很大的。个人愚见!
作者: newswan    时间: 2021-10-9 15:33

本帖最后由 newswan 于 2021-10-9 15:34 编辑

回复 59# xczxczxcz


&#128531;,搞错,是给 why 回复的。

没有禁用表情,怎么表情发不出
作者: newswan    时间: 2021-10-9 15:41

回复 50# WHY


可以加个计时功能,运行完成,显示用时
作者: WHY    时间: 2021-10-10 21:58

本帖最后由 WHY 于 2021-10-10 21:59 编辑

回复 59# xczxczxcz


    过奖,
感谢测试。
在我的电脑上,vbs 用时 3.5 分钟,PowerShell 脚本用时 2.1 分钟
作者: PCL0769    时间: 2021-10-12 14:46

谢谢各位老师出手帮助!
作者: PCL0769    时间: 2021-10-12 16:58

回复 36# newswan

老师好!
请帮忙看看这个能用批处理完成吗?谢谢!
http://www.bathome.net/thread-60353-1-1.html
作者: PCL0769    时间: 2021-10-12 16:59

回复 45# went
老师好!
请帮忙看看这个能用批处理完成吗?谢谢!
http://www.bathome.net/thread-60353-1-1.html
作者: PCL0769    时间: 2021-10-12 17:01     标题: RE: 请老师抽空帮写一个批处理,文本合并后生成在新文件夹中去重复(已解答,谢谢!)

回复 50# WHY

老师好!
请帮忙看看这个能用批处理完成吗?谢谢!
http://www.bathome.net/thread-60353-1-1.html
作者: PCL0769    时间: 2021-10-12 17:04

回复 47# idwma

老师好!
请帮忙看看这个能用批处理完成吗?谢谢!
http://www.bathome.net/thread-60353-1-1.html
作者: PCL0769    时间: 2021-10-12 17:05

回复 52# xczxczxcz

老师好!
请帮忙看看这个能用批处理完成吗?谢谢!
http://www.bathome.net/thread-60353-1-1.html




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