【问题标题】:Treat a string as a file in python在python中将字符串视为文件
【发布时间】:2017-11-06 22:52:58
【问题描述】:

为了重写一个开源库,我想在python 3中将一串文本视为一个文件。

假设我将文件内容作为字符串:

not_a_file = 'there is a lot of blah blah in this so-called file'

我想将此变量(即文件的内容)视为path-like object,这样我就可以在python的open()function中使用它。

这是一个简单的例子,说明了我的困境:

not_a_file = 'there is a lot of blah blah in this so-called file'
file_ptr = open(not_a_file, 'r')

显然该示例不起作用,因为not_a_file 不是类似路径的对象。出于可移植性目的,我不想编写文件或创建任何临时目录。

话虽如此,我需要解开这个谜团:

not_a_file = 'there is a lot of blah blah in this so-called file'
... Something goes here ... 
file_ptr = open(also_not_a_file, 'r') 

到目前为止我已经尝试过什么

  1. 我已经研究过 StringIO 并尝试将其用作类似路径的对象并且没有骰子: import StringIO output = StringIO.StringIO() output.write('First line.\n') file_ptr = open(output,'r') 好吧,这不起作用,因为 StringIO 不是类似路径的对象。

  2. 我以类似的方式尝试了 tempfile,但没有成功。 import tempfile tp = tempfile.TemporaryFile() tp.write(b'there is a lot of blah blah in this so-called file') open(tp,'r')

  3. 最后我尝试了mmap,看看是否可以将字符串写入内存,然后用open打开内存指针,没有成功。

感谢任何帮助! :-)

编辑 1:我想解决的问题

如果PurePath 被初始化为一个文件,那么pathlib.PurePath 可以与open() 一起工作。也许我可以创建一个继承 PurePath 的类的实例,当open() 读取时,它会读取我的字符串。举个例子吧:

from pathlib import PurePath

not_a_file = 'there is a lot of blah blah in this so-called file'
class Magic(PurePath):
    def __init__(self, string_input):
        self.file_content = string_input
        PurePath.__init__(self, 'Something magical goes here')
    #some more magic happens in this class

also_not_a_file = Magic(not_a_file)
fp = open(also_not_a_file,'r')
print(fp.readlines()) # 'there is a lot of blah blah in this so-called file'

【问题讨论】:

  • 为什么要使用open命令? output.write("第 1 行\n"); output.seek(0); file_ptr=输出
  • @clockwatcher 所以在我要使用的另一个库中,有这个open 命令需要通常的文件输入。出于我的目的和可移植性,我需要以某种方式将字符串传递给open
  • 有没有办法使用带有字符串的 pathlib.PurePath 来创建一个可以读取字符串的对象? open(pathlib.PurePath('path/to/filename.ext'),'r') 是有效的 python。我可以将PurePath 和我的字符串合并到一个类中,当传递给open() 时读取我的字符串?

标签: python string io


【解决方案1】:

StringIO 返回一个StringIO 对象,它几乎等同于open 语句返回的文件对象。所以基本上,您可以使用 StringIO 代替 open 语句。

# from StringIO import StringIO  # for Python 2, old
from io import StringIO
with StringIO('there is a lot of blah blah in this so-called file') as f:
    print(f.read())

输出:

there is a lot of blah blah in this so-called file

【讨论】:

  • 这还不够。我需要像对象also_not_a_string 这样的路径才能成为open() 的有效输入。这个对象,当通过open() 读取时,应该有“这个所谓的文件中有很多废话”字符串。
  • 所以您基本上是想在存储上创建一个真实的现有文件?由于open() 必须将可打开的文件名/路径作为参数。您可以使用 tempfile,但这就像创建文件、使用它并稍后删除它一样。那是你想要的吗?
  • 查看我对#2 的修改。这是一个不起作用的临时文件示例。同样,当通过open() 读取时,我需要一个类似路径的对象,产生字符串“这个所谓的文件中有很多废话”
  • 有时(很少)这是不可能的。 TensorFlow 就是这样一个罕见的问题。您必须指定文件名,并且不能发送文件对象/指针。
【解决方案2】:

您可以创建一个临时文件并将其名称传递给打开:

在 Unix 上:

