Python: จะสร้างชื่อไฟล์เฉพาะได้อย่างไร?


95

ฉันมีแบบฟอร์มบนเว็บหลามมีสองตัวเลือก - อัปโหลดไฟล์และtextarea ฉันต้องการรับค่าจากแต่ละค่าและส่งต่อไปยังโปรแกรมบรรทัดคำสั่งอื่น ฉันสามารถส่งชื่อไฟล์ด้วยตัวเลือกการอัปโหลดไฟล์ได้อย่างง่ายดาย แต่ฉันไม่แน่ใจว่าจะส่งค่าของ textarea อย่างไร

ฉันคิดว่าสิ่งที่ฉันต้องทำคือ:

  1. สร้างชื่อไฟล์เฉพาะ
  2. สร้างไฟล์ชั่วคราวด้วยชื่อนั้นในไดเร็กทอรีการทำงาน
  3. บันทึกค่าที่ส่งจาก textarea ลงในไฟล์ชั่วคราว
  4. เรียกใช้โปรแกรม commandline จากภายในโมดูล python ของฉันและส่งชื่อของไฟล์ชั่วคราว

ฉันไม่แน่ใจว่าจะสร้างชื่อไฟล์เฉพาะได้อย่างไร ใครช่วยให้คำแนะนำเกี่ยวกับการสร้างชื่อไฟล์เฉพาะได้ไหม อัลกอริทึมคำแนะนำและบรรทัดของโค้ดจะได้รับการชื่นชม

ขอบคุณสำหรับความกังวลของคุณ


1
ฉันแก้ไขคำถามของคุณเพื่อพยายามทำให้ชัดเจนยิ่งขึ้น โปรดแจ้งให้ฉันทราบหากฉันตีความบางอย่างไม่ถูกต้อง!
culix

คำตอบ:


147

ฉันไม่คิดว่าคำถามของคุณจะชัดเจนนัก แต่ถ้าสิ่งที่คุณต้องการคือชื่อไฟล์เฉพาะ ...

import uuid

unique_filename = str(uuid.uuid4())

ขออภัยฉันกำลังทำงานบนแพลตฟอร์ม windows จึงไม่รู้วิธีจัดการกับกระบวนการย่อย
MysticCodes

ดูเหมือนว่า uuid จะสร้างสตริงที่ยาวไม่ซ้ำกัน ฉันไม่คิดว่าจะดีกว่าที่จะมีชื่อไฟล์ที่มีสตริงยาวและ UUID, () อยู่ในนั้น
MysticCodes

6
ผมคิดว่าuuid.uuid4().hexจะเป็นทางเลือกที่ดีกว่าดูรายละเอียดที่นี่
Grey Li

4
@ToloPalmer: มีแนวโน้มว่า CPU ของคอมพิวเตอร์ของคุณมีข้อผิดพลาดในการประมวลผลที่ทำให้โหลดไฟล์ผิดมากกว่าที่ UUID ที่สร้างขึ้นจะชนกับค่าที่มีอยู่ UUID สร้างชื่อเฉพาะในแบบจำลองของคอมพิวเตอร์ที่เข้าใจว่าการคำนวณไม่ใช่คณิตศาสตร์ล้วน ๆ
GManNickG

2
ให้อภัยความคิดเห็นเก่าที่ไม่รู้ของฉัน ... อันที่จริงไม่ซ้ำกัน แต่ไม่น่าจะชนกันมากทางเลือกที่ดี;)
Tolo Palmer

51

หากคุณต้องการสร้างไฟล์ชั่วคราวใน Python มีโมดูลที่เรียกว่าtempfileในไลบรารีมาตรฐานของ Python หากคุณต้องการเปิดโปรแกรมอื่น ๆ เพื่อดำเนินการกับไฟล์ให้ใช้ tempfile.mkstemp () เพื่อสร้างไฟล์และ os.fdopen () เพื่อเข้าถึงตัวอธิบายไฟล์ที่ mkstemp () ให้คุณ

บังเอิญคุณบอกว่าคุณกำลังเรียกใช้คำสั่งจากโปรแกรม Python? คุณควรจะใช้โมดูลกระบวนการย่อย

ดังนั้นคุณสามารถเขียนโค้ดที่ดูเหมือน:

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)

