Изменить каталог имени файла - PullRequest
0 голосов
/ 15 мая 2018

Мне нужно изменить пути к именам файлов относительно данной папки.
Я имею дело с многопользовательскими общими корзинами, и было бы неплохо, чтобы пользователь не знал полный путь к файлу.

У меня есть пример ниже, но он выглядит немного грязным.

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)

}

Кроме того, новый путь должен начинаться с точки разделения.

Есть ли другой способ сделать это более элегантно? Примеры будут оценены.

Ответы [ 2 ]

0 голосов
/ 16 мая 2018

Я думаю, что хорошее независимое от платформы решение состоит в том, чтобы использовать функцию разделения пути golang path / filepath. Не делает предположений о том, как выглядит разделитель пути, обрабатывает тома и т. Д. *

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")
}
0 голосов
/ 15 мая 2018

Практическое правило: не манипулировать путями к файлам как строками . Там слишком много крайних случаев. Go имеет библиотеки path и filepath для управления путями.

Но есть исключения. Библиотеки Go path и filepath ограничены в своей функциональности, так как в ней отсутствует способ разбить путь на массив или проверить, является ли один путь к файлу дочерним по отношению к другому. Иногда гораздо эффективнее использовать строковые функции. Вы можете избежать многих проблем, сначала вызвав 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")
}
...