通过文本和文件流保存openpyxl文件

41

我正在将OpenPyXL构建到一个应用程序中,该应用程序期望一个包含Excel文件内容的字符串,以便通过文件流进行写入。

从我对OpenPyXL源代码的调查中,它似乎不支持这种输出。有没有人有修改openpyxl以支持此功能的经验?

或者有任何一般性的建议/解决方法吗?

谢谢。

5个回答

52

在openpyxl 2.6版本中调用save_virtual_workbook方法会发出以下警告:

DeprecationWarning: Call to deprecated function save_virtual_workbook (Use a NamedTemporaryFile).

在某个时候,save_virtual_workbook 将从 openpyxl中删除。

在Python 3中,将openpyxl工作簿保存到文件流的典型用法变为:

from io import BytesIO
from tempfile import NamedTemporaryFile
from openpyxl import Workbook

wb = Workbook()
with NamedTemporaryFile() as tmp:
    wb.save(tmp.name)
    output = BytesIO(tmp.read())

在查看 WorkBook 的实现 save 方法后,'filename' 直接发送到 ZipFile,它接受路径或文件对象,因此不需要使用 NamedTemporaryFile,可以直接使用内存中的 BytesIO:

from io import BytesIO
from openpyxl import Workbook

wb = Workbook()
virtual_workbook = BytesIO()
wb.save(virtual_workbook)

# now use virtual_workbook to send to a stream; email attachment, etc


请问您能否解答一下如何将虚拟工作簿发送到流或电子邮件或通过API响应发送的问题。 - Anutosh Chaudhuri
以某种原因,直接保存到 BytesIO 在这里无法正常工作。但无论如何,这更像是基于私有代码的黑客行为,所以我不建议在生产代码中这样做,因为无法保证私有代码不会发生变化。不过,使用 NamedTemporaryFile 的建议代码可以正常运行,并且也被 save_virtual_workbook 的弃用消息建议使用! - Jerther

50

jcollado的答案实际上是有效的,但在openpyxl.writer.excel中也有一个函数(遗憾的是尚未记录),名为“save_virtual_workbook”,它将获取您的工作簿并将其作为字符串返回:

from openpyxl.workbook import Workbook
from openpyxl.writer.excel import save_virtual_workbook

wb = Workbook()
print save_virtual_workbook(wb)
你要找的是由save_virtual_workbook()返回的字符串。

9
这正是我需要用文件流保存的。你也可以这样保存它:io.BytesIO(save_virtual_workbook(wb)) - Esteban
5
我们不应再使用这个函数了。Deprecated: Use a NamedTemporaryFile。请参见文档 - LMB

19

使用 StringIO 对象来保存文件内容:

from openpyxl.workbook import Workbook
from StringIO import StringIO

output = StringIO()
wb = Workbook()
wb.save(output)
print output.getvalue()

你要寻找的字符串就是这个例子最后一行输出的内容。


4
似乎那个方法不起作用了。wb.save() 只需要一个文件名(字符串对象),而不是一个 IO-Byte 对象。请注意不要改变原意,使翻译通俗易懂。 - nuts
3
确认这不起作用。无论您向wb的保存方法提供什么,都会尝试将其用作文件名。 - Esteban
1
我的 openpyxl 2.3.3 可以使用,但需要 io.BytesIO - velis
仅为支持此 - 检查此处的openpxyl代码,它只是将filename传递给Python的ZipFile库,该库接受文件名或文件类对象(例如BytesIO)。不幸的是,我无法确定自从哪个版本开始出现这种情况。 - Jonas

10

自版本2.6起,与save_virtual_workbook兼容的实现已被弃用:

from io import BytesIO
from tempfile import NamedTemporaryFile


def save_virtual_workbook(workbook):
    with NamedTemporaryFile() as tf:
        workbook.save(tf.name)
        in_memory = BytesIO(tf.read())
        return in_memory.getvalue()

我已经尝试了那种方法,但是我得到了“类型为bytes的对象不可序列化为JSON”的错误。更多信息请参见:https://stackoverflow.com/questions/62519571/output-json-file-as-excel-formated-filestream - JackTheKnife
@JackTheKnife 您是否正在使用Django Rest框架?如果您能提供最小代码,这将是有帮助的。 - Thanh Nguyen

0
from openpyxl import Workbook
from io import BytesIO

rows = [[1,2], [3,4]]

book = Workbook()
sheet = book.active

for row in rows:
    sheet.append(row)

io = BytesIO
book.save(io)

content = io.getValue()

return Response(
    content,
    mimetype=magic.from_buffer(content, mime=True),
    headers={
    'Content-Disposition': 'attachment;filename=' + 'test.xlsx'}
)

我需要使用openpyxl来使用字体颜色。 - Marlon Bernal
有一个打字错误,应该是 content = io.getvalue() - qocu
这个解决方案在最新版本的Python和openpyxl中不起作用。TypeError: descriptor 'tell' of '_io.BytesIO' object needs an argument - Mr Alihoseiny
@MrAlihoseiny,您之所以会遇到这个错误,是因为io被赋值为BytesIO函数。要获取BytesIO的值,请像这样调用它:io = BytesIO() - Josh Martin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接