tempfile.TeditionalFile () не работает с sqlite3 после назначения переменной - PullRequest
0 голосов
/ 30 октября 2019

Я использую модули tempfile и sqlite3 в Python.

Следующий код работает:

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

Таким образом, можно ожидать, что следующий код также будет работать, но он не't:

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

sqlite3.OperationalError: невозможно открыть файл базы данных

Мне удалось использовать этот ответ для извлечения файлапуть, используемый 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-запрос, казалось бы, без причины.

1 Ответ

0 голосов
/ 30 октября 2019

вы должны использовать NamedTemporaryFile вместо TemporaryFile. по-видимому, вы работаете в MS Windows, которая не поддерживает безымянные файлы, поэтому эти два одинаковы и, следовательно, вы не заметите никакой разницы

, которая говорит, что вы не должны использовать *TemporaryFile вообще, так как они создают и открывают файл, чтобы защитить вас от одновременных процессов, запутывающих вас. файл предположительно заблокирован и, следовательно, когда sqlite пытается открыть тот же файл, он терпит неудачу

, есть несколько альтернатив в зависимости от того, что вы хотите сделать:

  1. используйте tempfile.mktemp(), чтобы получитьимя временного файла, обратите внимание, что это устарело по причине
  2. , используйте tempfile.mkdtemp(), чтобы получить имя временного каталога, в котором вы можете создать базу данных. здесь меньше проблем с безопасностью, поэтому предпочтительно
  3. использовать tempfile.TemporaryDirectory(), который создаст каталог и автоматически удалит его, когда он выйдет из области видимости. это может быть хорошо / плохо для вашего варианта использования
  4. создать базу данных в памяти, выполнив sqlite3.connect(':memory:'). опять же, в зависимости от того, действительно ли это временная база данных, это может или не может быть тем, что вы хотите

, чтобы объяснить, что происходило раньше, что вы на самом деле делали, когда говорили, что это "работает", похожеto:

import sqlite3, tempfile

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

это будет:

  1. создать объект TemporaryFile, который создаст пустой временный файл на диске и откроет его для чтения / записи
  2. получить имя только что созданного временного файла
  3. удалить объект TemporaryFile из области, что также приведет к удалению связанного файла
  4. использовать временное имя для созданиябаза данных

причина сбоя, когда вы держали TemporaryFile, заключалась в том, что файл никогда не закрывался и не удалялся. sqlite3 это не понравилось, и поэтому ему не удалось

объяснение слишком длинное, надеюсь, оно имеет смысл!

...