StringIO的和兼容性“与”陈述(上下文管理器)(StringIO and compatibil

2019-07-30 21:03发布

我有一个旧的函数,它接受一个文件名作为参数,并处理该文件内容的一些遗留代码。 代码的一个工作传真如下。

我想要做的就是没有写一些内容,我才能用这个传统功能产生的磁盘,所以我虽然我可以用StringIO替代物理文件名来创建一个对象。 然而,这是不行的,因为你可以看到下面。

我以为StringIO是去使用此方式。 谁能告诉我,如果存在,是不是磁盘上的文件,但可以通过传统的功能被视为这种参数使用该传统功能,并将它传递的东西呢? 遗留功能确实有with上下文管理器做的工作filename参数值。

我在谷歌遇到的一两件事是: http://bugs.python.org/issue1286 ,但这并没有帮助我...

from pprint import pprint
import StringIO

    # Legacy Function
def processFile(filename):
    with open(filename, 'r') as fh:
        return fh.readlines()

    # This works
print 'This is the output of FileOnDisk.txt'
pprint(processFile('c:/temp/FileOnDisk.txt'))
print

    # This fails
plink_data = StringIO.StringIO('StringIO data.')
print 'This is the error.'
pprint(processFile(plink_data))

产量

这是在输出FileOnDisk.txt

['This file is on disk.\n']

这是错误:

Traceback (most recent call last):
  File "C:\temp\test.py", line 20, in <module>
    pprint(processFile(plink_data))
  File "C:\temp\test.py", line 6, in processFile
    with open(filename, 'r') as fh:
TypeError: coercing to Unicode: need string or buffer, instance found

Answer 1:

一个StringIO实例一个打开的文件了。 在open命令,而另一方面,只需要文件名,返回一个打开的文件。 甲StringIO实例是不适合作为一个文件名。

此外,您不需要关闭StringIO实例,因此没有必要要么把它作为一个上下文管理器。

如果你所有的遗留代码可以是文件名,然后StringIO实例不是要走的路。 使用tempfile模块生成临时文件名来代替。

下面是一个使用contextmanager确保临时文件的例子事后清理:

import os
import tempfile
from contextlib import contextmanager

@contextmanager
def tempinput(data):
    temp = tempfile.NamedTemporaryFile(delete=False)
    temp.write(data)
    temp.close()
    try:
        yield temp.name
    finally:
        os.unlink(temp.name)

with tempinput('Some data.\nSome more data.') as tempfilename:
    processFile(tempfilename)

您还可以切换到由所提供的新的Python 3基础设施io模块(在Python 2何时上市,3),其中io.BytesIO是更强大的替代StringIO.StringIO / cStringIO.StringIO 。 这种对象不支持所使用的上下文管理器(但仍不能传递给open()



Answer 2:

你可以定义自己的open函数

fopen = open
def open(fname,mode):
    if hasattr(fname,"readlines"): return fname
    else: return fopen(fname,mode)

然而,与想要呼叫__exit__其完成和StringIO的没有退出方法之后...

你可以自定义一个类与这个开放使用

class MyStringIO:
     def __init__(self,txt):
         self.text = txt
     def readlines(self):
          return self.text.splitlines()
     def __exit__(self):
          pass


Answer 3:

这一个是基于Python的文档contextmanager

这只是StringIO的包装用简单的上下文,当调用exit函数,它会返回到屈服点,并妥善关闭StringIO的。 这避免了使临时文件的需要,但随着大字符串,这将仍然吃起来记忆,因为StringIO的缓冲区字符串。 它运作良好,你在哪里知道的字符串数据大多数情况下是不会很长

from contextlib import contextmanager

@contextmanager
def buildStringIO(strData):
    from cStringIO import StringIO
    try:
        fi = StringIO(strData)
        yield fi
    finally:
        fi.close()

然后,你可以这样做:

with buildStringIO('foobar') as f:
    print(f.read()) # will print 'foobar'


文章来源: StringIO and compatibility with 'with' statement (context manager)