Редактирование zip-файла в памяти - PullRequest
0 голосов
/ 14 января 2020

Я пытаюсь отредактировать zip-файл в памяти в Go и вернуть заархивированный файл через ответ HTTP

Цель состоит в том, чтобы добавить несколько файлов к пути в примере zip-файла

Я добавляю файл log.txt в мой маршрут path/to/file в заархивированную папку

Все это должно быть сделано без сохранения файла или редактирования исходного файла.

Ответы [ 2 ]

1 голос
/ 14 января 2020

Итак, после нескольких часов неутомимой работы я понял, что мой подход был плохим или, возможно, невозможным с уровнем моих знаний, так что это не очень оптимальное решение, но оно работает, и заполняйте файл не так уж и много, это должно быть хорошо для вас .

Итак, у вас есть файл template.zip, и вы хотите добавить дополнительные файлы, мой первоначальный подход состоял в том, чтобы скопировать весь файл в память и отредактировать его, но у меня возникли сложности.

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

        root := "template"
err = filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
    if info.IsDir() {
        return nil
    }append(files,path)}

теперь у меня есть все мои файлы, и я могу создать буфер для хранения всех этих файлов

buf := new(bytes.Buffer)

// Create a new zip archive.
zipWriter := zip.NewWriter(buf)

теперь с zip-архивом я могу записать в него все свои старые файлы и одновременно копировать содержимое

for _, file := range files {
    zipFile, err := zipWriter.Create(file)
    if err != nil {
        fmt.Println(err)
    }

    content, err := ioutil.ReadFile(file)
    if err != nil {
        log.Fatal(err)
    }

    // Convert []byte to string and print to screen
    // text := string(content)

    _, err = zipFile.Write(content)
    if err != nil {
        fmt.Println(err)
    }
}

На данный момент у нас есть файл в buf.bytes()

Оставшийся холод добавляет новые файлы и отправляет ответ обратно клиенту

for _, appCode := range appPageCodeText {
    f, err := zipWriter.Create(filepath.fileextension)

    if err != nil {
        log.Fatal(err)
    }

    _, err = f.Write([]byte(appCode.Content)) 
}

err = zipWriter.Close()
if err != nil {
    fmt.Println(err)
}

w.Header().Set("Content-Disposition", "attachment; filename="+"template.zip")
w.Header().Set("Content-Type", "application/zip")

w.Write(buf.Bytes()) //'Copy' the file to the client
1 голос
/ 14 января 2020

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

Это только для справки. Если вам нужна дополнительная информация, вы должны установить более полезную информацию заголовка HTTP перед сжатием, чтобы клиент мог правильно обработать данные ответа.

package main

import (
    "archive/zip"
    "io"
    "net/http"
    "os"

    "github.com/gin-gonic/gin"
)

func main() {
    engine := gin.Default()
    engine.GET("/log.zip", func(c *gin.Context) {
        f, err := os.Open("./log.txt")
        if err != nil {
            c.String(http.StatusInternalServerError, err.Error())
            return
        }

        defer f.Close()
        info, err := f.Stat()
        if err != nil {
            c.String(http.StatusInternalServerError, err.Error())
            return
        }

        z := zip.NewWriter(c.Writer)
        head, err := zip.FileInfoHeader(info)
        if err != nil {
            c.String(http.StatusInternalServerError, err.Error())
            return
        }

        defer z.Close()

        w, err := z.CreateHeader(head)
        if err != nil {
            c.String(http.StatusInternalServerError, err.Error())
            return
        }

        _, err = io.Copy(w, f)
        if err != nil {
            c.String(http.StatusInternalServerError, err.Error())
            return
        }
    })

    engine.Run("127.0.0.1:8080")
}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...