tp = tempfile.NamedTemporaryFile()
tp.write(b'there is a lot of blah blah blah in this so-called file')
tp.flush()
open(tp.name, 'r')

在 Windows 上,您需要先关闭临时文件才能打开它:

tp = tempfile.NamedTemporaryFile(delete=False)
tp.write(b'there is a lot of blah blah blah in this so-called file')
tp.close()
open(tp.name, 'r')

使用完文件后,您将负责删除该文件。

【讨论】:

  • 你是通过tp.name而不是tp打开的吗?
  • unix 示例不适合我。 NamedTemporaryFile() 是一个类似路径的对象吗?我得到: Traceback(最近一次调用最后一次):文件“”,第 1 行,在 类型错误:预期的 str、字节或 os.PathLike 对象,而不是 _TemporaryFileWrapper
  • 我仍然无法正确读取对象的内容。 open(tp.name, 'r').readlines() 只是给我''
【解决方案3】:

根据我从您的 cmets 和最近的编辑中得知,您需要一个可以使用 open 语句打开的文件。 (我会留下我的其他答案,因为这是解决此类问题的更正确方法)

可以使用tempfile来解决你的问题,它基本上是这样做的:创建你的文件,对你的文件做一些事情,然后在关闭时删除你的文件。

import os
from tempfile import NamedTemporaryFile

f = NamedTemporaryFile(mode='w+', delete=False)
f.write("there is a lot of blah blah in this so-called file")
f.close()
with open(f.name, "r") as new_f:
    print(new_f.read())

os.unlink(f.name) # delete the file after

【讨论】:

    【解决方案4】:

    其他答案对我不起作用,但我设法弄明白了。

    使用 Python 3 时,您需要使用 io package

        import io
        with io.StringIO("some initial text data") as f:
            # now you can do things with f as if it was an opened file.
            function_that_requires_a_Fileobject_as_argument(f)
    

    【讨论】:

      【解决方案5】:

      您可以覆盖 open 对特定功能的含义 - 类似于 unittest.mock.patch 所做的。但是,要这样做,您必须跟踪目标函数所在的模块。为确保稍后恢复 open,您可以利用装饰器或上下文管理器:

      class FileToStringIOPatch:
          def __init__(self, module, new_reader=io.StringIO, **kwargs):
              self.new_reader = new_reader
              self.globals_dict = vars(module)
              self.old_open = self.globals_dict.get('open', open)
              self.kwargs = kwargs
      
          def __enter__(self):  # initialize context manager - overwrite `open`
              def new_open(file, mode='r', buffering=None, encoding=None, errors=None, newline=None, closefd=True):
                  return self.new_reader(file, **self.kwargs)
              self.globals_dict['open'] = new_open
      
          def __exit__(self, exc_type, exc_val, exc_tb): # close ctx manager - restore `open`
              self.globals_dict['open'] = self.old_open
      

      “模拟”函数声明与调用它的模块位于同一模块时的示例用法:

      def read(path):
          with open(path, 'r') as f:
              print(f.read())
      
      # ...
      import sys
      module_reference = sys.modules[__name__]
      
      string = "siala_baba_mak"
      with FileToStringIOPatch(module_reference)
          read(string)  # prints siala_baba_mak
      read('path/to/file.txt')  # outside of context manager it still works as usual
      

      “模拟”函数声明在另一个模块中时的示例用法

      def read(path):
          with open(path, 'r') as f:
              print(f.read())
      
      # ...
      
      from xyz import read
      import xyz
      module_reference = xyz
      
      string = "siala_baba_mak"
      with FileToStringIOPatch(module_reference)
          read(string)  # prints siala_baba_mak
      read('path/to/file.txt')  # outside of context manager it still works as usual
      

      您甚至可以提供自定义阅读器来添加其他功能,例如从 AWS S3 存储桶读取。

      from s3path import S3Path
      path = S3Path("s3://path/to/file.txt")
      with FileToStringIOPatch(module_reference, new_reader=path.open):
          read_(path)
      

      【讨论】:

        猜你喜欢
        • 2021-11-15
        • 2013-04-08
        • 2016-01-27
        • 2021-12-09
        • 2010-12-06
        • 1970-01-01
        • 2020-01-15
        • 2011-01-30
        • 2011-04-27
        相关资源
        最近更新 更多