Loop (读取文件内容)


逐行读取一个文本文件的内容 (比 FileReadLine 执行地更好)。

Loop, Read, InputFile [, OutputFile]

参数

Read 此参数必须是单词 READ。
InputFile 文本文件的名称,它的内容将被 loop 读取,如果未指定绝对路径,则假设位于 %A_WorkingDir%。支持 Windows 和 Unix 格式的文件;就是说,文件行可以是回车加换行符 (`r`n) 结尾或者只用换行符 (`n) 结尾。
OutputFile

(可选) 输出文件的名称,它在循环过程中会保持打开状态,如果未指定绝对路径,则假设位于 %A_WorkingDir%

在循环体内,请用只带一个参数(要写入的文本)的 FileAppend 命令来将文本追加到此文件。以这种方式追加到一个文件比使用 2 个参数模式的 FileAppend 执行地更好,因为每次操作不需要关闭文件再重新打开。如果需要,记得在写入内容后跟一个换行符 (`n)。

如果没有写入操作,该文件不会被打开。例如循环次数是零,或者没有使用 FileAppend 命令。

二进制模式:要以二进制模式而不是文本模式追加的话,在文件名前加一个星号。这会使每个换行符 (`n) 作为一个单独的换行 (LF) 写入,而不是 Windows 标准的回车加换行 (CR+LF)。例如:*C:\My Unix File.txt 。即使不用星号,如果循环第一次使用 FileAppend 命令的时候写入了任何成对的回车和换行符 (`r`n),二进制模式也会自动生效。

标准输出 (stdout):给 OutputFile 指定一个星号 (*) 可以将任何由 FileAppend 写入的文本发送到标准输出 (stdout)。这样的文本可以重定向到一个文件、传送到另一个 EXE 程序或被高级的文本编辑器获取。不过,以标准形式输出的文本并不会在执行它的命令提示符中出现。详见 FileAppend

逗号转义:和其它大多数命令的最后一个参数不同,在 OutputFile 参数中,逗号必须进行转义 (`,)。

注意

当你想对一个文本文件中的内容逐行进行操作的时候,文件读取循环十分有用。它比使用 FileReadLine 执行地更好,因为:1) 文件在整个操作过程中可以保持打开状态;2) 不必每次都重新扫描文件来查找请求的行数。

内置变量 A_LoopReadLine 存在于任何文件读取循环中。它包含了当前行的内容,行尾的回车和换行符(`r`n)标记除外。如果一个内层文件读取循环被装在一个外层文件读取循环中,则最里层循环的文件行将享有优先。

每行最多可以读取 65,534 个字符。如果某行的长度有超出,那它剩余的字符将在下次循环中被读取。

在文件读取循环中,经常使用 StringSplit 或者字符串解析循环来解析从 InputFile 中读取的每一行内容。例如,如果 InputFile 中的每一行内容都是由 tab 分隔的一系列片段,那么这些片段可以用下面这段示例逐个读取:

Loop, read, C:\Database Export.txt
{
    Loop, parse, A_LoopReadLine, %A_Tab%
    {
        MsgBox, 第 %A_Index% 个片段是 %A_LoopField%。
    }
}

要将整个文件内容读取到一个变量中的话,请用 FileRead,因为它比一个循环执行地好得多 (特别是读取大文件的时候)。

要同时打开多个文件,请用 DllCall(),参考这个例子

请看 Loop 命令获取 Blocks, Break, Continue 以及内置变量 A_Index (存在于任何类型的循环中) 的相关信息。

相关命令

FileRead, FileReadLine, FileAppend, Sort, Loop, Break, Continue, Blocks, FileSetAttrib, FileSetTime

示例

;示例 1: 第一个文件中,只有含有单词 FAMILY 的行会被写入第二个文件。
;取消第一行的注释的话,将会覆盖现有的文件,而不是将内容追加到现有的文件中。
;FileDelete, C:\Docs\Family Addresses.txt

Loop, read, C:\Docs\Address List.txt, C:\Docs\Family Addresses.txt
{
    IfInString, A_LoopReadLine, family, FileAppend, %A_LoopReadLine%`n
}

 

;示例 2: 读取一个文本文件的最后一行。
Loop, read, C:\Log File.txt
    last_line := A_LoopReadLine  ;当循环结束时,这个变量将会保存最后一行的内容。

 

;示例 3: 从一个文本文件或者 HTML 文件中提取所有的 FTP 和 HTTP URL。
FileSelectFile, SourceFile, 3,, 选择一个文本文件或者 HTML 文件来分析。
if SourceFile =
    return  ;未选择文件则退出。

SplitPath, SourceFile,, SourceFilePath,, SourceFileNoExt
DestFile = %SourceFilePath%\%SourceFileNoExt% Extracted Links.txt

IfExist, %DestFile%
{
    MsgBox, 4,, 覆盖已存在的链接文件?按否则是追加。`n`n文件:%DestFile%
    IfMsgBox, Yes
        FileDelete, %DestFile%
}

LinkCount = 0
Loop, read, %SourceFile%, %DestFile%
{
    URLSearchString = %A_LoopReadLine%
    Gosub, URLSearch
}
MsgBox 查找到 %LinkCount% 个链接,已写入 "%DestFile%"。
return


URLSearch:
;下面这么写是因为一些 URL 中嵌入了其它的 URL:
StringGetPos, URLStart1, URLSearchString, http://
StringGetPos, URLStart2, URLSearchString, ftp://
StringGetPos, URLStart3, URLSearchString, www.

;找到最左边的开始位置:
URLStart = %URLStart1%  ;设置默认的开始位置。
Loop
{
    ;通过只解析 "URLStart%A_Index%" 一次来提高效率 (至少在一个含有许多变量的脚本中能提高):
    ArrayElement := URLStart%A_Index%
    if ArrayElement =  ;抵达数组的末尾。
        break
    if ArrayElement = -1  ;取消这个元素。
        continue
    if URLStart = -1
        URLStart = %ArrayElement%
    else ; URLStart 中包含有效的起始位置,所以和 ArrayElement 比较。
    {
        if ArrayElement <> -1
            if ArrayElement < %URLStart%
                URLStart = %ArrayElement%
    }
}

if URLStart = -1  ; URLSearchString 中没有 URL。
    return

;否则,提取这个 URL:
StringTrimLeft, URL, URLSearchString, %URLStart%  ;省略开始部分/不相关的内容。
Loop, parse, URL, %A_Tab%%A_Space%<>  ;查找第一个空格,Tab,或者尖括号 (如果有的话)。
{
    URL = %A_LoopField%
    break  ;即只循环一次来获取首个“片段”。
}
;如果没有进入上面的循环,表示没找到结束符,将不处理 URL 变量的内容。

;如果 URL 以双引号结尾,移除它。目前使用了 StringReplace,
;但是要注意,由于双引号也可以出现在 URL 中,所以这个操作可能会破坏它们:
StringReplace, URLCleansed, URL, ",, All
FileAppend, %URLCleansed%`n
LinkCount += 1

;检查这一行中是否还有其它 URL:
StringLen, CharactersToOmit, URL
CharactersToOmit += %URLStart%
StringTrimLeft, URLSearchString, URLSearchString, %CharactersToOmit%
Gosub, URLSearch  ;循环调用自身。
return

翻译:okey3m   修正:天堂之门 menk33@163.com 2009年1月7日