当前位置: 首页 > 知识库问答 >
问题:

在Golang中编辑ZIP存档

蒙勇
2023-03-14

我正在编写一个应用程序,允许用户将匿名数据上传到S3存储桶,以便他们在不向我们提供身份验证数据的情况下试用我们的产品。

这是处理ZIP存档的结构,已被证明是正确的:

type ZipWriter struct {
    buffer *bytes.Buffer
    writer *zip.Writer
}

func FromFile(file io.Reader) (*ZipWriter, error) {

    // First, read all the data from the file; if this fails then return an error
    data, err := ioutil.ReadAll(file)
    if err != nil {
        return nil, fmt.Errorf("Failed to read data from the ZIP archive")
    }

    // Next, put all the data into a buffer and then create a ZIP writer
    // from the buffer and return that writer
    buffer := bytes.NewBuffer(data)
    return &ZipWriter{
        buffer: buffer,
        writer: zip.NewWriter(buffer),
    }, nil
}

// WriteToStream writes the contents of the ZIP archive to the provided stream
func (writer *ZipWriter) WriteToStream(file io.Writer) error {

    // First, attempt to close the ZIP archive writer so that we can avoid
    // double writes to the underlying buffer; if an error occurs then return it
    if err := writer.writer.Close(); err != nil {
        return fmt.Errorf("Failed to close ZIP archive, error: %v", err)
    }

    // Next, write the underlying buffer to the provided stream; if this fails
    // then return an error
    if _, err := writer.buffer.WriteTo(file); err != nil {
        return fmt.Errorf("Failed to write the ZIP data to the stream, error: %v", err)
    }

    return nil
}

使用ZipWriter,我使用FromFile函数加载ZIP文件,然后使用WriteToStream函数将其写入字节数组。之后,我调用以下函数将ZIP归档数据上传到S3中的预签名URL:

// DoRequest does an HTTP request against an endpoint with a given URL, method and access token
func DoRequest(client *http.Client, method string, url string, code string, reader io.Reader) ([]byte, error) {

    // First, create the request with the method, URL, body and access token
    // We don't expect this to fail so ignore the error
    request, _ := http.NewRequest(method, url, reader)
    if !util.IsEmpty(code) {
        request.Header.Set(headers.Accept, echo.MIMEApplicationJSON)
        request.Header.Set(headers.Authorization, fmt.Sprintf("Bearer %s", code))
    } else {
        request.Header.Set(headers.ContentType, "application/zip")
    }

    // Next, do the request; if this fails then return an error
    resp, err := client.Do(request)
    if err != nil {
        return nil, fmt.Errorf("Failed to run the %s request against %s, error: %v", method, url, err)
    } else if resp.StatusCode != http.StatusOK {
        return nil, fmt.Errorf("Failed to run the %s request against %s, response: %v", method, url, resp)
    }

    // Now, read the body from the response; if this fails then return an error
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return nil, fmt.Errorf("Failed to read the body associated with the response, error: %v", err)
    }

    // Finally, return the body from the response
    return body, nil
}

所以,整个操作是这样进行的:

file, err := os.Open(location)
if err != nil {
    log.Fatalf("Unable to open ZIP archive located in %s, error: %v", location, err)
}

writer, err := lutils.FromFile(file)
if err != nil {
    log.Fatalf("File located in %s could not be read as a ZIP archive, error: %v", location, err)
}

buffer := new(bytes.Buffer)
if err := writer.WriteToStream(buffer); err != nil {
    log.Fatalf("Failed to write data to the ZIP archive, error: %v", err)
}

if body, err := DoRequest(new(http.Client), http.MethodPut, url, "", buffer); err != nil {
    log.Fatalf("Failed to upload the data to S3, response: %s, error: %v", string(body), err)
}

我遇到的问题是,尽管上传到S3成功,但当下载ZIP存档并提取数据时,找不到任何文件。在调查这个问题时,我想出了一些可能的失败点:

  1. FromFile不能正确地从该文件创建ZIP存档;导致存档文件损坏

在更深入地研究了这些可能性之后,我认为问题可能在于如何从归档文件创建ZIP编写器,但我不确定问题是什么。

共有1个答案

姬向明
2023-03-14

这里的问题有点像转移视线。正如@CeriseLimón所指出的,在现有ZIP存档上调用NewWriterClose必然会导致在文件末尾添加一个空存档。在我的用例中,解决方案是打开文件并将其直接写入流,而不是试图将其作为ZIP存档读取。

file, err := os.Open(location)
if err != nil {
    log.Fatalf("Unable to open ZIP archive located in %s, error: %v", location, err)
}

if body, err := DoRequest(new(http.Client), http.MethodPut, url, "", file); err != nil {
    log.Fatalf("Failed to upload the data to S3, response: %s, error: %v", string(body), err)
}
 类似资料:
  • 有些代码编辑器,比如WebStorm,在编辑器失去焦点时可以自动保存。我在Atom编辑器中搜索过类似的选项,但还没有找到任何内容。 原子编辑器是否有允许在失去焦点时自动保存已编辑文件的设置?如果是,这可以设置在哪里?如果没有,人们将如何着手编写一个插件,做到这一点?

  • Android Studio中我的应用程序的可以编辑,但编辑完文本后,退出窗口时将不会保存。怎么办?

  • 在“SQL 编辑器”选项卡,你可以创建和编辑视图的 SELECT 语句 SQL。Navicat Data Modeler 为编辑视图定义提供广泛的高级功能,例如:编辑代码功能、智能自动完成代码、设置 sql 格式及更多。 【提示】当你在视图创建工具创建视图,SELECT 语句将会自动生成。 美化 SQL(仅适用于非 Essentials 版) 若要格式化凌乱的 SQL 代码到一个结构良好的脚本,你

  • 我有这个自定义树视图代码: 我希望能够使用内容菜单重命名树的节点。你能帮我实现这个吗?

  • 本文向大家介绍vim 保存在Vim中编辑的只读文件,包括了vim 保存在Vim中编辑的只读文件的使用技巧和注意事项,需要的朋友参考一下 示例 有时,我们可能会打开一个文件,如果没有使用,我们将没有权限在Vim中进行写入sudo。 使用此命令保存在Vim中编辑的只读文件。 您可以:w!!在其中映射到.vimrc: 如图所示,系统将提示您。 。 按O,文件将被保存。它在vi / vim中保持打开状态,

  • 使用laravel 7/livewire应用程序,我使用Repository制作crud,并获得了数据列表,在装载事件中,我分配了受保护的var$FacilityRepository,它在render方法中正常工作, 但在编辑方法中为空,我得到错误: 当用户单击“编辑链接”时 在模板中,编辑链接定义为: 为什么会出现错误以及如何修复? 修改#2: > 类设施扩展组件{...公共$FacilityR