【问题标题】:python 3: using file tell() in a for loop yields an errorpython 3:在 for 循环中使用文件 tell() 会产生错误
【发布时间】:2016-08-09 07:30:28
【问题描述】:

嗨,我想在列表中保存所有包含“CREATE TABLE”的行的位置 a) 有没有更好更正确的方法呢? (我是 python 新手) b)为什么将tell用于迭代器很重要?我认为这是一种读取方法(或等效方法),因此只是告诉位置不应该损害文件迭代过程。

所以我有以下课程:

class SQLParser(object):
def __init__(self,filename):
    self.file = open(filename,'r')
    self.createTablePositions=[]
    self.insertIntoPositions=[]

def findCreateTable(self):
    for line in self.file:
        if line.find("CREATE TABLE") is 0:
            print(line)
            self.createTablePositions.append(self.file.tell())



sqlhandler = SQLParser("sql.sql")
sqlhandler.findCreateTable()
print(sqlhandler.createTablePositions)

这会产生以下错误:“回溯(最近一次调用): 文件“C:/Users/user/PycharmProjects/sqlparser/sqlparser.py”,第 18 行,在 sqlhandler.findCreateTable() 在 findCreateTable 中的文件“C:/Users/user/PycharmProjects/sqlparser/sqlparser.py”,第 12 行 curPos = self.file.tell() OSError: 告诉位置被 next() 调用禁用"

我已经搜索了网络和 stackoverflow,但我没有找到直接解决我的问题的方法。 - 目前像重写 next() 方法这样的解决方案超出了我的知识范围,我怀疑这个练习的目的。

您的建议将得到高度评价!

【问题讨论】:

    标签: file python-3.x


    【解决方案1】:

    对于初学者,您永远不会关闭文件,这不好。

    该错误主要是由于tell() 方法的内部行为引起的。通过for line in file 迭代文件,您会不断调用内部操作next(),这会扰乱tell() 方法的工作方式。通常最好使用特定的方法从文件中读取数据:readline()readlines()。除非您确切地知道自己在做什么,否则迭代由操作系统(文件系统)控制的对象可能会由于访问方法(有时)或其他冲突而导致错误。

    同样file.tell() 方法返回光标的位置而不是你所在的行。因此,如果说您正在阅读具有 20 个字符的第一行,则在使用 file.readline() 方法后,file.tell() 将返回 22(字符数加上结束符或其他)

    我建议换一种方式考虑,而不是你正在做的事情。

    class SQLParser(object):
        """
        Parses a SQL file.
        """
    
        def __init__(self,filename):
            self.createTablePositions= self.findCreateTable(filename)
            self.insertIntoPositions=[]
    
        def findCreateTable(self, filename):
            temp = []
            with open(filename, 'r') as file:
                # with operator closes the file upon exit of block
                fileNum = 0
                for line in file.readlines():
                    if "CREATE TABLE" in line:
                        print(line)
                        temp.append(fileNum)
                    fileNum += 1
            return temp
    
    
    sqlhandler = SQLParser("sql.sql")
    print(sqlhandler.createTablePositions)
    

    因此,现在,您将在初始化类对象时解析文件。

    然后您可以继续对insertIntoPosition 的另一种方法执行类似的操作。

    【讨论】:

    • 嗨,我需要大量的字符来获取特定的单词并在另一个文件中重新表述它们,但我猜这个方向很好。
    • 首先谢谢你,关于关闭文件,你是对的,但我还没有完成课程,所以这只是我最后要做的事情(顺便说一句,它不像 C++ - 对象的析构函数不自己处理它?)。最后一个问题我如何跳转到文件中的第 16 行?如果你能回答这个问题(试图在 python 文档中找到),那就太棒了! (这就是为什么我想要 tell() 以便我以后可以使用 seek() !)
    • 跳线:linecache
    • 在python中没有像C++那样的垃圾收集,它是自动的(我猜有一些例外,但不适用于这种情况)
    【解决方案2】:

    如果你的SQL文件太大,根据this answer有两种解决方法:

    1. 使用file.readline() 代替next()
    with open(path, mode) as file:
        while True:
            line = file.readline()
            if not line:
                break
            file.tell()
    
    1. 使用offset += len(line) 代替file.tell()
    offset = 0
    with open(path, mode) as file:
        for line in file:
            offset += len(line)
    

    【讨论】:

      猜你喜欢
      • 2018-12-09
      • 2021-01-14
      • 2018-07-08
      • 2021-05-23
      • 1970-01-01
      • 1970-01-01
      • 2021-06-09
      • 2013-09-13
      • 1970-01-01
      相关资源
      最近更新 更多