我有一些带遗留函数的遗留代码,它将文件名作为参数并处理文件内容。下面是代码的工作传真。
我想要做的是不必使用我生成的一些内容写入磁盘以使用此遗留函数,所以我虽然可以使用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
StringIO
实例已经是一个打开的文件。另一方面,open
命令只接受文件名,以返回打开的文件。 StringIO
实例不适合作为文件名。
此外,您不需要关闭StringIO
实例,因此也不需要将其用作上下文管理器。
如果所有遗留代码都可以使用文件名,那么StringIO
实例就不是了。使用tempfile
module生成临时文件名。
以下是使用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)
您还可以切换到io
模块(Python 2和3中提供)提供的较新的Python 3基础结构,其中io.BytesIO
是StringIO.StringIO
/ cStringIO.StringIO
的更强大的替代品。此对象支持用作上下文管理器(但仍无法传递给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
这个是基于contextmanager的python doc
它只是用简单的上下文包装StringIO,当调用exit时,它将返回到屈服点,并正确关闭StringIO。这避免了制作tempfile的需要,但是对于大字符串,这仍会占用内存,因为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'