tempfile.TemporaryFile() does not work with sqlite3 after being assigned to a variable

穿精又带淫゛_ 提交于 2020-08-06 01:39:11

问题


I am using the tempfile and sqlite3 modules in Python.

The following code works:

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

Thus, I would expect the following code to work as well, but it doesn't:

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

sqlite3.OperationalError: unable to open database file

I was able to use this answer to extract the file path used by conn1. Feeding that into sqlite.connect worked as well:

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)

It seems that I can use TemporaryFile().name, so long as I don't save it in a variable. This is problematic, because in my real code I need to store the path to the temporary file. I could get around all this by using the code used to generate conn3, but it's horribly ugly and inefficient to create an extra database connection and SQL query for seemingly no reason.


回答1:


you should be using NamedTemporaryFile instead of TemporaryFile. presumably you're running under MS Windows which doesn't support unnamed files so these two are the same and hence you don't notice any difference

that said, you shouldn't be using *TemporaryFile at all, as these create and open the file in order protect you from concurrent processes messing you up. the file is presumably locked and hence when sqlite tries to open same file it fails

there are a few alternatives depending on what you want to do:

  1. use tempfile.mktemp() to get the name of a temporary file, note this is depreciated for a reason
  2. use tempfile.mkdtemp() to get the name of a temporary directory, into which you can create the database. this has less security issues so is preferred
  3. use tempfile.TemporaryDirectory() which will create a directory and automatically delete it when it goes out of scope. this might be good/bad for your use case
  4. create the database in memory by doing sqlite3.connect(':memory:'). again depending on whether this really is a temporary database this may or may not be what you want

to explain what was going on before, what you were actually doing when you said it's "working" is similar to:

import sqlite3, tempfile

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

this would:

  1. create a TemporaryFile object, which creates an empty temporary file on the disk and opens it for reading/writing
  2. get the name of the temporary file that was just created
  3. remove the TemporaryFile object from scope, which would also cause the associated file to be removed
  4. use the temporary name to create the database

the reason it failed when when you kept the TemporaryFile around was that the file was never closed and removed. sqlite3 didn't like this and hence it failed

that explanation got far too long, hope it makes sense!



来源:https://stackoverflow.com/questions/58630687/tempfile-temporaryfile-does-not-work-with-sqlite3-after-being-assigned-to-a-va

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!