Golang遍历目录并删除文件或目录的方法

Golang遍历目录并删除文件或目录的方法 我将大量文件复制到了一个已存在的目录中,现在需要撤销此操作。目标目录中包含许多其他文件,这些文件需要保留,因此无法简单地删除目录中的所有文件。我使用Python成功完成了此操作。以下是脚本:

import os, sys, shutil

source = "/tmp/test/source" 
target = "/tmp/test/target" 


for root, dirs, files in os.walk(source): # for files and directories in source
    for dir in dirs:
        if dir.startswith("."):
            print(f"Removing Hidden Directory: {dir}")
        else: 
            print(f"Removing Directory: {dir}")
        try:
            shutil.rmtree(f"{target}/{dir}") # remove directories and sub-directories
        except FileNotFoundError:
            pass

    for file in files:
        if file.startswith("."): # if filename starts with a dot, it's a hidden file
            print(f"Removing Hidden File: {file}")
        else:
            print(f"Removing File: {file}")
        try:
            os.remove(f"{target}/{file}") # remove files        
        except FileNotFoundError:
            pass

print("Done")

上述脚本会检查原始(源)目录并列出其中的文件。然后,它会检查您复制文件的目标目录,并仅删除源目录中存在的已列出文件。

如何在Golang中实现相同的功能?我尝试使用filepath.WalkDir(),但文档中说明:

WalkDir walks the file tree rooted at root, calling fn for each file or directory in the tree, including root.

如果WalkDir()包含根目录,那么os.Remove或os.RemoveAll将会删除整个目录。


更多关于Golang遍历目录并删除文件或目录的方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

找到了答案。使用 os.ReadDir 读取源目录条目。对于每个条目,使用 os.RemoveAll 删除对应的目标文件。

func main() {
    fmt.Println("hello world")
}

更多关于Golang遍历目录并删除文件或目录的方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Golang中实现类似功能,可以使用filepath.WalkDir()遍历源目录,然后删除目标目录中对应的文件和目录。关键是要正确处理相对路径,避免删除整个目标目录。

以下是实现代码:

package main

import (
    "fmt"
    "io/fs"
    "os"
    "path/filepath"
    "strings"
)

func main() {
    source := "/tmp/test/source"
    target := "/tmp/test/target"

    err := filepath.WalkDir(source, func(path string, d fs.DirEntry, err error) error {
        if err != nil {
            return err
        }

        // 获取相对于源目录的相对路径
        relPath, err := filepath.Rel(source, path)
        if err != nil {
            return err
        }

        // 跳过源目录本身
        if relPath == "." {
            return nil
        }

        // 构建目标路径
        targetPath := filepath.Join(target, relPath)

        if d.IsDir() {
            // 处理目录
            if strings.HasPrefix(d.Name(), ".") {
                fmt.Printf("Removing Hidden Directory: %s\n", d.Name())
            } else {
                fmt.Printf("Removing Directory: %s\n", d.Name())
            }
            
            // 删除目录及其内容
            if err := os.RemoveAll(targetPath); err != nil && !os.IsNotExist(err) {
                return err
            }
        } else {
            // 处理文件
            if strings.HasPrefix(d.Name(), ".") {
                fmt.Printf("Removing Hidden File: %s\n", d.Name())
            } else {
                fmt.Printf("Removing File: %s\n", d.Name())
            }
            
            // 删除文件
            if err := os.Remove(targetPath); err != nil && !os.IsNotExist(err) {
                return err
            }
        }

        return nil
    })

    if err != nil {
        fmt.Printf("Error: %v\n", err)
        return
    }

    fmt.Println("Done")
}

对于更精确的控制,可以使用以下版本,它先收集所有需要删除的路径,然后按深度逆序删除(先删除最深层的文件/目录):

package main

import (
    "fmt"
    "io/fs"
    "os"
    "path/filepath"
    "sort"
    "strings"
)

func main() {
    source := "/tmp/test/source"
    target := "/tmp/test/target"

    var paths []string
    
    // 第一步:收集所有需要删除的路径
    err := filepath.WalkDir(source, func(path string, d fs.DirEntry, err error) error {
        if err != nil {
            return err
        }

        relPath, err := filepath.Rel(source, path)
        if err != nil {
            return err
        }

        if relPath == "." {
            return nil
        }

        targetPath := filepath.Join(target, relPath)
        paths = append(paths, targetPath)
        
        return nil
    })

    if err != nil {
        fmt.Printf("Error collecting paths: %v\n", err)
        return
    }

    // 第二步:按路径深度逆序排序(先删除最深层的)
    sort.Slice(paths, func(i, j int) bool {
        return len(strings.Split(paths[i], string(os.PathSeparator))) > 
               len(strings.Split(paths[j], string(os.PathSeparator)))
    })

    // 第三步:删除所有收集的路径
    for _, path := range paths {
        if info, err := os.Stat(path); err == nil {
            if info.IsDir() {
                if strings.HasPrefix(filepath.Base(path), ".") {
                    fmt.Printf("Removing Hidden Directory: %s\n", filepath.Base(path))
                } else {
                    fmt.Printf("Removing Directory: %s\n", filepath.Base(path))
                }
                if err := os.RemoveAll(path); err != nil && !os.IsNotExist(err) {
                    fmt.Printf("Error removing directory %s: %v\n", path, err)
                }
            } else {
                if strings.HasPrefix(filepath.Base(path), ".") {
                    fmt.Printf("Removing Hidden File: %s\n", filepath.Base(path))
                } else {
                    fmt.Printf("Removing File: %s\n", filepath.Base(path))
                }
                if err := os.Remove(path); err != nil && !os.IsNotExist(err) {
                    fmt.Printf("Error removing file %s: %v\n", path, err)
                }
            }
        }
    }

    fmt.Println("Done")
}

这两个实现都只删除源目录中存在的文件和目录,不会影响目标目录中的其他文件。使用filepath.Rel()获取相对路径是关键,这样可以正确构建目标路径而不包含源目录本身。

回到顶部