我继承了一些代码,这些代码读取大量数据文件并将这些数据打包成块,将其发送到某处的服务器并继续执行。
有时打包程序失败/死亡/无法联系服务器等,数据文件变大。在这一点上,执行所有这些操作的小型 ArchLinux 机器很少会无法完成该过程 - 此时我会在我的 Mac 上获取数据并在本地执行相同的任务(同时需要更好的解决方案)。
ArchLinux 机器永远不会出现我的 Mac 似乎总是遇到的相同错误,即:
该文件1000
一次读取行,这是使用 实现的islice
,这似乎是一种可接受的方式:https ://stackoverflow.com/a/6335876/310391
问题在于,在 Mac 上,这最终会将几行代码拼凑在一起。结果列表很1000
长,但至少其中一行实际上是一行的串联,没有\n
, 和另一行的大部分从稍微向上(36 行返回,在本例中正好 4096 字节)文件(这在向后读取文件时是有道理的,见下文)。
查看 之前和之后的文件seek()
和tell()
位置islice
,我分别得到(例如)3530855
和字节3651687
的读取大小。120832
如果我在 pdb 中遇到此错误时将文件返回到3530855
,然后file.readlines(120832)
我会得到1092
行(readlines
' size 只是一个提示,所以这是有道理的),并且 munged 行不存在(但它的组成部分在各自正确的索引中完好无损)。
没有其他进程从该文件读取或写入该文件,因此我看不到它在执行时会如何“分流” islice
,例如。
tell()
前面给出的第一个位置islice
,上面给出3530855
的后向阅读器(生成器)(文件是os.dup()
'd,首先,在生成器内部)yield
逐行执行 - 生成器break
s 找到时的循环包含它成功发送的最后一个时间戳的行:
for line in BackwardsFileReader(fp):
if somecondition:
break
和
def BackwardsReader(seekfile, size=4096, pos=-1):
"""Read a file line by line, backwards"""
fd = os.dup(seekfile.fileno())
buf = ""
whence = os.SEEK_END if pos < 0 else os.SEEK_SET
with os.fdopen(fd) as readfile:
readfile.seek(0, os.SEEK_END)
if readfile.tell() == 0:
# File is empty, bail.
return
readfile.seek(pos, whence)
buf = readfile.read(size)
readfile.seek(pos, whence)
newline_pos = buf.find("\n")
if newline_pos != -1:
trailing_newline = True
buf = buf[:newline_pos]
else:
trailing_newline = False
while 1:
newline_pos = buf.rfind("\n")
pos = readfile.tell()
if newline_pos != -1:
# Found a newline
line = buf[newline_pos+1:]
# Seek the original file to the end of buf
seekfile.seek(pos + len(buf), os.SEEK_SET)
buf = buf[:newline_pos]
if pos or newline_pos or trailing_newline:
line += "\n"
yield line
elif pos:
# Need to fill buffer
toread = min(size, pos)
readfile.seek(-toread, 1)
buf = readfile.read(toread) + buf
readfile.seek(-toread, 1)
if pos == toread:
buf = "\n" + buf
else:
# Start-of-file
seekfile.seek(0)
return
如果我不费心对文件进行切片,并阅读全部内容(在我的 Mac 上),问题仍然会发生,但不是在同一个地方,而且频率较低。
我唯一能想到的是,生成器可能正在进一步向后推进文件(4096 字节,缓冲区大小),而 islice 正在向前读取文件......奇怪的是这在 Linux 机器上从未发生过。低级文件操作不是我的面包和黄油,当在这里与生成器结合使用时,我想我一定会遗漏一些东西 - 任何人都可以在这里建议下一个调试步骤,或者提供有关可能导致这种差异的提示吗?