【问题标题】:python write string directly to tarfilepython直接将字符串写入tarfile
【发布时间】:2010-10-18 22:56:30
【问题描述】:

有没有办法将字符串直接写入 tar 文件?从http://docs.python.org/library/tarfile.html 看来,只能添加已写入文件系统的文件。

【问题讨论】:

    标签: python file file-io tar


    【解决方案1】:

    我会说这是可能的,通过使用 TarInfo e TarFile.addfile 将 StringIO 作为文件对象传递。

    非常粗糙,但有效

    import tarfile
    import StringIO
    
    tar = tarfile.TarFile("test.tar","w")
    
    string = StringIO.StringIO()
    string.write("hello")
    string.seek(0)
    info = tarfile.TarInfo(name="foo")
    info.size=len(string.buf)
    tar.addfile(tarinfo=info, fileobj=string)
    
    tar.close()
    

    【讨论】:

    • 你可以直接说StringIO.StringIO("hello")来代替写求。
    • 是不是类似python3和bytesIO对象的过程?
    • @proteneer:我相信在 python 3 中,seek 方法会为您提供二进制长度,而它在内部使用字符串 len() 函数,因此 tarfile.copyfileobj 函数将因 raise OSError("end of file reached") 而失败跨度>
    【解决方案2】:

    正如 Stefano 指出的,您可以使用 TarFile.addfileStringIO

    import tarfile, StringIO
    
    data = 'hello, world!'
    
    tarinfo = tarfile.TarInfo('test.txt')
    tarinfo.size = len(data)
    
    tar = tarfile.open('test.tar', 'a')
    tar.addfile(tarinfo, StringIO.StringIO(data))
    tar.close()
    

    您可能还想填写tarinfo 的其他字段(例如mtimeuname 等)。

    【讨论】:

    • “正如 Stefano 指出的那样”是编辑吗?否则,我看不出你在做什么不同。感谢您的回复。
    • 我认为 Stefano 在我写回复时还没有发布任何代码,他只指出可以使用 TarFile.addfile 和 StringIO。不过,我的记忆有点模糊。
    • FWIW,是的,@Stefano 的详细信息是在您写完这篇文章后添加到an edit 中的。另一个回答说同样的事情也几乎同时出现。
    【解决方案3】:

    我发现这正在寻找如何在 Django 中提供刚刚在内存中创建的 .tgz 存档,可能其他人会发现我的代码有用:

    import tarfile
    from io import BytesIO
    
    
    def serve_file(request):
        out = BytesIO()
        tar = tarfile.open(mode = "w:gz", fileobj = out)
        data = 'lala'.encode('utf-8')
        file = BytesIO(data)
        info = tarfile.TarInfo(name="1.txt")
        info.size = len(data)
        tar.addfile(tarinfo=info, fileobj=file)
        tar.close()
    
        response = HttpResponse(out.getvalue(), content_type='application/tgz')
        response['Content-Disposition'] = 'attachment; filename=myfile.tgz'
        return response
    

    【讨论】:

      【解决方案4】:

      Python 3 中的解决方案使用io.BytesIO。请务必将TarInfo.size 设置为字节的长度,而不是字符串的长度。

      给定单个字符串,最简单的解决方案是在其上调用.encode() 以获取字节。在当今时代,您可能需要 UTF-8,但如果收件人希望使用特定编码,例如 ASCII(即没有多字节字符),请改用它。

      import io
      import tarfile
      
      data = 'hello\n'.encode('utf8')
      info = tarfile.TarInfo(name='foo.txt')
      info.size = len(data)
      
      with tarfile.TarFile('test.tar', 'w') as tar:
          tar.addfile(info, io.BytesIO(data))
      

      如果你真的需要一个可写的 string 缓冲区,类似于@Stefano Borini 对于 Python 2 接受的答案,那么解决方案是在底层 io.BytesIO 缓冲区上使用 io.TextIOWrapper

      import io
      import tarfile
      
      textIO = io.TextIOWrapper(io.BytesIO(), encoding='utf8')
      textIO.write('hello\n')
      bytesIO = textIO.detach()
      info = tarfile.TarInfo(name='foo.txt')
      info.size = bytesIO.tell()
      
      with tarfile.TarFile('test.tar', 'w') as tar:
          bytesIO.seek(0)
          tar.addfile(info, bytesIO)
      

      【讨论】:

      • 可以不指定utf8编码,默认:data = 'hello\n'.encode()
      【解决方案5】:

      仅作记录:
      StringIO 对象具有 .len 属性。
      无需 seek(0) 和做 len(foo.buf)
      无需保留整个字符串来执行 len() on,或者上帝保佑,自己进行会计处理。

      (也许在写 OP 的时候没有。)

      【讨论】:

        【解决方案6】:

        在我的例子中,我想从现有的 tar 文件中读取数据,将一些数据附加到内容中,然后将其写入新文件。比如:

        for ti in tar_in:
            buf_in = tar.extractfile(ti)
            buf_out = io.BytesIO()
            size = buf_out.write(buf_in.read())
            size += buf_out.write(other data)
            buf_out.seek(0)
            ti.size = size
            tar_out.addfile(ti, fileobj=buf_out)
        

        处理目录和链接需要额外的代码。

        【讨论】:

          【解决方案7】:

          你必须使用 TarInfo 对象和 addfile 方法而不是通常的 add 方法:

          from StringIO import StringIO
          from tarfile import open, TarInfo
          
          s = "Hello World!"
          ti = TarInfo("test.txt")
          ti.size = len(s)
          
          tf = open("testtar.tar", "w")
          tf.addfile(ti, StringIO(s))
          

          【讨论】:

            猜你喜欢
            • 2017-11-29
            • 2011-10-05
            • 1970-01-01
            • 2021-12-13
            • 2014-05-21
            • 1970-01-01
            • 1970-01-01
            • 2011-01-30
            • 2020-10-27
            相关资源
            最近更新 更多