go - 编辑内存中的zip文件并通过http响应返回它会导致文件损坏

标签 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)

最佳答案

  • (主要问题):您将Read的前512个字节outFile编码为FileHeader,这意味着它们没有被读入buffer,这意味着该文件的前512个字节不会发送到客户端。您执行了Seek,但为时已晚,无法使用-那时buffer的内容已经设置好了。您需要更早移动“搜索”或写入两个缓冲区,或者只是删除不必要的FileHeader读取。
  • 您的评论声称您这样做是为了获取文件的内容类型,但实际上从不使用FileHeader。为什么会这样呢?您知道文件的类型是什么,只需编写它即可。因此,不需要单独读取前512个字节。
  • 实际上,这一切都是不需要的-使用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
    

    关于go - 编辑内存中的zip文件并通过http响应返回它会导致文件损坏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59725717/

    相关文章:

    docker - 从另一个容器访问Neo4J

    asynchronous - 当我在 goroutine 中运行 wg.Wait() 时,为什么我的代码可以正常工作?

    go - Redigo ScanStruct 错误与 time.Time

    go - 我不能用 Golang 发送 post 请求?

    go - go get return go:标志需要一个参数:-mod

    golang 模块名称更改导致本地测试失败

    go - 为什么这个 Golang 代码会泄漏内存中变量的值

    dictionary - 这个并发映射有什么问题?

    json - 使用标准模板包从json对象获取前两个值

    session - 为什么要使用 gorilla/context 而不是 session 来进行用户身份验证?