问题
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:
- use
tempfile.mktemp()
to get the name of a temporary file, note this is depreciated for a reason - 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 - 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 - 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:
- create a
TemporaryFile
object, which creates an empty temporary file on the disk and opens it for reading/writing - get the name of the temporary file that was just created
- remove the
TemporaryFile
object from scope, which would also cause the associated file to be removed - 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