Python 如何在可能处于通用模式的文件流上使用io原语(查找、读取)?
我有一个Python 如何在可能处于通用模式的文件流上使用io原语(查找、读取)?,python,file-io,io,Python,File Io,Io,我有一个文件对象,它可能在通用模式下打开,也可能不打开。(如果有帮助,我可以使用file.mode访问此模式) 我想使用标准的io方法处理此文件:read和seek 如果我在非通用模式下打开文件,一切都会正常工作: In [1]: f = open('example', 'r') In [2]: f.read() Out[2]: 'Line1\r\nLine2\r\n' # uhoh, this file has carriage returns In [3]: f.seek(0) In
文件
对象,它可能在通用模式下打开,也可能不打开。(如果有帮助,我可以使用file.mode
访问此模式)
我想使用标准的io
方法处理此文件:read
和seek
如果我在非通用模式下打开文件,一切都会正常工作:
In [1]: f = open('example', 'r')
In [2]: f.read()
Out[2]: 'Line1\r\nLine2\r\n' # uhoh, this file has carriage returns
In [3]: f.seek(0)
In [4]: f.read(8)
Out[4]: 'Line1\r\nL'
In [5]: f.seek(-8, 1)
In [6]: f.read(8)
Out[6]: 'Line1\r\nL' # as expected, this is the same as before
In [7]: f.close()
但是,如果在通用模式下打开文件,则会出现问题:
In [8]: f = open('example', 'rU')
In [9]: f.read()
Out[9]: 'Line1\nLine2\n' # no carriage returns - thanks, 'U'!
In [10]: f.seek(0)
In [11]: f.read(8)
Out[11]: 'Line1\nLi'
In [12]: f.seek(-8, 1)
In [13]: f.read(8)
Out[13]: 'ine1\nLin' # NOT the same output, as what we read as '\n' was *2* bytes
Python将\r\n
解释为\n
,并返回长度为8的字符串
但是,创建此字符串需要从文件中读取9个字节
因此,当尝试使用seek
反转读取
时,我们无法回到开始的位置
有没有办法确定我们使用了一个2字节的换行符,或者更好的方法是禁用这种行为 目前我能想到的最好办法是在阅读前后做一个
告诉,然后检查我们实际得到了多少,但这似乎非常不雅观
另外,在我看来,这种行为实际上与read
的文档相反:
In [54]: f.read?
Type: builtin_function_or_method
String Form:<built-in method read of file object at 0x1a35f60>
Docstring:
read([size]) -> read at most size bytes, returned as a string.
If the size argument is negative or omitted, read until EOF is reached.
Notice that when in non-blocking mode, less data than what was requested
may be returned, even if no size parameter was given.
我是否误解了文档?我在这里列出了一个解决方法,尽管我一点也不满意
考虑到根本问题是通用模式下\n
的长度与文件中实际表示的字节数之间存在差异,避免错误的一种方法是从中间流中读取\n
实际上表示一个字节:
def wrap_stream(f):
# if this stream is a file, it's possible to just throw the contents in
# another stream
# alternatively, we could implement an io object which used a generator to
# read lines from f and interpose newlines as required
return StringIO(f.read())
从wrap\u stream
返回的新io
对象将显示新行作为\n
,无论文件以何种模式打开。您真正想做什么
如果向前读取然后向后搜索的原因是希望返回到文件中的某个特定点,那么请使用tell()记录您所在的位置。这比跟踪读取的字节数容易
savepos = f.tell()
f.read(8)
f.seek(savepos)
f.read(8)
使用fdopen在现有描述符上获取一个新的文件对象,但不使用有问题的“U”模式,并使用该模式进行搜索,这是否可以接受?例如:
>>> import os
>>> f=open('example','rU')
>>> f.read()
'Line1\nLine2\n'
>>> ff=os.fdopen(f.fileno(),'r')
>>> ff.seek(0)
>>> ff.read()
'Line1\r\nLine2\r\n'
>>> ff.seek(-7,1)
>>> f.read()
'Line2\n'
>>>
因此,您可以在任何模式下使用该文件,而无需在该模式下关闭并重新打开该文件。文本模式I/O是魔鬼为了挫败人类的阴谋而创建的。像躲避瘟疫一样避免它。你所要求的是不可能的。只需在二进制模式下打开文件并使用它。或者使用io.open(…,换行符='\n')
禁用通用换行符。
>>> import os
>>> f=open('example','rU')
>>> f.read()
'Line1\nLine2\n'
>>> ff=os.fdopen(f.fileno(),'r')
>>> ff.seek(0)
>>> ff.read()
'Line1\r\nLine2\r\n'
>>> ff.seek(-7,1)
>>> f.read()
'Line2\n'
>>>