# Loop (文件和文件夹)

获取指定的文件或文件夹，一次一个。

Loop, FilePattern [, IncludeFolders?, Recurse?]

#### 参数

FilePattern | 单个文件或文件夹的名称，或一个通配符类型例如 C:\Temp\*.tmp 。如果未指定绝对路径将假设 FilePattern 在 %A_WorkingDir% 中。 星号和问号标记都被支持作为通配符。当文件类型出现在文件的长/普通名称或它的 8.3 短名称 中时都将获得匹配。 如果此参数是单个文件或文件夹 (即没有通配符) 并且 Recurse 设为 1 ，如果指定的文件名称出现在多个被搜索的文件夹中时，将找到多个匹配。
IncludeFolders? | 使用下面的数字，或留空而使用默认： 0 (默认) 不获取文件夹 (仅文件)。 1 获取所有匹配通配符类型的文件和文件夹。 2 只获取文件夹 (没有文件)。
Recurse? | 使用下面的数字，或留空而使用默认： 0 (默认) 子文件夹不被 recursed into(搜索)。 1 搜索子文件夹以便获取包含在其中匹配 FilePattern 的文件和文件夹。所有的子文件夹将被搜索，不仅仅是那些名称匹配 FilePattern 的。

#### 可用在 文件-Loop 里的特有变量

下面的变量存在于任何 文件-loop 中。如果一个内部的 文件-loop 封在一个外部的 文件-loop 中，最里面 loop 的文件将享有优先权：

A_LoopFileName | 当前取得的文件或文件夹名称 (不带路径)。
A_LoopFileExt | 文件的扩展名 (例如 TXT, DOC, 或 EXE)。不包括点号 (.) 。
A_LoopFileFullPath | 当前取得的文件/文件夹的完全路径和名称。不过，如果 FilePattern 包含了一个相对路径而不是一个绝对路径，那么这里的路径也将是相对的。此外，任何在 FilePattern 里短 (8.3) 名称的文件夹也仍是短的 (请看下一行来获取长版名称)。
A_LoopFileLongPath | 此变量在以下方面和 A_LoopFileFullPath 不同： 1) 它总是包含文件的绝对/完全路径，即使 FilePattern 包含的是一个相对路径； 2) 任何本身在 FilePattern 中是文件夹的短 (8.3) 名称的，将转换为它们的长名称； 3) 在 FilePattern 里的字符被转化为大写或小写，用来匹配存在文件系统里的大小写。将文件名称转换为它们被 Explorer(资源管理器) 显示的确切路径名称，这会很有用 -- 例如那些传递给一个脚本作为命令行的参数。
A_LoopFileShortPath | 当前取得的文件/文件夹的 8.3 短路径和名称。例如： C:\MYDOCU~1\ADDRES~1.txt 。不过，如果 FilePattern 包含一个相对路径而不是一个绝对路径，那么这里的路径也将是相对的。 要获取单个文件或文件夹完整的 8.3 路径和名称，像在这个例子中那样为 FilePattern 指定它的名称：
    Loop, C:\My Documents\Address List.txt
        ShortPathName = %A_LoopFileShortPath%
注意：如果文件没有短名称，此变量将为空，这会在那些注册表里设置了 NtfsDisable8dot3NameCreation(Ntfs禁用8点3名称创建) 的操作系统上发生。如果 FilePattern 包含一个相对路径并且 loop 内部使用 SetWorkingDir 从对 loop 自身起作用的工作目录切换出来，它也将为空。
A_LoopFileShortName | 8.3 短名称，或文件替换名称。如果文件没有此名称 (由于长名称比 8.3 格式更短或者大概因为短名称在一个 NTFS 文件系统上被禁止创建)， A_LoopFileName 将代替它被获得。
A_LoopFileDir | A_LoopFileName 所属目录的完全路径。不过，如果 FilePattern 包含一个相对路径而不是绝对路径，那么这里的路径也将是相对的。根目录不包含结尾反斜线。例如： C:
A_LoopFileTimeModified | 文件被最后修改的时间。格式 YYYYMMDDHH24MISS 。
A_LoopFileTimeCreated | 文件被创建的时间。格式 YYYYMMDDHH24MISS 。
A_LoopFileTimeAccessed | 文件被最后访问的时间。格式 YYYYMMDDHH24MISS 。
A_LoopFileAttrib | 当前获取的文件的 属性 。
A_LoopFileSize | 当前获取的文件的字节大小。同样支持大于 4 G 的文件。
A_LoopFileSizeKB | 当前获取的文件的千字节大小，四舍五入为整数。
A_LoopFileSizeMB | 当前获取的文件的兆字节大小，四舍五入为整数。

#### 注意

当你想要对收集的文件和/或文件夹一次一个进行操作时，文件-loop 是很有用的。

所有匹配的文件会被获取，包括隐藏文件。相比之下，操作系统的特性例如 DIR 命令默认省略隐藏文件。要避免处理隐藏、系统和/或只读文件，在 loop 里使用一些像下面这样的命令：

    if A_LoopFileAttrib contains H,R,S  ; 跳过任何具有 H (隐藏), R (只读), 或 S (系统)的文件。注意：在 "H,R,S" 之间无空格。
        continue  ; 跳过此文件并继续下一个。

