标题: [文件操作] [已解决]批处理怎样按指定大小分割txt文档? [打印本页]
作者: yylogo 时间: 2008-10-8 14:23 标题: [已解决]批处理怎样按指定大小分割txt文档?
家有txt小说若干,常有学生下载到mp4或手机内存卡,一般没有问题。但时间一长,发现有个别的mp4和手机无法打开较长的文档。解决的办法就是将长文件切成若干个小文件。于是乎,不断的复制一小段内容,新建一个txt文档,打开这个新建的文档,粘贴,关闭,保存:然后周而复始地重复这个过程。也许一个小时或几个小时还没完成一部小说的下载,极其麻烦。希望能有一个小程序能一点就解决。大致想法是这样的:输入小说的地址和文件名,回车后,立刻产生一个同名文件夹,文件夹内是按100k切分的若干txt,名字为文件夹名加1、2、3....等,最后的那个文件当然会小于100k。(特别要求,每个切分的txt文档必须以中文句号、英文句号或中英文问号结束,这样可以保证文档的大小不超过100k,并且相对完整的结束。)
谢谢各位回答者和看客。
作者: null 时间: 2008-10-8 14:54
想来想去,也没想出什么思路。。。
作者: Batcher 时间: 2008-10-8 16:06
C:\Test>split --help
Usage: split [OPTION] [INPUT [PREFIX]]
Output fixed-size pieces of INPUT to PREFIXaa, PREFIXab, ...; default
PREFIX is `x'. With no INPUT, or when INPUT is -, read standard input.
-b, --bytes=SIZE put SIZE bytes per output file
-C, --line-bytes=SIZE put at most SIZE bytes of lines per output file
-l, --lines=NUMBER put NUMBER lines per output file
-NUMBER same as -l NUMBER
--verbose print a diagnostic to standard error just
before each output file is opened
--help display this help and exit
--version output version information and exit
SIZE may have a multiplier suffix: b for 512, k for 1K, m for 1 Meg.
Report bugs to <[email]bug-textutils@gnu.org[/email]>.
split.exe
http://bbs.bathome.net/thread-1114-1-1.html
作者: pusofalse 时间: 2008-10-8 16:08
- @echo off
- set/p file=请把要处理的文件拖到此处:
- for /f "delims=" %%a in ("%file:"=%") do (
- md "%%~na"
- split -a 3 -b 100k "%file:"=%" "%%~na\%%~na_"
- ren "%%~na\*" "*.txt"
- )
- pause
复制代码
借助了第三方工具split.exe,用最合适的代码做最合适的事情吧。
请先下载3楼提供的下载链接,再运行此批处理。
作者: pusofalse 时间: 2008-10-8 17:04
三楼BATCHER兄提供的链接中的split.exe没有-a参数,版本问题。。。
使用以下代码:- @echo off
- set/p file=请把要处理的文件拖到此处:
- for /f "delims=" %%a in ("%file:"=%") do (
- md "%%~na"
- split -b 100k "%file:"=%" "%%~na\%%~na_"
- ren "%%~na\*" "*.txt"
- )
- pause
复制代码
作者: yylogo 时间: 2008-10-8 17:24
出效果了,pusofalse,辛苦你了。
虽然最后的效果还不是最满意的。
最满意的是题目要增加为***-1.txt,***_2.txt ........,并且每篇文档只要求不超过100k,结尾需要以中文句号、英文句号或中英文问号结束,以显文档的相对完整。期待更多的高手。。。
作者: 随风 时间: 2008-10-8 17:28
有了5楼代码的基础,要完美解决你的问题,就是很简单的事了,
暂时没空,等会给你代码。。。
作者: yylogo 时间: 2008-10-8 17:33
如果能不用第三方软件更好。
作者: 随风 时间: 2008-10-8 18:16
看来问题不是我想的那么简单。
split 不知道是如何控制文件大小的,我的a.txt内容全是时间这两个字,按说无法分割成 99k的文件才对啊?我分别测试分割成 99k 和 100k 发现文件每行的长度是一样的,只是行数不同,真奇怪?如果是通过控制回车的数量,那么行的长度应该不一样才对啊?
但如何楼主要求的是
“每篇文档只要求不超过100k,结尾需要以中文句号、英文句号或中英文问号结束,以显文档的相对完整”
倒不是没有解决办法,可以用split把文件分割成99k的文件,然后再在每个文件末尾追加一个半角句号就可以了。 不知道这样能否满足楼主要求?
至于文件名的问题则不是问题。。。
另外如果不用第三方软件来作的话,
首先文件内容中的特殊字符就是一个大问题,
其次效率将会是慢的惊人的。!!!
并且不能保证都是以100k来分割文件,只能保证不高与100k
所以建议还是用第三方软件好。
不知楼主意下如何?
作者: yylogo 时间: 2008-10-8 18:29
"每个文件末尾追加一个半角句号", 追加的句号不是自然的句号?那也不太好呀。
很难吗?用c语言可以解决这个问题吗?
作者: Batcher 时间: 2008-10-8 18:50 标题: 回复 10楼 的帖子
如果要实现你的想法,需要对文本的每个字符进行判断,不管用什么语言,速度都会慢的无法忍受。
作者: yylogo 时间: 2008-10-8 22:21
以下为儿子所写“分小说”软件的c代码,我一直在用“分小说”软件,还行,也就是还没有实现“以中文句号、英文句号或中英文问号结束”,所以求助。还有一点,是否有什么bug或者是否可以瘦身,或提高效率。请指教。
include "stdio.h"
main(){
FILE *fp,*in,*ot;
char name[40],jname[40],dosn[40],aa[40];
int a,j;
long i;
system("dir /b | find \"txt\" > ql.yylogo");
fp=fopen("ql.yylogo","rt");
while(!feof(fp)){
fscanf(fp,"%s",jname);
strcpy(name,jname);
j=strlen(name);
for(a=0;a<j;a++)
if(a>=j-4)
name[a]='\0';
in=fopen(jname,"rt");
strcpy(dosn,"md ");
strcat(dosn,name);
system(dosn);
a=1;
while(!feof(in)){
sprintf(aa,"%s\\%d.txt",name,a);
ot=fopen(aa,"wt");
for(i=1;i<=39999L;i++){
if(feof(in))
break;
fputc(fgetc(in),ot);
}
fclose(ot);
a++;
}
}
fclose(fp);
system("del ql.yylogo");
}
作者: 随风 时间: 2008-10-8 22:24
- @echo off&setlocal enabledelayedexpansion
- for /l %%a in (1 1 20) do set "bu=ZZZZZZZZZZ!bu!"
- set/p file=请把要处理的文件拖到此处:
- for /f "delims=" %%a in ("%file:"=%") do (
- if not exist "%%~na" md "%%~na"
- split -b 99k "%file:"=%" "%%~na\%%~na_"
- set "var=%%~na"
- )
- for /f "tokens=1* delims=_" %%a in ('dir/b/a-d "%var%"') do (
- echo 。>>"%var%\%%a_%%b"
- set "%%b=%%b!bu!"
- set "paixu.!%%b:~0,200!=%%b"
- )
- for /f "tokens=2 delims==" %%a in ('set paixu.') do (
- set /a n+=1
- ren "%var%\%var%_%%a" "%var%_!n!.txt"
- )
- start "" "%var%"
复制代码
[ 本帖最后由 随风 于 2008-10-9 17:48 编辑 ]
作者: yylogo 时间: 2008-10-8 22:44
13楼的代码测试不能通过,没有效果,提示:环境变量paixu,没有定义。
作者: 随风 时间: 2008-10-8 22:49
我测试可以啊???
作者: 随风 时间: 2008-10-8 22:55
你把要处理的文件和批处理放在同一个文件夹里试试
作者: yylogo 时间: 2008-10-8 23:13
问题出在这,程序不能自己建立一个与文件同名的文件夹,需要手动建立,再测试,就有效果了,而且有了标点符号做最后的结尾,看到了,不过是人为添加的标点符号。。。
谢谢了。
作者: terse 时间: 2008-10-9 02:03
也来一个
利用forstr /o 不知道forstr 能处理多大的文件
效率是问题 呵呵 凑个热闹- @echo off&setlocal enabledelayedexpansion
- set/a kb+=102400,x+=1
- set/p file=请把要处理的文件拖到此处:
- set file=%file:"=%
- call:lp "%file%"
- pause&exit
- :lp
- md "%~n1"
- for /f "tokens=1* delims=:" %%i in ('findstr /o ".*" "%file%"') do (
- if %%i gtr !kb! set /a kb+=102400,x+=1
- >>"%~n1\%~n1_!x!%~x1" echo.%%j
- )
复制代码
作者: yylogo 时间: 2008-10-9 09:36
18楼的,我不得不说
姚明啊,高,你实在是高。
没有第三方软件,你的程序在任何位置都可以运行出我想要的实际效果。
但为什么某些拆分的txt略大于100k呢,有101k的,有102k的,能解释一下吗?
[ 本帖最后由 yylogo 于 2008-10-9 09:46 编辑 ]
作者: terse 时间: 2008-10-9 10:55
原帖由 yylogo 于 2008-10-9 09:36 发表
18楼的,我不得不说
姚明啊,高,你实在是高。
没有第三方软件,你的程序在任何位置都可以运行出我想要的实际效果。
但为什么某些拆分的txt略大于100k呢,有101k的,有102k的,能解释一下吗?
你可以修改102400这个数来控制文件大小
作者: namejm 时间: 2008-10-9 12:10
楼主不是指定要用特定的符号结束吗?难道指定的结束符号只位于每一行的结尾处?还请说明文本格式,可能还可以写出更高效的代码。
作者: yylogo 时间: 2008-10-9 13:58 标题: 回复 21楼 的帖子
文本格式为txt的小说。切分小说我想最好以一个正规标点符号结束,可能会有e文小说,所以我说:“以中文句号、英文句号或中英文问号结束每一章”
我希望你说的“可能还可以写出更高效的代码。”
谢谢!
作者: namejm 时间: 2008-10-9 17:52
原以为你每一行只有一个句号呢,如果不止一个句号的话,还是非常麻烦的。
作者: yylogo 时间: 2008-10-9 21:17
尘土飞扬,你好像好没有完全理解我的意思。
也许我没有表达清楚,我再理一理:
我要将一篇较大的小说切分为若干个不大于100k的小章节,每个被切分的txt文档的最末尾要以一个句号结束。
作者: namejm 时间: 2008-10-9 21:50
如果需要只需要切分为100K左右的小章节倒还好办,但是,要保证每个文档的末尾要以一个句号结束,则就很有难度了,除非每行都是以句号结尾,否则,纯批处理的效率将十分低下。18楼的代码仅能实现小章节在100K左右,还不能保证能以句号结尾。
作者: pusofalse 时间: 2008-10-9 21:58
不知这样可否:
第一个文件的尾部(最后出现的一个全角句号或问号到全文结束)会出现在第二个文件的头部。即:这段文本信息即出现在第一个文件中(尾部),也出现在第二个文本中(头部)。不过借助了两个第三方工具split.exe wfr.exe- @echo off
- :loop
- setlocal enabledelayedexpansion
- set/p file=请把要处理的文件拖到此处:
- for /f "delims=" %%a in ("%file:"=%") do (
- md "%%~na"
- split -b 100k "%file:"=%" "%%~na\%%~na_"
- ren "%%~na\*" "*.txt"
- set "name=%%~na"
- )
- for /f "delims=" %%a in ('dir /b /s /on "%name%\*.txt"') do set/a n+=1&set "_!n!=%%a"
- set/a n-=1
- for /l %%i in (1 1 %n%) do (
- set/a x=%%i+1
- type "!_%%i!"|wfr /exp /r:"[\r\n]" /t|wfr /exp /r:".*[。?]" /t>"%name%\tmp.txt"
- (type "%name%\tmp.txt"&echo.&call,type "%%_!x!%%")>"%name%\tmp.tmp"
- call,move /y "%name%\tmp.tmp" "%%_!x!%%"
- )
- del "%name%\tmp.txt"
- endlocal
- pause
复制代码
wfr.exe下载:http://bbs.bathome.net/thread-1909-1-2.html
从第二个文件开始,大小会大于100k。
先下载split.exe wfr.exe 放到此批处理所在目录中OK。
[ 本帖最后由 pusofalse 于 2008-10-9 22:07 编辑 ]
作者: terse 时间: 2008-10-10 00:02
我的思路是 能否把原文本的标点都给定义了 然后判断最后一个字符是否标点
作者: yylogo 时间: 2008-10-10 00:34 标题: 再次测试
原帖由 namejm 于 2008-10-9 21:50 发表
如果需要只需要切分为100K左右的小章节倒还好办,但是,要保证每个文档的末尾要以一个句号结束,则就很有难度了,除非每行都是以句号结尾,否则,纯批处理的效率将十分低下。18楼的代码仅能实现小章节在100K左右 ...
再次测试一个2.22m的文件,发现18楼的不仅可以以一个标点符号结束,而且结束的地方恰好是原文章的一个段落的结束,比我想的还要好。标点符号包括句号、分号、引号和省略号。
尘土飞扬先生,你再仔细看看他的代码,并测试一个较大的txt文档,你会发现他的效果很好,2.22m的文件切分时间是35秒,txt文档再大也大不了多少了,我这里的txt小说最大的也不过5m左右。所以,我觉得18楼的最好,没有第三方软件,代码也简洁。
只有一点美中不足,有几个切分的txt为101k,超出题目要求,(但并不影响我的实际要求),他说“你可以修改102400这个数来控制文件大小”,可我不会,你能就18楼的代码完美一下吗?控制住切分的txt不超出100k。
作者: Batcher 时间: 2008-10-10 01:08 标题: 回复 28楼 的帖子
公司一台服务器用来存放日志的txt文档已经700MB了,还在每天增加......
作者: terse 时间: 2008-10-10 01:09
批处理的效率肯定不理想 代码也没你想那么好 只是你的文本每行字符都在范围内,也因每行的结束都是标点,那样的话又可避免切分好的文本最后缺少标点问题
另把102400改小一下试看如何 你可以改为102300 102200 102100 直到满意
作者: pusofalse 时间: 2008-10-10 02:02
去掉了wfr.exe 只用SPLIT.EXE。应该可以了。- @echo off
- :loop
- setlocal enabledelayedexpansion
- set/p file=请把要处理的文件拖到此处:
- for /f "delims=" %%a in ("%file:"=%") do (
- md "%%~na"
- split -b 99k "%file:"=%" "%%~na\%%~na_"
- ren "%%~na\*" "*.txt"
- set "name=%%~na"
- )
- for /f "delims=" %%a in ('dir /b /s /on "%name%\*.txt"') do set/a n+=1&set "_!n!=%%a"
- set/a n-=1
- for /l %%i in (1 1 %n%) do (
- set/a x=%%i+1
- findstr /v $ "!_%%i!">tmp&findstr $ "!_%%i!">tmp1
- move /y tmp1 "!_%%i!"
- (type tmp&echo.&call type "%%_!x!%%")>tmp2
- call,move /y tmp2 "%%_!x!%%"
- )
- del tmp
- endlocal
- pause
复制代码
作者: yylogo 时间: 2008-10-10 02:15 标题: 回复 29楼 的帖子
700m的txt的文件,o my god,我的双核cpu,2g内存,肯定是打不开的,100%肯定,那不成了屎壳螂,加那么大干吗?
话又说回来,真要看你说的这么大的txt,还真必须要使用我们在这探讨的切分问题(不知警察有没有)。所以,18楼的效率还真是个问题。(我使用就那么大-不超过10m,不存在问题)
我在12楼贴的c代码,切分2.22m的txt,不到1秒钟。不过,就是一刀切,每一篇40k,不大不小,不管结尾有没有标点符号。是不是说,在这个问题上,c比bat强呢。如果让那段c代码寻找结尾的标点符号,会不会也出现效率的问题呢?
不好意思,我只会问问题,不会写。
作者: yylogo 时间: 2008-10-10 02:53 标题: 回复 31楼 的帖子
测试了你31楼的代码,效果相当的完美,没有一个文件超过100k,所有的文件都是以段落结尾。而且,切分的效率非常高,2.23m的文档,不到2秒钟。
但在我查找文章前后连贯的时候,发现了一个致命的缺陷,我想,这是所有人都始料未及的,那就是从切分的第二个文件开始,每篇文章的第一二段出现了或多或少的乱码。
这个问题是不是第三方软件的bug造成的呢?你们试一试吧。我将一个2.23m的txt小说上传到了论坛2号群空间共享里面,标题是:切分代码试验文档.txt
第三方看样子靠不住,和第三者插足一样,不要太相信了,是不是可以解剖一下第三方软件的源代码呢。
作者: pusofalse 时间: 2008-10-10 03:17
也发现了如此的问题,应该是是split.exe的BUG。对此无能为力~
作者: Batcher 时间: 2008-10-10 05:12 标题: 回复 32楼 的帖子
日志文件,没办法。我们那台服务器有4个CPU,4G的内存,都无法用记事本打开(可以用第三方工具打开),你的电脑就更不行啦^_^
为啥那个C代码能准确保证每一篇40k呢?因为它在写文件的时候,是逐字写入的。为啥 terse 兄给你的BAT代码会小的误差呢,因为它在写文件的时候,是逐行写入的。
在这个问题上,C比BAT强吗?如果要考虑标点符号,就必须逐字判断,这时BAT要考虑特殊字符的问题,而C则没有这个顾忌,从这一点上来考虑C确实比BAT强。C是语言,BAT是脚本,其实不应该放在一起比较的。
既然那个C代码是逐字写入文件的,那么,如果你具备C基础,稍加修改即可实现要求。如果你具备BAT基础,再好好看看30楼的回复,就知道怎么实现"不大于100k"了。
还有,你把那个C代码中的39999改成100000,看看结果如何^_^
作者: 随风 时间: 2008-10-10 05:47
不用第三放软件还真是有点吃力。
初步测试成功
以中文句号结尾。
文件大小基本不大于100 k (可自行修改 set /a n=101600 数值的大小)
缺点:
1、效率低 样本文件 2.22m 耗时: 0 小时 1 分钟 3 秒 28 毫秒
2、文件内容不能含有特殊符号
如:英文的 " %^&<>()!& 大概就这几个,不一定全是,但肯定有。。。
为提高效率创建了一个临时文件 tmp.txt (完成后会自动删除)
:- @echo off
- set /a n=101600,kb=n
- set "临时文件=tmp.txt"
- set /p file=请把要处理的文件拖到此处:
- set "file=%file:"=%"
- cls&echo 正在分割 %file% 文件请稍候。。。
- for /f "delims=" %%a in ("%file%") do set wjm=%%~na
- findstr /no ".*" "%file%">"%临时文件%"
- for /f "tokens=2 delims=:" %%a in ('find /c /v "" "%临时文件%"') do set /a z=%%a
- if not exist "%wjm%\" md "%wjm%"
- :list
- set /a x+=1
- if defined t >>"%wjm%\%wjm%_%x%.txt" echo %t%
- set "t="
- if not defined h (set skip=) else (set skip=skip=%h%)
- setlocal enabledelayedexpansion
- for /f "%skip% tokens=1,2* delims=:" %%a in (%临时文件%) do (
- if %%b geq !kb! set /a kb+=n&set flag=a&goto loop
- set /a g+=1
- set !g!=%%c&set /a h=%%a,u=%%a
- )
- :loop
- if not defined flag (
- if defined t >>"%wjm%\%wjm%_%x%.txt" echo %t%
- for /l %%a in (1 1 !g!) do >>"%wjm%\%wjm%_%x%.txt" echo.!%%a!
- goto end
- )
- set "var=!%g%!"
- if not defined var set /a g-=1,h-=1&goto loop
- for /f "tokens=1* delims=。" %%a in ("!var!") do (
- if "!var!"=="%%a" set /a g-=1,h-=1&goto loop
- if not "%%b"=="" set "t=%%b"
- set w=%%a。
- )
- for /l %%a in (1 1 !g!) do >>"%wjm%\%wjm%_%x%.txt" echo.!%%a!
- >>"%wjm%\%wjm%_%x%.txt" echo !w!
- endlocal&set h=%h%&set t=%t%&set kb=%kb%&set "u=%u%"
- if %u% neq %z% goto list
- :end
- del/q "%临时文件%" 2>nul
- start "" "%wjm%"
复制代码
[ 本帖最后由 随风 于 2008-10-10 06:06 编辑 ]
作者: yylogo 时间: 2008-10-10 11:29
随风,你好!昨晚没有睡吧,06点06分还在修改帖子,辛苦了。
测试了你的代码,本机35秒左右,还可以,其他的要求也能达到,但我发现切分的第二个txt文档是101k,其他都是100k,最后的那一个除外。第二个txt文档是101k,这是怎么回事呢?纯代码讨论,其实也不影响我的使用。
不知大家烦不烦我,这个帖子费了很多朋友的时间和精力,还可能有其他的修正代码的出现,
希望此贴能开拓各位解决问题的思路和注意细节的习惯。
不知何时可以结贴,希望还晚一点,期待更多的优秀帖子出现。
[ 本帖最后由 yylogo 于 2008-10-10 11:33 编辑 ]
作者: Batcher 时间: 2008-10-10 11:59 标题: 回复 37楼 的帖子
希望此帖能开拓楼主自己动手的习惯
36楼写的很清楚“可自行修改 set /a n=101600 数值的大小”
作者: 随风 时间: 2008-10-10 14:07
Re 37楼
文件大小为100 k 应该是纯属巧合,(不过似乎也太巧了点)
第二个文件过大的原因是因为第一个文件的最后一行太长的缘故。
代码运行原理如下:
set /a n=101600
102400 为100k 这里特意取了一个偏小的植,目的是为了防止文件大于100 k (若文件还是太大,可将此
值再改小)
findstr /o 可以在文件的每行显示前面文件的字节数(既:大小)当此值大于101600 时,则开始准备分
割文件。
先判断此时的最后一行是否含有 句号,若没有则再判断上一行,直到发现句号为止。
再将此行第一个句号的前面部分作为这个文件的结尾,后面的部分作为下一个文件的开头。
若是此行太长的话,那么写入下一行开头的内容就会越多,所以就有可能导致下一个文件过大。
解决办法是减小 set /a n=101600 值,但这样会导致其他文件的会偏小。
不过 37 楼 Batcher 巡查 说的也没错,我在36楼以明确说明 (可自行修改 set /a n=101600 数值的大
小)你若仔细看了话,
应该自己先试一试,不要过于依赖别人现成的代码。
[ 本帖最后由 随风 于 2008-10-10 14:09 编辑 ]
作者: zqz0012005 时间: 2008-10-10 14:21 标题: 来个vbs吧
对于编码是ANSI的文本,一个英文字符占一个字节,一个汉字占两个字节,所以100K就是51200个汉字。最后得到的小文本一般小于100K,可自行调整- if WScript.Arguments.length=0 then msgbox "请把文本拖到脚本上" : wscript.quit
- Set fso = CreateObject("Scripting.FileSystemObject")
- set f = fso.GetFile(WScript.Arguments(0))
- set ts = f.OpenAsTextStream
- strText = ts.ReadAll
- fp = f.ParentFolder
- fn = left(f.Name,InStrRev(f.Name,".")-1)
- set f = nothing
- if not fso.FolderExists(fp&"\"&fn) then fso.CreateFolder fp&"\"&fn
-
- strtext=Replace(strtext, "。", "。///")
- strtext=Replace(strtext, "?", "?///")
- strtext=Replace(strtext, "!", "!///")
- strtext=Replace(strtext, ".", ".///")
- strtext=Replace(strtext, "!", "!///")
- strtext=Replace(strtext, "?", "?///")
- a=split(strtext,"///")
-
- i=0:j=0:k=1
-
- do while i<=UBound(a)
- j=j+len(a(i))
- if j<51200 then
- fso.OpenTextFile(fp&"\"&fn&"\"&fn&"-"&k&".txt",8,true).Write a(i)
- else
- j=0
- k=k+1
- fso.OpenTextFile(fp&"\"&fn&"\"&fn&"-"&k&".txt",8,true).Write a(i)
- end if
- i=i+1
- loop
复制代码
[ 本帖最后由 zqz0012005 于 2008-10-10 14:47 编辑 ]
作者: youxi01 时间: 2008-10-10 16:01
按照楼上这种切割方式是否合理呢?
按照人家文章本自然段落格式来切割是否更人性化?
作者: zqz0012005 时间: 2008-10-10 20:28
我想过按自然段落来切割,但考虑到不少txt小说根本就不分段,所以还是按标点切割
欢迎光临 批处理之家 (http://bathome.net./) |
Powered by Discuz! 7.2 |