Loop Read

检索文本文件中的行, 每次一行.

Loop Read InputFile , OutputFile

参数

InputFile

类型: 字符串

需要在循环中读取其内容的文本文件的名称, 如果未指定绝对路径, 则假定在 A_WorkingDir 中. 文件的行结束符可以是回车和换行符(`r`n), 也可以只是换行符(`n), 或只是回车(`r).

OutputFile

类型: 字符串

(可选的) 在循环期间保持打开的文件的名称, 如果未指定绝对路径, 则假定在 A_WorkingDir 中.

在循环的主体内, 使用 FileAppend 函数, 不带 Filename 参数(即省略它) 来追加到这个特殊的文件. 以这种方式追加到一个文件比使用 2 个参数模式的 FileAppend 执行地更好, 因为每次操作时不需要关闭文件和再重新打开. 如果需要的话, 记得在文本后加入换行符(`n) 或回车符和换行符(`r`n).

如果没有向文件写入任何内容, 文件就不会被打开. 如果循环执行零迭代或从未调用 FileAppend, 就会发生这种情况.

选项: 行末(EOL) 转换模式和输出文件编码取决于在 FileAppend 的首次调用中传递的选项(即省略 Filename 的首次调用). 随后的调用会忽略 Options 参数. 默认情况下不执行 EOL 转换; 也就是说, 除非存在 "`n" 选项, 否则换行符(`n) 将按原样写入.

标准输出(stdout): 指定 OutputFile 为星号(*) 可以把 FileAppend 写入的任何文本发送到标准输出(stdout). 这些文本可以重定向到文件, 指向另一个 EXE 的管道或被高级文本编辑器捕获, 然而发送到标准输出的文本不会出现在运行它的命令提示符中. 这可以通过以下方法解决 1) 使用 Ahk2Exe ConsoleApp 指令编译脚本, 或 2) 通过管道或重定向捕获脚本的输出. 有关详情, 请参阅 FileAppend.

备注

当您想对包含在文本文件中的内容逐行进行操作时, 文件读取循环很有用. 在整个操作过程中, 文件是打开的, 以避免每次都要重新扫描以找到下一行.

内置变量 A_LoopReadLine 存在于任何文件读取循环中. 它包含当前行的内容, 不包括回车和标志行结束的换行符(`r`n). 如果一个内部的文件读取循环被一个外部的文件读取循环所包围, 那么最内部循环的文件行将优先.

读取长度为 65,534 个字符的行. 如果行的长度超过了这个长度, 其剩余的字符将在下一个循环迭代时被读取.

StrSplit解析循环通常用于文件读取循环中, 以解析从 InputFile 中获取的每一行的内容. 例如, 如果 InputFile 的每一行都是一系列以 tab 分隔的字段, 那么这些字段可以像这个例子一样单独检索:

Loop read, "C:\Database Export.txt"
{
    Loop parse, A_LoopReadLine, A_Tab
    {
        MsgBox "Field number " A_Index " is " A_LoopField "."
    }
}

要加载整个文件内容到变量中, 请使用 FileRead, 因为它比循环执行的更好(尤其对于大文件).

要同时打开多个文件, 请使用 FileOpen.

可以选择使用 One True Brace(OTB) 样式, 它允许左大括号出现在同一行而不是下面. 例如: Loop Read InputFile, OutputFile {.

请参阅 Loop 了解关于区块, Break, Continue 和 A_Index 变量(其存在于各种类型的循环中) 的相关信息.

在不存在字节顺序标记时要控制如何解码文件, 请使用 FileEncoding.

循环的后面可以有一个可选的 Else 语句, 如果输入文件是空的或者找不到的话, 就会执行这个语句. 如果指定了 OutputFile, 上面描述的 FileAppend 的特殊模式也可以在 Else 语句的主体中使用. 如果没有 Else 语句, 如果找不到文件, 则抛出 OSError.

FileEncoding, FileOpen/File 对象, FileRead, FileAppend, Sort, Loop, Break, Continue, 区块, FileSetAttrib, FileSetTime

示例

只有首个文件中包含单词 FAMILY 的那些行才会写入第二个文件中. 取消注释首行可以覆盖而不是追加到任何现有的文件中.

;FileDelete "C:\Docs\Family Addresses.txt"

Loop read, "C:\Docs\Address List.txt", "C:\Docs\Family Addresses.txt"
{
    if InStr(A_LoopReadLine, "family")
        FileAppend(A_LoopReadLine "`n")
}
else
    MsgBox "Address List.txt was completely empty or not found."

获取文本文件的最后一行.

Loop read, "C:\Log File.txt"
    last_line := A_LoopReadLine  ; 当循环结束时, 这里会保持最后一行的内容.

尝试从文本或 HTML 文件中提取所有 FTP 和 HTTP URL.

SourceFile := FileSelect(3,, "Pick a text or HTML file to analyze.")
if SourceFile = ""
    return  ; 此时将退出.

SplitPath SourceFile,, &SourceFilePath,, &SourceFileNoExt
DestFile := SourceFilePath "\" SourceFileNoExt " Extracted Links.txt"

if FileExist(DestFile)
{
    Result := MsgBox("Overwrite the existing links file? Press No to append to it.`n`nFILE: " DestFile,, 4)
    if Result = "Yes"
        FileDelete DestFile
}

LinkCount := 0
Loop read, SourceFile, DestFile
{
    URLSearch(A_LoopReadLine)
}
MsgBox LinkCount ' links were found and written to "' DestFile '".'
return


URLSearch(URLSearchString)
{
    ; 由于在一些 URL(网址) 中内嵌有其他的 URL, 所以用这种特殊的方法进行处理:
    ; 找到最左边的起始位置:
    URLStart := 0  ; 设置起始默认值.
    for URLPrefix in ["https://", "http://", "ftp://", "www."]
    {
        ThisPos := InStr(URLSearchString, URLPrefix)
        if !ThisPos  ; 此前缀被取消资格.
            continue
        if !URLStart
            URLStart := ThisPos
        else ; URLStart 里面有一个有效的位置, 所以要和 ThisPos 比较一下.
        {
            if ThisPos && ThisPos < URLStart
                URLStart := ThisPos
        }
    }

    if !URLStart  ; 在 URLSearchString 中不存在 URL.
        return

    ; 否则, 提取该 URL:
    URL := SubStr(URLSearchString, URLStart)  ; 忽略开始/无效部分.
    Loop parse, URL, " `t<>"  ; 找到首个空格, tab 或尖括号(如果有).
    {
        URL := A_LoopField
        break  ; 即仅执行一次循环来获取首个 "片段".
    }
    ; 如果上面的循环因为没有找到结尾字符而导致迭代次数为零,
    ; 那么 URL 变量的内容保持不变.

    ; 如果 URL 以双引号结束, 那么移除它. 暂时使用 StringReplace, 不过注意
    ; 双引号似乎可以合法存在于 URL 中, 所以这样做
    ; 可能破坏它们:
    URLCleansed := StrReplace(URL, '"')
    FileAppend URLCleansed "`n"
    global LinkCount += 1

    ; 看看当前行中是否含有其他 URL:
    CharactersToOmit := StrLen(URL)
    CharactersToOmit += URLStart
    URLSearchString := SubStr(URLSearchString, CharactersToOmit)
    
    ; 到自身的递归调用:
    URLSearch(URLSearchString)
}