папка zip с источником и целью - PullRequest
0 голосов
/ 06 июня 2018

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

Например

Папка в пути, как источник

"/Users/i03434/go/src/zdf/BUILD"

цель

"/Users/i03434/go/src/zdf/app/info.zip"

В настоящее время я пытаюсь добавить новый путь [2], который не помогает, есть идеи, как это сделать?

Это весь код

func zipit(params ...string) error {

    zipfile, err := os.Create(params[1])
    if err != nil {
        return err
    }
    defer zipfile.Close()

    archive := zip.NewWriter(zipfile)
    defer archive.Close()

    info, err := os.Stat(params[0])
    if err != nil {
        return err
    }

    var baseDir string
    if info.IsDir(); len(params) > 2 {
        baseDir = params[2]
    } else {
        baseDir = filepath.Base(params[0])
    }

    if baseDir != "" {
        baseDir += "/"
    }

    filepath.Walk(params[0], func(path string, info os.FileInfo, err error) error {
        if err != nil {
            return err
        }

        if info.IsDir() {
            return nil
        }

        header, err := zip.FileInfoHeader(info)
        if err != nil {
            return err
        }

        if baseDir != "" {
            header.Name = filepath.Join(strings.TrimPrefix(path, baseDir))
        }

        header.Method = zip.Deflate

        writer, err := archive.CreateHeader(header)
        if err != nil {
            return err
        }

        file, err := os.Open(path)
        if err != nil {
            return err
        }
        defer file.Close()
        _, err = io.Copy(writer, file)
        return err
    })

    return err
}

Логика почтового индексаработает как положено, почтовый индекс должен соответствовать спецификации jar

1 Ответ

0 голосов
/ 02 июля 2018

Для тестирования:

Вы можете передать смоделированную переменную zipFile, которая влияет на интерфейс io.Writer, в качестве аргумента для функции zipit и сравнить ее с ожидаемыми данными втест.
Также вам понадобится известный набор файлов в месте назначения, чтобы вы сравнили его со значением в макете.

См. Это для тестирования io.Writer

Код тестирования:

Строковое значение сжатого файла, созданного с конкретными значениями source & newBaseDir, должно быть заранее известно и сохранено в want.

func TestZipIt(t *testing.T) {

    source := ""
    newBaseDir := ""

    var zipFileMock bytes.Buffer
    if err := zipit(zipFileMock, source, newBaseDir); err != nil {
        t.Fatalf("zipit() returned an error: %s", err)
    }

    got := b.String()

    // want is the value of the zipped file as a string
    want := ...

    if got != want {
        t.Errorf("zipit() test failed")
        // t.Errorf("zipit() = %q, want %q", got, want)
    }
}

Программный код:

func main() {
    ...
    // params[0] is source
    // params[1] is destination
    // params[2] is newBaseDirectory

    zipfile, err := os.Create(destination)
    if err != nil {
        // handle error
    }
    defer zipfile.Close()

    if err = zipit(zipfile, source, newBaseDir); err != nil {
        // handle error
    }
    ...
}

func zipit(zipFile io.Writer, source, newBaseDir string) error {

    archive := zip.NewWriter(zipfile)
    defer archive.Close()

    info, err := os.Stat(source)
    if err != nil {
        return err
    }

    var baseDir string
    if info.IsDir() {
        baseDir = filepath.Dir(source)
    }

    if baseDir != "" {
        baseDir += "/"
    }

    filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
        if err != nil {
            return err
        }

        if info.IsDir() {
            return nil
        }

        header, err := zip.FileInfoHeader(info)
        if err != nil {
            return err
        }

        if baseDir != "" {
            header.Name = filepath.Join(newBaseDir, strings.TrimPrefix(path, baseDir))
        }

        header.Method = zip.Deflate

        writer, err := archive.CreateHeader(header)
        if err != nil {
            return err
        }

        file, err := os.Open(path)
        if err != nil {
            return err
        }
        defer file.Close()
        _, err = io.Copy(writer, file)
        return err
    })

    return err
}

Оригинальный ответ:

Есть несколько вещей, которые следует учитывать.

  • Вам нужно использовать filepath.Dir вместо filepath.Base.Base дает последний элемент пути, а не базовый каталог.

  • if info.IsDir(); len(params) > 2 { только проверяет условие len(params) > 2, info.IsDir() вычисляется, но нигде не используется.

См .: Если с кратким форматом выписки в Go [1] [2]

Должно быть

if info.IsDir() {
    if len(params) > 2 {
        ...
    } else {
        ...
    }
}
  • Если мое понимание вашего требования верно.Старый базовый путь должен быть удален из заголовков файла и заменен значением param [2], если оно доступно, или предполагается, что мы сохраняем относительную файловую структуру, если она пуста.

Изменения:

var baseDir string
if info.IsDir(); len(params) > 2 {
    baseDir = params[2]
} else {
    baseDir = filepath.Base(params[0])
}

должно быть

    var baseDir, newBaseDir string
    if info.IsDir() {
        baseDir = filepath.Dir(params[0])
        if len(params) > 2 {
            newBaseDir = params[2]
        }
    }

И

header.Name = filepath.Join(strings.TrimPrefix(path, baseDir))
становится
header.Name = filepath.Join(newBaseDir, strings.TrimPrefix(path, baseDir))

...