更改文件名路径目录

Change filename path directory

我需要更改相对于给定文件夹的文件名路径。
我正在处理多用户共享存储桶,如果用户不知道完整的文件路径就好了。

下面有一个例子,但看起来有点脏。

package main

import (
    "fmt"
    "strings"
)

func main() {
    secretUrl := "allusers/user/home/path/to/file"
    separator := "home/"

    newUrl := strings.Split(secretUrl, separator)

    newUserUrl := separator + newUrl[len(newUrl)-1]
    fmt.Printf("%q\n", newUserUrl)

}

另外,新路径需要从分离点开始

还有其他更优雅的方法吗?示例将不胜感激。

经验法则是不要将文件路径作为字符串进行操作。边缘案例太多了。 Go 有 path and filepath 库来操作路径。

但也有例外。 Go 的 pathfilepath 库的功能有限,比如它缺少一种将路径拆分为数组或检查一个文件路径是否是另一个文件路径的子路径的方法。有时使用字符串函数效率更高。您可以通过首先调用 filepath.Clean 对它们进行规范化来避免很多问题。

如果前缀始终是 allusers/user/home 那么您可以将路径分割成片,在清理它们之后,并将它们作为数组进行比较。

// Clean will take care of // and trailing /
secret := filepath.Clean("allusers//user/home//path/to/file")
base   := filepath.Clean("allusers/user/home/")

// Clean has made splitting on / safe.
secret_parts := strings.Split(secret, "/")
base_parts   := strings.Split(base, "/")

现在我们有两个数组来比较所有的片段。首先,检查以确保 base_parts 确实是 secret_parts 的前缀,而 reflect.DeepEqual 仅在 secret_parts 的前几个元素上。与 base_parts.

中的数字相同
func sliceHasPrefix( s, prefix []string  ) bool {
    if len(s) < len(prefix) {
        return false
    }

    return reflect.DeepEqual(prefix, s[0:len(prefix)])
}

然后我们可以用filepath.Join把剩下的部分拼回去

if sliceHasPrefix( secret_parts, base_parts ) {
    fmt.Println( filepath.Join(secret_parts[len(base_parts):]...) )
} else {
    panic("secret is not inside base")
}

我认为一个很好的独立于平台的解决方案是使用 golang path/filepath Split 函数。不对路径分隔符的外观、处理卷等做出假设...

import (
    "path/filepath"
)

func subpath(homeDir, prevDir string) string {
    subFiles := ""
    for {
        dir, file := filepath.Split(prevDir)
        if len(subFiles) > 0 {
            subFiles = file + string(filepath.Separator) + subFiles
        } else {
            subFiles = file
        }
        if file == homeDir {
            break
        }
        if len(dir) == 0 || dir == prevDir {
            break
        }
        prevDir = dir[:len(dir) - 1]
    }
    return subFiles
}

通话
subpath("home", "allusers/user/home/path/to/file")

处理 "home" 可能出现多次而您希望匹配第一个的情况:

func subpath(homeDir, prevDir string) (subFiles string, found bool) {
    for {
        dir, file := filepath.Split(prevDir)
        if len(subFiles) > 0 {
            subFiles = file + string(filepath.Separator) + subFiles
        } else {
            subFiles = file
        }
        if len(dir) == 0 || dir == prevDir {
            return
        }
        prevDir = dir[:len(dir) - 1]
        if file == homeDir {
            found = true
            // look for it lower down
            lower, foundAgain := subpath(homeDir, prevDir)
            if foundAgain {
                subFiles = lower + string(filepath.Separator) + subFiles
            }
            return
        }
    }
}

通话
path, found = subpath("home", "allusers/user/home/path/home2/home/to/file")
if found {
    fmt.Printf("%q\n", path)
} else {
    fmt.Printf("not found\n")
}