要在一个递归搜索期间获得文件的相对路径而不是绝对路径，使用 SetWorkingDir 来改变在 loop 之前所基于的文件夹，并在之后的 Loop 里省略路径 (例如 Loop, *.*, 0, 1)。这将导致 A_LoopFileFullPath 包含的文件路径相对于它所基于文件夹。

如果一个 文件-loop 在它自己的范围内创建或重命名文件或文件夹，它会搅乱它自己。例如，如果它通过 FileMove 或其他方法重命名文件，每个这样的文件可能被找到两次：一次以它的旧名称，再一次以它的新名称。要绕弯解决这个问题，在创建一个文件的列表之后重命名它们。例如：

    FileList =
    Loop *.jpg
       FileList = %FileList%%A_LoopFileName%`n
    Loop, parse, FileList, `n
       FileMove, %A_LoopField%, renamed_%A_LoopField%

在一个 NTFS 文件系统上，文件可能总会以字母顺序来获取。在其他文件系统里，文件没有以特别的顺序来获取。要确保一个特别的顺序，以 Sort 命令示例部分下面显示的那样来使用。

文件和文件夹的完整路径名称长于 259 字符的部分将被略过，就像它们不存在一样。这样的文件相当罕见，因为通常操作系统不允许它们创建。

请看 Loop 关于 Blocks, Break, Continue, 和 A_Index 变量 (其存在于每种类型的 loop 中) 的信息。

#### 相关命令

Loop, Break, Continue, Blocks, SplitPath, FileSetAttrib, FileSetTime

#### 示例

    ; 例子 #1:
    Loop, %A_ProgramFiles%\*.txt, , 1  ; 在子文件夹中搜索。
    {
        MsgBox, 4, , 文件名称 = %A_LoopFileFullPath%`n`n继续?
        IfMsgBox, No
            break
    }

    ; 例子 #2: 计算一个文件夹的大小，包括它所有子文件夹里的文件：
    SetBatchLines, -1  ; 让操作以最快的速度运行。
    FolderSizeKB = 0
    FileSelectFolder, WhichFolder  ; 告诉用户去挑选一个文件夹。
    Loop, %WhichFolder%\*.*, , 1
        FolderSizeKB += %A_LoopFileSizeKB%
    MsgBox %WhichFolder% 的大小是 %FolderSizeKB% KB 。

    ; 例子 #3: 获得以名称来分类的文件名 (请看下一个例子来以日期分类):
    FileList =  ; 初始化为空。
    Loop, C:\*.*
        FileList = %FileList%%A_LoopFileName%`n
    Sort, FileList, R  ; R 选项以反方向分类。其他选项请看 Sort 命令页面。
    Loop, parse, FileList, `n
    {
        if A_LoopField =  ; 忽略在列表底部的空白。
            continue
        MsgBox, 4,, 文件编号 %A_Index% 是 %A_LoopField% 。继续？
        IfMsgBox, No
            break
    }

    ; 例子 #4: 获得以修改日期分类的文件名称:
    FileList =
    Loop, %A_MyDocuments%\Photos\*.*, 1
        FileList = %FileList%%A_LoopFileTimeModified%`t%A_LoopFileName%`n
    Sort, FileList  ; 以日期分类。
    Loop, parse, FileList, `n
    {
        if A_LoopField =  ; 省略在列表尾部的最后一个换行 (空项) 。
            continue
        StringSplit, FileItem, A_LoopField, %A_Tab%  ; 以 tab 符号分为两部分。
        MsgBox, 4,, 下一个文件 (修改于 %FileItem1%) 是：`n%FileItem2%`n`n继续？
        IfMsgBox, No
            break
    }

    ; 例子 #5: 仅复制比它们目标文件更新的源文件：
    CopyIfNewer:
    ; 调用方已为我们设置了变量 CopySourcePattern 和 CopyDest 。
    Loop, %CopySourcePattern%
    {
        copy_it = n
        IfNotExist, %CopyDest%\%A_LoopFileName%  ; 如果目标文件还未存在，将总去复制。
            copy_it = y
        else
        {
            FileGetTime, time, %CopyDest%\%A_LoopFileName%
            EnvSub, time, %A_LoopFileTimeModified%, seconds  ; 目标文件的时间减去源文件的时间。
            if time < 0  ; 源文件比目标文件更新。
                copy_it = y
        }
        if copy_it = y
        {
            FileCopy, %A_LoopFileFullPath%, %CopyDest%\%A_LoopFileName%, 1   ; 确定覆盖地复制
            if ErrorLevel
                MsgBox, 无法复制 "%A_LoopFileFullPath%" 到 "%CopyDest%\%A_LoopFileName%" 。
        }
    }
    Return

    ; 例子 #6: 像存在文件系统中那样把通过命令行参数传递进来的文件名称转变为长文件名、完整路径以及正确的大写/小写字符。
    Loop %0%  ; 将每个文件拖到脚本 (或以一个参数传递)。
    {
        GivenPath := %A_Index%  ; 获取下一命令行参数。
        Loop %GivenPath%, 1
            LongPath = %A_LoopFileLongPath%
        MsgBox 大小写正确的长路径文件名`n%GivenPath%`n是：`n%LongPath%
    }

翻译：天堂之门 menk33@163.com 2008年8月30日