Gere nomes de arquivos temporários sem criar arquivos reais em Python

98

A questão, número 10501247 , em stackoverflow dá a resposta como criar um arquivo temporário em Python.
Eu só preciso ter o nome do arquivo temporário no meu caso.
Chamar tempfile.NamedTemporaryFile () retorna o identificador de arquivo após a criação do arquivo real.
Existe uma maneira de obter apenas o nome do arquivo?

# Trying to get temp file path
tf = tempfile.NamedTemporaryFile()
temp_file_name = tf.name
tf.close()
# Here is my real purpose to get the temp_file_name
f = gzip.open(temp_file_name ,'wb')
...
Colina
fonte
7
NamedTemporaryFilegarante um nome exclusivo, (provavelmente) experimentando e tentando novamente se ele existir. Obter apenas um nome não garante que você possa realmente criar o arquivo mais tarde, você está se abrindo para a condição de corrida de outra pessoa usando o mesmo nome antes de você.
Joachim Isaksson
5
@Joachim True, há uma condição de corrida aqui e seria preferível evitar isso. No entanto, às vezes você tem que passar um nome de arquivo temporário para uma função (abertura de arquivo acontecendo internamente). Ter um nome bem aleatório dá uma probabilidade muito maior de que a condição de corrida não seja um problema. Acho que há uma necessidade válida de fornecer um bom nome de arquivo temporário para minimizar a chance de uma falha na condição de corrida. É claro que adicionar um bom prefixo e sufixo com base no processo em execução e na tarefa executada fornecerá ainda menos chance de uma colisão.
PolyMesh
@PolyMesh Você pode evitar a condição de corrida criando um diretório temporário e usando um arquivo de nome fixo dentro dele. Portanto, sua função aceita um diretório, em vez de um arquivo, e sempre cria o mesmo arquivo.
DylanYoung
use tarfile e passe para fileobj
Wyrmwood

Respostas:

67

Se você deseja apenas um nome de arquivo temporário, pode chamar a função interna do arquivo temporário _get_candidate_names():

import tempfile

temp_name = next(tempfile._get_candidate_names())
% e.g. px9cp65s

Chamar nextnovamente, retornará outro nome, etc. Isso não fornece o caminho para a pasta temporária. Para obter o diretório 'tmp' padrão, use:

defult_tmp_dir = tempfile._get_default_tempdir()
% results in: /tmp 
Marcin
fonte
3
a melhor maneira de criar um diretório temporário é temp_dir = tempfile.mkdtemp(prefix='some-prefix_')criar com segurança um diretório temporário e retornar uma string com o caminho absoluto.
Emanuel Ey
3
É importante ressaltar que next(tempfile._get_candidate_names())não retorna necessariamente um caminho inexistente, é por isso que as interfaces de arquivo temporário em nível de usuário podem tentar vários nomes até que um não utilizado seja encontrado :
Eli Korvigo
1
Pode-se usar público em tempfile.gettempdir()vez de privado tempfile._get_default_tempdir().
flonk em
@EmanuelEy É importante lembrar que ao usar tempfile.mkdtempo usuário é responsável por deletar o diretório temporário e seu conteúdo quando feito com ele.
Daniel Braun
46

Acho que a maneira mais fácil e segura de fazer isso é algo como:

path = os.path.join(tempfile.mkdtemp(), 'something')

Um diretório temporário é criado que só você pode acessar, portanto, não deve haver problemas de segurança, mas não haverá arquivos criados nele, portanto, você pode escolher qualquer nome de arquivo que deseja criar nesse diretório.

editar: No Python 3 você agora pode usar tempfile.TemporaryDirectory()como um gerenciador de contexto para lidar com a exclusão para você:

with tempfile.TemporaryDirectory() as tmp:
  path = os.path.join(tmp, 'something')
  # use path
Alec
fonte
1
Como Daniel Braun mencionou acima: É importante lembrar que ao utilizar tempfile.mkdtempo usuário é responsável por deletar o diretório temporário e seu conteúdo ao terminar com ele.
bitinerant
4
Se você usar tempfile.TemporaryDirectory()como gerenciador de contexto, ele será excluído para você.
gerrit
17

Pode ser um pouco tarde, mas há algo de errado com isso?

import tempfile
with tempfile.NamedTemporaryFile(dir='/tmp', delete=False) as tmpfile:
    temp_file_name = tmpfile.name
f = gzip.open(temp_file_name ,'wb')
Russell
fonte
37
Este código irá realmente criar o arquivo temporário para obter seu nome, enquanto na pergunta ele diz without creating actual file in Python.
Jakub Kukul
Isso não responder à pergunta
herve
8

tempfile.mktemp() faça isso.

Mas observe que ele está obsoleto. No entanto, ele não criará o arquivo e é uma função pública em tempfile em comparação com o uso do _get_candidate_names().

O motivo pelo qual está obsoleto é devido ao intervalo de tempo entre chamar isso e realmente tentar criar o arquivo. No entanto, no meu caso, a chance disso é tão pequena e, mesmo que falhe, seria aceitável. Mas cabe a você avaliar seu caso de uso.

Zitrax
fonte
1
“Mesmo se falhasse, isso seria aceitável”; a condição de corrida não é apenas um risco de falha, é um risco de segurança (consulte a tempfile.mktempdocumentação). Portanto, isso não deve ser considerado aceitável.
bignose de
4
@bignose É um possível problema de segurança. Depende do que você deseja fazer, do ambiente de execução em que está, etc. Dito isso: pode ser mais seguro fazer algo como os.path.join(tempfile.mkdtemp(), 'something')Lá pelo menos o diretório é criado (e pertencente a você, presumo).
Alec de
5

Combinando as respostas anteriores, minha solução é:

def get_tempfile_name(some_id):
    return os.path.join(tempfile.gettempdir(), next(tempfile._get_candidate_names()) + "_" + some_id)

Faça some_idopcional se não for necessário para você.

juanmirocks
fonte
Novamente, os nomes dos candidatos podem não estar realmente disponíveis. Esta é a resposta correta: stackoverflow.com/a/45803022/6387880
j4hangir
1
No entanto, provavelmente é necessário criar nomes aleatórios. No entanto, com certeza, se _get_candidate_names()não existir, pode-se usar como padrão algum gerador de string semi-aleatório. Por exemplo, algum uuid.
juanmirocks
4

Como Joachim Isaksson disse nos comentários, se você apenas receber um nome, poderá ter problemas se algum outro programa usar esse nome antes do seu programa. As chances são mínimas, mas não impossíveis.

Portanto, a coisa segura a fazer nessa situação é usar o construtor GzipFile () completo, que tem a assinatura GzipFile( [filename[, mode[, compresslevel[, fileobj]]]]). Assim, você pode passar para ele o open fileobj e também um nome de arquivo, se desejar. Veja a documentação gzip para detalhes.

PM 2Ring
fonte