Go 更改文件名路径目录

Go 更改文件名路径目录,go,filepath,Go,Filepath,我需要更改相对于给定文件夹的文件名路径。 我正在处理多用户共享存储桶,如果用户不知道完整的文件路径,那就太好了 我下面有一个例子,但它似乎有点脏 package main import ( "fmt" "strings" ) func main() { secretUrl := "allusers/user/home/path/to/file" separator := "home/" newUrl := strings.Split(secretUr

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

我下面有一个例子,但它似乎有点脏

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具有和库来操作路径

但也有例外。Go的
路径
文件路径
库在功能上受到限制,例如它无法将路径拆分为数组或检查一个文件路径是否是另一个文件路径的子路径。有时使用字符串函数要有效得多。通过首先调用它们来规范化它们,可以避免很多问题

如果前缀始终为
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\u parts
确实是
secret\u parts
的前缀,仅在
secret\u parts
的前几个元素上。与基本零件中的编号相同

func sliceHasPrefix( s, prefix []string  ) bool {
    if len(s) < len(prefix) {
        return false
    }

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

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

但也有例外。Go的
路径
文件路径
库在功能上受到限制,例如它无法将路径拆分为数组或检查一个文件路径是否是另一个文件路径的子路径。有时使用字符串函数要有效得多。通过首先调用它们来规范化它们,可以避免很多问题

如果前缀始终为
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\u parts
确实是
secret\u parts
的前缀,仅在
secret\u parts
的前几个元素上。与基本零件中的编号相同

func sliceHasPrefix( s, prefix []string  ) bool {
    if len(s) < len(prefix) {
        return false
    }

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

我认为一个很好的独立于平台的解决方案是使用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")
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")
}
要处理“主页”可能出现多次且您希望与第一次匹配的情况,请执行以下操作:

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
        }
    }
}
打电话给

subpath("home", "allusers/user/home/path/to/file")
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")
}

我认为一个很好的独立于平台的解决方案是使用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")
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")
}
要处理“主页”可能出现多次且您希望与第一次匹配的情况,请执行以下操作:

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
        }
    }
}
打电话给

subpath("home", "allusers/user/home/path/to/file")
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")
}

这个秘密总是从alluser/user/home/…开始吗?这是URL还是文件路径?你到底在问什么?除了“是”或“否”之外,您还希望得到什么样的答案?从技术上讲,这是AWS S3的关键。因此,它是一个文件路径,有时也会考虑URL。我更想找一些使用“path/filepath”包的东西,但找不到。可能更适合codereview论坛?秘密总是从
alluser/user/home/…
开始吗?这是URL还是文件路径?你到底在问什么?除了“是”或“否”之外,您还希望得到什么样的答案?从技术上讲,这是AWS S3的关键。因此,它是一个文件路径,有时也会考虑URL。我更想找一些使用“path/filepath”包的东西,但找不到。可能更适合codereview论坛?回答得很好!请更新您的答案以匹配homeDir的第一个实例,即“allusers/user/home/path/home2/home/to/file”。回答得很好!请更新您的答案以匹配homeDir的第一个实例,即“allusers/user/home/path/home2/home/to/file”。关于不使用字符串的回答也不错。如果前缀总是固定的,这个答案就太好了。不幸的是,它并不总是固定的,只有一个文件夹是事先知道的。这对于已知的文件路径非常有用。@Godfrey您可以调整它,在
secret\u paths
中找到基本目录的索引,并从该点开始返回
secret\u paths
的一部分。将路径作为数组使用通常更容易。好主意。不管怎样,不管我最终接受与否,你的回答仍然很有见地。当复杂性增加时,我的字符串失败得很惨。关于不使用字符串的回答也很好。如果前缀总是固定的,这个答案就太好了。不幸的是,它并不总是固定的,只有一个文件夹是事先知道的。这对于已知的文件路径非常有用。@Godfrey您可以调整它,在
secret\u paths
中找到基本目录的索引,并从该点开始返回
secret\u paths
的一部分。将路径作为数组使用通常更容易。好主意。不管怎样,不管我最终接受与否,你的回答仍然很有见地。当复杂度增加时,我的字符串失败得很惨。