确定路径是否在GO中的另一个路径内



我想删除文件的所有路径组件,直到(但不包括(整体基本目录。

示例:/总体/基础/a/b/c/file

我想删除"文件",然后删除" c"," b",然后删除"如果可能的话(目录不为空(。我做不是想要取消链接"基于"或"总体"。

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支持平台上使用的简洁可靠的方式。

IMHO,如果您要支持golang支持的所有平台,则路径处理相当复杂。Bellow是我迄今为止实施的解决方案(可能不是最简单的解决方案(。注意:

  1. 它支持广义动作,而不是os.Remove
  2. 而不是基于字符串的路径比较,而是使用功能os.SameFile来测试两个文件/目录是否相等。
  3. 在实施中,首先访问了所有候选路径,并将其添加到visitedPaths切片中。然后,如果没有发生错误,则对每个候选路径执行action

代码:

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=%sn", p.FullPath)
            return os.Remove(p.FullPath)
        }
        fmt.Printf("  Removing file=%sn", p.FullPath)
        return os.Remove(p.FullPath)
    }
    pw := pathwalker.NewPathWalker(pathName, basePath)
    n, err := pw.Walk(act)
    fmt.Printf("Removed: %d/%d, err=%vn", n, len(pw.VisitedPaths()), err)
}

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

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

相关内容

  • 没有找到相关文章

最新更新