เมื่อเรียกใช้คุณจะพบว่าcatคำสั่งทำงานได้ดี แต่ไฟล์ชั่วคราวถูกลบในfinallyบล็อก โปรดทราบว่าคุณต้องลบไฟล์ชั่วคราวที่ mkstemp () ส่งคืนด้วยตัวเอง - ไลบรารีไม่มีทางรู้ว่าคุณทำเสร็จแล้ว

(แก้ไข: ฉันเคยสันนิษฐานว่า NamedTem ContemporaryFile ทำในสิ่งที่คุณต้องการ แต่อาจไม่สะดวกนัก - ไฟล์จะถูกลบทันทีเมื่อปิดวัตถุไฟล์ชั่วคราวและมีกระบวนการอื่น ๆ เปิดไฟล์ก่อนที่คุณจะปิด จะไม่ทำงานในบางแพลตฟอร์มโดยเฉพาะ Windows ขออภัยล้มเหลวในส่วนของฉัน)


การใช้NamedTem ContemporaryFileอาจเป็นสิ่งที่พวกเขาต้องการ (เว้นแต่ว่าพวกเขาต้องการให้อยู่บนเซิร์ฟเวอร์จากนั้นพวกเขาสามารถใช้ "tempfile.NamedTem ContemporaryFile (delete = False)")
Terence Honles

ฉันสามารถทำให้ชื่อไฟล์ชั่วคราวนั้นไม่ซ้ำกันได้หรือไม่? ดังนั้นฉันจึงสามารถบันทึกได้ในภายหลังเมื่อกระบวนการย่อยเสร็จสมบูรณ์ด้วยชื่อเฉพาะ
MysticCodes

@Terence Honles: ฉันแนะนำ tempfile.NamedTem ContemporaryFile () แต่เดิมคุณไม่สามารถใช้มันเพื่อสร้างไฟล์ชั่วคราวที่กระบวนการอื่น ๆ สามารถเข้าถึงบน Windows NamedTemporaryFile (ลบ = false) แน่นอนทำความสะอาดแม้ว่า @ user343934: tempfile.mkstemp () รับประกันว่าจะให้ชื่อที่ไม่ซ้ำกับคุณทุกครั้งที่มีการเรียกมันจะสร้างชื่อแบบสุ่มและใช้สิ่งอำนวยความสะดวกของระบบปฏิบัติการ (O_EXCL หากคุณสงสัย) เพื่อหลีกเลี่ยงการชนกัน
Richard Barrell

