Python file.tell给出错误的值位置

时间:2013-11-01 16:19:25

标签: python seek tell

我正在尝试使用Python从现有文件中提取许多位置。这是我目前提取位置的代码:

    self.fh = open( fileName , "r+")
    p = re.compile('regGen regPorSnip begin')
    for line in self.fh :
        if ( p.search(line) ):
            self.porSnipStartFPtr = self.fh.tell()
            sys.stdout.write("found regPorSnip")

此代码段重复多次(文件打开次数较少),搜索值不同,似乎有效:我收到正确的消息,变量有值。

但是,使用下面的代码,第一个写入位置是错误的,而后续的写入位置是正确的:

    self.fh.seek(self.rstSnipStartFPtr,0)
    self.fh.write(str);
    sys.stdout.write("writing %s" % str )
    self.rstSnipStartFPtr = self.fh.tell()

我已经读过将某些read / readline选项传递给fh会导致错误的判断值,因为Python倾向于“预读”。我看到避免这种情况的一个建议是读取整个文件并重写它,这在我的应用程序中不是一个非常有吸引力的解决方案。

如果我将第一个代码段更改为:

  for line in self.fh.read() :
        if ( p.search(line) ):
            self.porSnipStartFPtr = self.fh.tell()
            sys.stdout.write("found regPorSnip")

然后看来self.fh.read()只返回字符而不是整行。搜索从不匹配。 self.fh.readline()似乎也是如此。

我的结论是fh.tell仅在写入操作后查询时返回有效的文件位置。

有没有办法在阅读/搜索时提取准确的文件位置?

感谢。

2 个答案:

答案 0 :(得分:12)

在文档对象的next()方法的文档中(相当模糊地)解释了原因:

  

当文件用作迭代器时,通常在for循环中(例如,   对于f:print line中的行,重复调用next()方法。   此方法返回下一个输入行,或者在何时引发StopIteration   EOF被击中。为了使for循环成为最有效的循环方式   在文件的行(一个非常常见的操作),next()方法   使用隐藏的预读缓冲区。使用预读的结果   缓冲区,将next()与其他文件方法(如readline())相结合   不行。但是,使用seek()将文件重新定位到   绝对位置将刷新预读缓冲区。

tell()返回的值反映了这个隐藏的预读缓冲区已经达到了多远,通常会超出程序实际检索到的字符数千字节。

没有可移植的方法。如果您需要将tell()与阅读行混合,请改用文件的readline()方法。权衡是,作为获得可用tell()结果的回报,使用readline()迭代大文件通常比使用for line in file_object:慢得多。

代码

具体而言,将循环更改为:

line = self.fh.readline()
while line:
    if p.search(line):
        self.porSnipStartFPtr = self.fh.tell()
        sys.stdout.write("found regPorSnip")
    line = fh.readline()

我不确定这是你真正想要的,但是:tell()正在捕捉 next 行的开头位置。如果想要行的 start 的位置,那么你需要更改逻辑,如下所示:

pos = self.fh.tell()
line = self.fh.readline()
while line:
    if p.search(line):
        self.porSnipStartFPtr = pos
        sys.stdout.write("found regPorSnip")
    pos = self.fh.tell()
    line = fh.readline()

或用“一圈半”来做:

while True:
    pos = self.fh.tell()
    line = self.fh.readline()
    if not line:
        break
    if p.search(line):
        self.porSnipStartFPtr = pos
        sys.stdout.write("found regPorSnip")

答案 1 :(得分:0)

我想我不明白这个问题

>>> fh = open('test.txt')
>>> fh.tell()
0L
>>> fh.read(1)
'"'
>>> fh.tell()
1L
>>> fh.read(5)
'a" \n"'
>>> fh.tell()
7L