我使用以下代码使用批处理文件将a
写入hi.txt
5次。
问题是它会自动将换行添加到最后。
输出:
a
a
a
a
a
我想:
aaaaa
答案 0 :(得分:1)
@echo off
break|set /p=a>file
break|set /p=a>>file
break|set /p=a>>file
break|set /p=a>>file
type file
试试这个......
答案 1 :(得分:1)
<nul set /p"=string"
这是通常的批处理构造,用于输出不带结束CR / LF的字符串。
如果您需要&#34;立即&#34;为文件生成10000 a
个字符,您可以使用类似
@echo off
setlocal enableextensions disabledelayedexpansion
<nul >"file.txt" (for /l %%a in (1 1 625) do @set /p"=aaaaaaaaaaaaaaaa" )
即16 a * 625 iterations = 10000 a
答案 2 :(得分:1)
下面的方法可能是创建具有给定数量的相同字符的文件的最快方法。如果该数字仅为10,000,则立即创建该文件。
@echo off
setlocal EnableDelayedExpansion
set times=10000
rem Create the initial file with one "a"
set /P "=a" < NUL > bitNumberOfChars.txt
rem Identify individual bits in the number of times
rem and append the same number of "a"'s to output file
rem Test 31 bits, from 0 to 30
(for /L %%i in (0,1,30) do if !times! neq 0 (
set /A "bit=times & (1<<%%i), times-=bit"
if !bit! neq 0 type bitNumberOfChars.txt
type bitNumberOfChars.txt >> bitNumberOfChars.txt
)) > output.txt
del bitNumberOfChars.txt
编辑:已添加优化方法
正如用户dbenham在评论中指出的那样,此方法未优化,因为它使用辅助磁盘文件。下面的新版本是一个优化的版本,不会将数据存储在文件中,而是存储在变量中dbenham建议的内存变量中。该过程与第一种方法相同:在每一步中,字符串长度加倍,并测试给定数字的一位;如果该位不为零,则输出当前字符串。
@echo off
setlocal EnableDelayedExpansion
for /F "delims==" %%a in ('set') do set "%%a="
set times=%1
rem Create the initial string with one "a"
set "s=a"
rem Identify individual bits in the number of times
rem and append the same number of "a"'s to output file
< NUL (
rem Test the first 12 bits, from 0 to 11 (string up to 4 KB)
for /L %%i in (0,1,11) do (
set /A "bit=times & (1<<%%i), times-=bit"
if !bit! neq 0 set /P "=!s!"
if !times! equ 0 goto break
set "s=!s!!s!"
)
rem Test the bit 12 (string of 8 KB - 8)
set /A "bit=times & (1<<12), times-=bit"
if !bit! neq 0 set /P "=!s!"
if !times! equ 0 goto break
set "s=!s:~4!"
set "s=!s!!s!"
rem Test the rest of bits, from 13 to 30 (repeating string of 8 KB)
set t2=1, t3=0
for /L %%i in (13,1,30) do if !times! neq 0 (
set /A "bit=times & (1<<%%i), times-=bit"
if !bit! neq 0 (
for /L %%t in (1,1,!t2!) do set /P "=!s!"
set /A "t3+=t2*8"
)
set /A "t2<<=1"
)
rem Add missing bytes (8 bytes per each 8 KB string)
set /A div=t3/8184, mod=t3%%8184
for /L %%t in (1,1,!div!) do set /P "=!s!"
for %%t in (!mod!) do set /P "=!s:~0,%%t!"
) > output.txt
:break
这种方法与dbenham的方法几乎具有相同的性能;但是,因为此方法使用稍大的最大字符串(8184与8000字符),所以对于具有特定大小的非常大的文件,它会稍微快一些。完成多次测试并获得平均时间后,使用10,000,000个字符的文件,此方法的运行速度提高约1.5%,使用66,000,000个字符的文件,运行速度提高3.5%。
答案 3 :(得分:0)
除非您使用的是高性能固态硬盘,否则性能可能会受到磁盘写入速度的限制。 Aacini解决方案没有经过优化,因为它不仅将所需的字符串写入磁盘,而且还将至少写入临时文件,因此IO成本大约翻了一倍。
优化的解决方案应该在总长度和写入操作数量方面最小化磁盘写入操作。
用于在没有回车符或换行符(\ r \ n)的情况下写入数据的SET / P hack相对较慢。在我的计算机上,ECHO
比<NUL SET /P
快约2倍。所以我们也希望最小化SET / P的执行次数。
通过变量操作内存中的字符串相对较快。
我的优化解决方案准备一个具有近乎最大长度的变量(最大可能为8191的8000)。写入整个大字符串足以接近所需长度,然后使用子字符串操作来获取余数。
我写了两个优化的例程来协助完成任务。
:MakeString8k
将任何字符串复制到8000字节的长度,全部都在内存中,覆盖原始变量。一旦定义,这个8k字符串就可以用于多次写操作。
:WriteBigString
使用SET / P在循环中多次写入一个字符串,加上一个子字符串,以达到所需的长度。输出将写入stdout,因此可以将CALL重定向到所需的输出文件。这通常会以:MakeString8k
的输出作为输入字符串调用,并且已知输入长度为8000.如果未传递输入字符串的长度,则使用:strlen
函数计算长度。
我已经包含了演示代码,演示了如何向test.txt写入“a”10000次。但是很容易将参数更改为几乎任何给定长度的字符串。
@echo off
setlocal enableDelayedExpansion
set "str=a"
call :makeString8k str
call :writeBigString 10000 str 8000 >>test.txt
exit /b
:MakeString8k StrVar
::
:: Replicate the string within variable StrVar to length 8000.
:: The pattern will be discontinuous at the midway point if 8000
:: is not an even multiple of the original string length.
::
:: If delayed expansion is enabled when called, then the initial
:: string can contain any valid byte code except 0x00. If delayed
:: expansion is disabled when called, then the string cannot contain
:: carriage return (0x0D) or linefeed (0x0A).
::
if "!!" neq "" (
setlocal enableDelayedExpansion
set make8k.setlocal=1
)
for /l %%N in (1 1 13) do set "%~1=!%~1:~0,4000!!%~1:~0,4000!"
if defined make8k.setlocal for /f delims^=^ eol^= %%A in ("!%~1!") do (
endlocal
set "%~1=%%A"
)
exit /b
:WriteBigString Len SeedVar [SeedLen]
::
:: Repeatedly write to stdout the string in seedVar until length Len
:: is reached. Performance is improved slightly if the length of SeedVar
:: is also passed as SeedLen.
::
:: This function may not work properly if the string begins with =, ",
:: or white space.
::
setlocal enableDelayedExpansion
set "seedLen=%~3"
if not defined seedLen call :strlen %2 seedLen
set /a "wholeCnt=%~1/seedLen, subLen=%~1%%seedLen"
<nul (for /l %%N in (1 1 %wholeCnt%) do set /p "=!%~2!")
for %%N in (%subLen%) do <nul set /p "=!%~2:~0,%%N!"
exit /b
:strlen StrVar RtnVar
::
:: Compute the length of the string within StrVar and return
:: the result in variable RtnVar, or write the result to stdout
:: if RtnVar is not specified.
::
setlocal EnableDelayedExpansion
set "s=!%~1!#"
set "len=0"
for %%P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
if "!s:~%%P,1!" NEQ "" (
set /a "len+=%%P"
set "s=!s:~%%P!"
)
)
(
endlocal
if "%~2" neq "" (set "%~2=%len%") else echo %len%
)
exit /b
注意:There are limitations to the SET /P hack - 如果字符串以=
,"
或空格,制表符或新行等空格字符开头,则可能无法正常工作。确切的限制取决于您使用的Windows版本。
您可以使用https://stackoverflow.com/a/19468559/1012053发布的技术来调整此解决方案,以支持编写除null(0x00)字符以外的任何字符串。
我已经测试了我的解决方案与Aacini的解决方案,这大约快了2倍。两个解决方案都在眨眼间写入10,000个字节。但是大文件的区别变得明显。它需要Aacini的代码〜13秒才能在我的机器上写入1亿个字节,而我的代码只需要约6秒。