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

Эй, ребята, я новичок в go ровно 23 часа и 10 минут, так что, очевидно, у меня проблемы с некоторыми вещами, у меня есть zip-файл, который находится в памяти, и я хотел бы взять этот файл, сделать его копию добавить некоторые файлы копируют и возвращают файл через HTTP, он работает, но когда я открываю файл, он кажется поврежденным

outFile, err := os.OpenFile("./template.zip", os.O_RDWR, 0666)
if err != nil {
    log.Fatalf("Failed to open zip for writing: %s", err)
}
defer outFile.Close()


zipw := zip.NewWriter(outFile)

fmt.Println(reflect.TypeOf(zipw))
for _, appCode := range appPageCodeText {
    f, err := zipw.Create(appCode.Name + ".jsx")

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

    _, err = f.Write([]byte(appCode.Content)) //casting it to byte array and writing to file
}

// Clean up
err = zipw.Close()
if err != nil {
    log.Fatal(err)
}
defer outFile.Close()

//Get the Content-Type of the file
//Create a buffer to store the header of the file in
FileHeader := make([]byte, 512)
//Copy the headers into the FileHeader buffer
outFile.Read(FileHeader)
//Get content type of file
 fmt.Println(reflect.TypeOf(outFile))
//Get the file size
FileStat, _ := outFile.Stat()                      //Get info from file
FileSize := strconv.FormatInt(FileStat.Size(), 10) //Get file size as a string

buffer := make([]byte, FileStat.Size())

outFile.Read(buffer)


//Send the headers
w.Header().Set("Content-Disposition", "attachment; filename="+"template.zip")
w.Header().Set("Content-Type", "application/zip")
w.Header().Set("Content-Length", FileSize)
outFile.Seek(0, 0)
// io.Copy(w, buffer) //'Copy' the file to the client
w.Write(buffer)

1 Ответ

2 голосов
/ 14 января 2020
  1. (основная проблема): вы Read первые 512 байтов outFile в FileHeader, что означает, что они не считаны в buffer Это означает, что первые 512 байт файла не отправляются клиенту. Вы делаете Seek, но слишком поздно для того, чтобы это было полезно - содержимое buffer уже установлено в этой точке. Вам нужно переместить поиск раньше, или написать оба буфера, или просто удалить ненужные FileHeader read.

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

  3. На самом деле, все это не нужно - вместо создания файла на диске, используя zip.Writer для записи в файл, повторно - открыв файл с диска, прочитав его в байтовый массив, а затем записав этот байтовый массив в HTTP-клиент, вы можете просто записать zip.Writer непосредственно в HTTP-клиент (если вам не нужны настройки Content-Length), или пусть он записывает в bytes.Buffer и затем копирует этот буфер в HTTP-клиент (если для вас важен точный Content-Length).

Первый версия выглядит так:

w.Header().Set("Content-Disposition", "attachment; filename=template.zip")
w.Header().Set("Content-Type", "application/zip")
zipw := zip.NewWriter(w)
// Your for loop to add items to the zip goes here.
//
zipw.Close() // plus error handling

А вторая версия выглядит так:

buffer := &bytes.Buffer{}
zipw := zip.NewWriter(buffer)
// Your for loop to add items to the zip goes here.
//
zipw.Close() // plus error handling
w.Header().Set("Content-Disposition", "attachment; filename=template.zip")
w.Header().Set("Content-Type", "application/zip")
w.Header().Set("Content-Length", strconv.FormatInt(buffer.Length(), 10))
io.Copy(w, buffer) // plus error handling
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...