【问题标题】:tempfile.TemporaryFile() does not work with sqlite3 after being assigned to a variabletempfile.TemporaryFile() 在分配给变量后不适用于 sqlite3
【发布时间】:2020-02-26 01:35:12
【问题描述】:

我在 Python 中使用 tempfile 和 sqlite3 模块。

以下代码有效:

import sqlite3, tempfile
conn1 = sqlite3.connect(tempfile.TemporaryFile().name)

因此,我希望以下代码也能正常工作,但事实并非如此:

import sqlite3, tempfile
database_file = tempfile.TemporaryFile()
conn2 = sqlite3.connect(database_file.name)

sqlite3.OperationalError: 无法打开数据库文件

我能够使用this answer 来提取 conn1 使用的文件路径。将其输入 sqlite.connect 也可以:

import sqlite3, tempfile
conn1 = sqlite3.connect(tempfile.TemporaryFile().name)

cur = conn1.cursor()
cur.execute("PRAGMA database_list")
row = cur.fetchone()
database_file_path = row[2]
conn3 = sqlite3.connect(database_file_path)

看来我可以使用 TemporaryFile().name,只要我不将它保存在变量中。这是有问题的,因为在我的真实代码中我需要存储临时文件的路径。我可以通过使用用于生成 conn3 的代码来解决所有这些问题,但是似乎无缘无故地创建额外的数据库连接和 SQL 查询是非常丑陋和低效的。

【问题讨论】:

  • 将函数结果分配给变量并将其作为参数传递与直接传递函数结果没有区别。一定是发生了其他事情。
  • 你应该使用NamedTemporaryFile
  • @Barmar 感谢您的建议,但不幸的是,这似乎也不起作用。我在答案中运行了第二个代码块,将 TemporaryFile 替换为 NamedTemporary File。我得到了和以前一样的错误。

标签: python sql python-3.x sqlite temporary-files


【解决方案1】:

您应该使用NamedTemporaryFile 而不是TemporaryFile。大概您在不支持未命名文件的 MS Windows 下运行,因此这两个是相同的,因此您不会注意到任何区别

也就是说,您根本不应该使用*TemporaryFile,因为它们会创建并打开文件以保护您免受并发进程的影响。该文件可能已被锁定,因此当 sqlite 尝试打开同一文件时它会失败

有几种选择,具体取决于您想要做什么:

  1. 使用tempfile.mktemp() 获取临时文件的名称,请注意这是有原因的折旧
  2. 使用tempfile.mkdtemp() 获取临时目录的名称,您可以在其中创建数据库。这具有较少的安全问题,因此是首选
  3. 使用tempfile.TemporaryDirectory(),它将创建一个目录并在超出范围时自动将其删除。这对您的用例可能是好是坏
  4. 通过sqlite3.connect(':memory:') 在内存中创建数据库。再次取决于这是否真的是一个临时数据库,这可能是也可能不是你想要的

为了解释之前发生的事情,当你说它“工作”时你实际上在做什么类似于:

import sqlite3, tempfile

a = tempfile.TemporaryFile()
b = a.name
del a
conn1 = sqlite3.connect(b)

这会:

  1. 创建一个TemporaryFile 对象,该对象在磁盘上创建一个空的临时文件并打开它以供读取/写入
  2. 获取刚刚创建的临时文件的名称
  3. 从作用域中移除TemporaryFile 对象,这也会导致关联文件被移除
  4. 使用临时名称创建数据库

当您保留TemporaryFile 时它失败的原因是该文件从未关闭和删除。 sqlite3 不喜欢这个,因此失败了

这个解释太长了,希望它有意义!

【讨论】:

  • tempfile.mkstemp() 代替tempfile.mktemp(),但我首选的解决方案是使用tempfile.TemporaryDirectory(),因为mkstemp 打开文件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多