ว้าวฉันไม่รู้ว่ามันใช้ไม่ได้กับ windows ... ล้มเหลว :( ... ฉันเดาว่าน่ารู้
Terence Honles

@Terence Honles: NamedTem ContemporaryFile () ไม่ได้ล้มเหลวใน Windows (เท่าที่ฉันรู้) แต่คุณไม่สามารถปิดไฟล์ได้โดยไม่ต้องลบมันเช่นกันและ (ตามที่ฉันเข้าใจความหมายของไฟล์บน Windows) ไม่มีโปรแกรมอื่นใดสามารถเปิด ไฟล์ในขณะที่คุณเปิด ฉันอาจจะผิด; ความหมายสำหรับการมีหลายกระบวนการที่แชร์ไฟล์ภายใต้ Windows อาจมีการเปลี่ยนแปลงตั้งแต่ฉันตรวจสอบครั้งล่าสุด
Richard Barrell

32

uuidโมดูลจะเป็นทางเลือกที่ดีผมชอบที่จะใช้uuid.uuid4().hexเป็นชื่อไฟล์สุ่มเพราะมันจะกลับสตริงฐานสิบหกโดยไม่ต้องขีดกลาง

import uuid
filename = uuid.uuid4().hex

ผลลัพธ์ควรเป็นดังนี้:

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

1
ปัญหาของการมีขีดกลางคืออะไร?
David Lopez

15

บางทีคุณอาจต้องการไฟล์ชั่วคราวที่ไม่ซ้ำใคร

import tempfile

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

print f.name
f.close()

f ถูกเปิดไฟล์ delete=Falseหมายถึงอย่าลบไฟล์หลังจากปิด

หากคุณต้องการควบคุมชื่อไฟล์มีทางเลือกprefix=...และsuffix=...อาร์กิวเมนต์ที่ใช้สตริง ดูhttps://docs.python.org/3/library/tempfile.html


วิธีนี้ดีมากถ้าคุณไม่จำเป็นต้องควบคุมชื่อไฟล์
hiwaylon

1
ควรเป็น tmpfile.NamedTem ContemporaryFile ไม่ใช่แค่ NamedTem ContemporaryFile
user1993015

w+bmodeเป็นค่าเริ่มต้น โดยใช้tempfileฟังก์ชันการทำงานที่มีข้อเสียของสิทธิ์การเข้าถึงไฟล์ที่ไม่ถูกต้อง: tempfileเอกสารที่จะใช้os.O_TMPFILEเป็นหน้ากาก os.umask()แต่ปกติประการการสร้างแฟ้ม
m8mble

8

คุณสามารถใช้datetimeโมดูล

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

โปรดทราบว่า: ฉันใช้replaceเนื่องจากไม่อนุญาตให้ใช้เครื่องหมายโคลอนในชื่อไฟล์ในหลายระบบปฏิบัติการ

เท่านี้ก็จะทำให้คุณมีชื่อไฟล์ที่ไม่ซ้ำกันทุกครั้ง


2
เว้นแต่ชื่อไฟล์จะถูกสร้างขึ้นหลังกัน (เช่นในการวนซ้ำ) จากนั้นก็เหมือนกัน
skjerns

1

ฉันเจอคำถามนี้และจะเพิ่มคำตอบสำหรับผู้ที่อาจกำลังมองหาสิ่งที่คล้ายกัน แนวทางของฉันคือสร้างชื่อไฟล์แบบสุ่มจากasciiตัวละคร มันจะไม่เหมือนใครด้วยความน่าจะเป็นที่ดี

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
คำตอบที่ชัดเจนสำหรับคำถามนั้นเกี่ยวข้องกับแพ็คเกจ uuid อย่างไรก็ตามเซิร์ฟเวอร์เป้าหมายของฉันมี python 2.4 ไม่มีแพ็คเกจ uuid และการอัพเกรดไม่ได้รับอนุญาตจากเจ้าของเซิร์ฟเวอร์เนื่องจากซอฟต์แวร์เดิมเข้ากันไม่ได้ดังนั้นคำตอบนี้จึงเหมาะกับฉัน
Alberto Gaona

1
ฉันชอบคำตอบนี้เป็นพิเศษ: สามารถปรับแต่งรายละเอียดโครงการได้อย่างง่ายดาย
swdev

1
1) ไม่มีเหตุผลที่จะใช้การเรียกซ้ำที่นี่โดยเฉพาะอย่างยิ่งไม่ถูกผูกไว้ 2) มีเงื่อนไขการแย่งชิงระหว่างเวลาที่path.exists()ส่งคืนFalseและเวลาที่ผู้บริโภคเปิดไฟล์จริง
Jonathon Reinhart

1

สามารถทำได้โดยใช้ฟังก์ชันเฉพาะในโมดูลufp.path

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

หากเส้นทางปัจจุบันมีไฟล์ 'test.ext' ฟังก์ชัน ufp.path.unique return './test (d1) .ext'.


6
ufp เป็นส่วนหนึ่งของ drupal? ไม่ใช่โมดูลมาตรฐาน
endolith

1

หากต้องการสร้างพา ธ ไฟล์เฉพาะหากมีอยู่ให้ใช้แพ็กเกจแบบสุ่มเพื่อสร้างชื่อสตริงใหม่สำหรับไฟล์ คุณสามารถอ้างอิงโค้ดด้านล่างนี้ได้

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

ตอนนี้คุณสามารถใช้เส้นทางนี้เพื่อสร้างไฟล์ตามนั้น


1

ในกรณีที่คุณต้องมี ID ที่ไม่ซ้ำกันสั้น ๆ เป็นชื่อไฟล์ของคุณลองshortuuid, shortuuidใช้ตัวพิมพ์เล็กและตัวอักษรตัวพิมพ์ใหญ่และตัวเลขและลบอักขระที่คล้ายกันเช่นลิตร, 1, I, O และ 0

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

เปรียบเทียบกับ

>>> import uuid
>>> unique_filename = str(uuid.uuid4())
>>> len(unique_filename)
36
>>> unique_filename
'2d303ad1-79a1-4c1a-81f3-beea761b5fdf'
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.