file - 确定路径是否在 Go 中的另一个路径内

标签 file go path

我想删除一个文件的所有路径组件,直至(但不包括)整个基目录。

例子: /总体/basedir/a/b/c/文件

我想删除"file",然后删除“c”、“b”,如果可能的话再删除“a”(目录不为空)。我不想取消链接“basedir”或“overall”。

filepath.HasPrefix 似乎是一个不错的选择,但它显然已被弃用:https://golang.org/pkg/path/filepath/#HasPrefix

我现在拥有的是:

p := THEPATH

// attempt to remove file and all parent directories up to the basedir
// FIXME: HasPrefix is apparently bad.. a better idea?
for filepath.HasPrefix(p, baseDir) {
    err := os.Remove(p)
    if err != nil {
        break
    }
    // climb up one
    p = filepath.Dir(p)
}

寻找一种适用于所有支持 Go 的平台的简洁可靠的方法。

最佳答案

恕我直言,如果您想支持 golang 支持的所有平台,路径处理会相当复杂。 Bellow 是我迄今为止实现的解决方案(可能不是最简单的解决方案)。备注:

  1. 它支持通用操作而不仅仅是 os.Remove
  2. 代替基于字符串的路径比较,函数os.SameFile用于测试两个文件/目录是否相等。
  3. 在实现中,首先访问所有候选路径并将其添加到visitedPaths slice 中。然后,如果没有错误发生,则对每个候选路径执行一个action

The code :

package pathwalker

import (
    "os"
    "path/filepath"
    "strings"
)

type PathAction func(PathInfo) error
type PathInfo struct {
    FileInfo os.FileInfo
    FullPath string
}
type PathWalker struct {
    pathName     string
    basePath     string
    visitedPaths []PathInfo
    lastFi       os.FileInfo
}

//NewPathWalker creates PathWalker instance
func NewPathWalker(pathName, basePath string) *PathWalker {
    return &PathWalker{
        pathName: pathName,
        basePath: basePath,
    }
}

func (w *PathWalker) visit() (bool, error) {
    //Make sure path ends with separator
    basePath := filepath.Clean(w.basePath + string(filepath.Separator))
    baseInfo, err := os.Lstat(basePath)
    if err != nil {
        return false, err
    }

    //clean path name
    fi, err := os.Lstat(w.pathName)
    if err != nil {
        return false, err
    } else if fi.IsDir() {
        //When pathname is a directory, remove latest separator
        sep := string(filepath.Separator)
        cleanPath := filepath.Clean(w.pathName + sep)
        w.pathName = strings.TrimRight(cleanPath, sep)
    } else {
        w.pathName = filepath.Clean(w.pathName)
    }
    return w.doVisit(w.pathName, baseInfo)
}

//visit path recursively
func (w *PathWalker) doVisit(pathName string, baseInfo os.FileInfo) (bool, error) {
    //Get file info
    fi, err := os.Lstat(pathName)
    if err != nil {
        return false, err
    }

    //Stop when basePath equal to pathName
    if os.SameFile(fi, baseInfo) {
        return true, nil
    }

    //Top directory reached, but does not match baseInfo
    if w.lastFi != nil && os.SameFile(w.lastFi, fi) {
        return false, nil
    }
    w.lastFi = fi

    //Append to visited path list
    w.visitedPaths = append(w.visitedPaths, PathInfo{fi, pathName})

    //Move to upper path
    up := filepath.Dir(pathName)
    if up == "." {
        return false, nil
    }

    //Visit upper directory
    return w.doVisit(up, baseInfo)
}

//Walk perform action then return number of proceed paths and error
func (w *PathWalker) Walk(act PathAction) (int, error) {
    n := 0
    ok, err := w.visit()
    if err != nil {
        return 0, err
    } else if ok && act != nil {
        for _, pi := range w.visitedPaths {
            err := act(pi)
            if err != nil {
                return n, err
            }
            n++
        }
    }
    return n, nil
}

//VisitedPaths return list of visited paths
func (w *PathWalker) VisitedPaths() []PathInfo {
    return w.visitedPaths
}

然后如果你想删除basePath下的文件和父目录,你可以这样做:

func remove(pathName, basePath string) {
    act := func(p pathwalker.PathInfo) error {
        if p.FileInfo.IsDir() {
            fmt.Printf("  Removing directory=%s\n", p.FullPath)
            return os.Remove(p.FullPath)
        }

        fmt.Printf("  Removing file=%s\n", p.FullPath)
        return os.Remove(p.FullPath)
    }

    pw := pathwalker.NewPathWalker(pathName, basePath)
    n, err := pw.Walk(act)
    fmt.Printf("Removed: %d/%d, err=%v\n", n, len(pw.VisitedPaths()), err)
}

如果你只是想测试一个路径是否在另一个路径内,你可以这样做:

n, err := pathwalker.NewPathWalker(fileName, basePath).Walk(nil)
if n > 0 && err != nil {
    //is inside another path
}

关于file - 确定路径是否在 Go 中的另一个路径内,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44407006/

相关文章:

postgresql - 在 postgreSQL 中使用主键

go - 我可以获得指向 golang 中映射值的指针吗?

Php - 获取 php 脚本后的路径

swift - 我怎样才能制作像数字 8 这样的路径(SpriteKit,Swift)

Windows 中的 Python 配置 - 模块位置 - pip 与 Eclipse/Liclipse

file - 在 Windows 7 中根据 LastWriteTime(上次修改时间)比较文件夹内容

java - 替换文本后如何保持文档文件内容相同的格式

javascript - 使用javascript读取服务器文件

go - 如何从 Telnet session 读取数据

python - 在python中复制文件名中包含特定字符串的文件