Python: como criar um nome de arquivo exclusivo?


93

Eu tenho um formulário da web em python com duas opções - upload de arquivo e textarea . Preciso pegar os valores de cada um e passá-los para outro programa de linha de comando. Posso passar facilmente o nome do arquivo com opções de upload de arquivo, mas não tenho certeza de como passar o valor da textarea.

Acho que o que preciso fazer é:

  1. Gere um nome de arquivo único
  2. Crie um arquivo temporário com esse nome no diretório de trabalho
  3. Salve os valores passados ​​de textarea no arquivo temporário
  4. Execute o programa de linha de comando de dentro do meu módulo python e passe a ele o nome do arquivo temporário

Não tenho certeza de como gerar um nome de arquivo exclusivo. Alguém pode me dar algumas dicas sobre como gerar um nome de arquivo exclusivo? Quaisquer algoritmos, sugestões e linhas de código são apreciados.

Obrigado pela preocupação


1
Eu editei sua pergunta para tentar torná-la mais clara. Avise-me se eu interpretar algo incorretamente!
culix 01 de

Respostas:


142

Não achei que sua pergunta fosse muito clara, mas se você só precisa de um nome de arquivo exclusivo ...

import uuid

unique_filename = str(uuid.uuid4())

Desculpe, estou trabalhando na plataforma Windows, então não sei como lidar com o subprocesso
MysticCodes

uuid parece criar uma longa string única. Não acho melhor ter o nome do arquivo com string longa e UUID, () nele.
MysticCodes

6
Acho que uuid.uuid4().hexseria uma escolha melhor, veja detalhes aqui .
Gray Li

4
@ToloPalmer: É mais provável que a CPU do seu computador tenha um erro de processamento que faça com que ele carregue o arquivo errado do que um UUID gerado colida com qualquer valor existente. UUID produz um nome único em um modelo de computação que entende que nem toda computação é matemática pura.
GManNickG

2
Perdoe minha ignorância, velho comentário ... Na verdade não é o único, mas muito improvável de colidir, então boa escolha;)
Tolo Palmer

51

Se você quiser fazer arquivos temporários em Python, existe um módulo chamado tempfile nas bibliotecas padrão do Python. Se você deseja iniciar outros programas para operar no arquivo, use tempfile.mkstemp () para criar arquivos e os.fdopen () para acessar os descritores de arquivo que mkstemp () fornece.

A propósito, você diz que está executando comandos de um programa Python? É quase certo que você esteja usando o módulo de subprocesso .

Assim, você pode escrever alegremente um código semelhante a:

import subprocess
import tempfile
import os

(fd, filename) = tempfile.mkstemp()
try:
    tfile = os.fdopen(fd, "w")
    tfile.write("Hello, world!\n")
    tfile.close()
    subprocess.Popen(["/bin/cat", filename]).wait()        
finally:
    os.remove(filename)

Executando isso, você deve descobrir que o catcomando funcionou perfeitamente bem, mas o arquivo temporário foi excluído do finallybloco. Esteja ciente de que você tem para excluir o arquivo temporário que mkstemp () retorna-se - a biblioteca tem nenhuma maneira de saber quando você está feito com ele!

(Editar: eu presumi que NamedTemporaryFile fazia exatamente o que você estava procurando, mas isso pode não ser tão conveniente - o arquivo é excluído imediatamente quando o objeto de arquivo temporário é fechado e outros processos abrem o arquivo antes de você fechá-lo não funcionará em algumas plataformas, especialmente Windows. Desculpe, falha da minha parte.)


usar NamedTemporaryFile é provavelmente o que eles querem (a menos que queiram que ele permaneça no servidor, e então eles podem usar "tempfile.NamedTemporaryFile (delete = False)")
Terence Honles

Posso tornar esse nome de arquivo temporário exclusivo também? para que eu possa salvá-lo mais tarde, quando o subprocesso for concluído com um nome exclusivo
MysticCodes

@Terence Honles: Eu sugeri tempfile.NamedTemporaryFile () originalmente, mas você não pode realmente usar isso para criar arquivos temporários que outros processos podem acessar no Windows. NamedTemporaryFile (delete = False) certamente é mais limpo . @ user343934: tempfile.mkstemp () garante a você um nome único cada vez que é chamado - ele gera os nomes aleatoriamente e usa os recursos do sistema operacional (O_EXCL, se você estiver se perguntando) para evitar colisões.
Richard Barrell

uau, eu não sabia que não funciona no Windows ... falha :( ... Acho que é bom saber
Terence Honles

@Terence Honles: NamedTemporaryFile () não falha no Windows (até onde eu sei), mas você não pode fechar o arquivo sem excluí-lo também, e (pelo que entendi semântica de arquivo no Windows) nenhum outro programa pode abrir o arquivo enquanto você o tem aberto. Eu posso estar errado; a semântica para ter vários processos compartilhando um arquivo no Windows pode ter mudado desde a última verificação.
Richard Barrell

31

O uuidmódulo seria uma boa escolha, prefiro usar uuid.uuid4().hexcomo nome de arquivo aleatório porque retornará uma string hexadecimal sem travessões .

import uuid
filename = uuid.uuid4().hex

As saídas devem ser assim:

>>> import uuid
>>> uuid.uuid()
UUID('20818854-3564-415c-9edc-9262fbb54c82')
>>> str(uuid.uuid4())
'f705a69a-8e98-442b-bd2e-9de010132dc4'
>>> uuid.uuid4().hex
'5ad02dfb08a04d889e3aa9545985e304'  # <-- this one

Qual é o problema de ter travessões?
David Lopez,

15

Talvez você precise de um arquivo temporário exclusivo?

import tempfile

f = tempfile.NamedTemporaryFile(mode='w+b', delete=False)

print f.name
f.close()

f é um arquivo aberto. delete=Falsesignifica não excluir o arquivo após o fechamento.

Se você precisa de controle sobre o nome do arquivo, existem argumentos opcionais prefix=...e suffix=...que aceitam strings. Consulte https://docs.python.org/3/library/tempfile.html .


Isso é ótimo se você não precisa controlar o nome do arquivo.
hiwaylon

1
Deve ser tmpfile.NamedTemporaryFile, não apenas NamedTemporaryFile.
user1993015

w+bé o padrão mode. O uso de qualquer tempfilefuncionalidade tem a desvantagem de permissões de acesso ao arquivo incorretas: tempfiledocumentos a serem usados os.O_TMPFILEcomo máscara, mas a criação normal de arquivos respeita os.umask().
m8mble

8

Você pode usar o módulo datetime

import datetime
uniq_filename = str(datetime.datetime.now().date()) + '_' + str(datetime.datetime.now().time()).replace(':', '.')

Observe que: Estou usando, replacepois os dois pontos não são permitidos em nomes de arquivos em muitos sistemas operacionais.

É isso, isso lhe dará um nome de arquivo único a cada vez.


2
A menos que os nomes dos arquivos sejam criados imediatamente após o outro (por exemplo, em um loop). Então eles são iguais.
skjerns

1

Eu me deparei com esta pergunta e adicionarei minha solução para aqueles que podem estar procurando algo semelhante. Minha abordagem foi apenas fazer um nome de arquivo aleatório a partir de asciicaracteres. Será único com uma boa probabilidade.

from random import sample
from string import digits, ascii_uppercase, ascii_lowercase
from tempfile import gettempdir
from os import path

def rand_fname(suffix, length=8):
    chars = ascii_lowercase + ascii_uppercase + digits

    fname = path.join(gettempdir(), 'tmp-'
                + ''.join(sample(chars, length)) + suffix)

    return fname if not path.exists(fname) \
                else rand_fname(suffix, length)

1
A resposta óbvia para a pergunta tinha a ver com o pacote uuid. No entanto, meu servidor de destino tem python 2.4, nenhum pacote uuid e a atualização não foi autorizada pelo proprietário do servidor devido a incompatibilidades de software legado, então esta resposta funciona para mim.
Alberto Gaona

1
Eu particularmente gosto desta resposta: pode ser facilmente ajustado para as especificações do projeto.
swdev

1
1) Não há razão para usar recursão aqui, especialmente ilimitada. 2) Existe uma condição de corrida entre a hora que path.exists()retorna Falsee a hora em que o consumidor realmente abre o arquivo.
Jonathon Reinhart,

1

Isso pode ser feito usando a função exclusiva no módulo ufp.path .

import ufp.path
ufp.path.unique('./test.ext')

se o caminho atual existir, o arquivo 'test.ext'. retorno da função ufp.path.unique './test (d1) .ext'.


6
ufp faz parte do drupal? não é um módulo padrão
endolith

1

Para criar um caminho de arquivo exclusivo, se houver, use o pacote aleatório para gerar um novo nome de string para o arquivo. Você pode consultar o código abaixo para o mesmo.

import os
import random
import string

def getUniquePath(folder, filename):    
    path = os.path.join(folder, filename)
    while os.path.exists(path):
         path = path.split('.')[0] + ''.join(random.choice(string.ascii_lowercase) for i in range(10)) + '.' + path.split('.')[1]
    return path

Agora você pode usar este caminho para criar o arquivo de acordo.


0

Caso você precise de IDs curtos e exclusivos como nome de arquivo, tente shortuuid, shortuuid usa letras e dígitos em caixa baixa e caixa alta, e remove caracteres de aparência semelhante, como l, 1, I, O e 0.

>>> import shortuuid
>>> shortuuid.uuid()
'Tw8VgM47kSS5iX2m8NExNa'
>>> len(ui)
22

comparado com

>>> import uuid
>>> unique_filename = str(uuid.uuid4())
>>> len(unique_filename)
36
>>> unique_filename
'2d303ad1-79a1-4c1a-81f3-beea761b5fdf'
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.