สร้างชื่อไฟล์ชั่วคราวโดยไม่ต้องสร้างไฟล์จริงใน Python


107

คำถามหมายเลข 10501247ใน stackoverflow ให้คำตอบเกี่ยวกับวิธีสร้างไฟล์ชั่วคราวใน Python
ฉันต้องมีชื่อไฟล์ชั่วคราวในกรณีของฉันเท่านั้น
การเรียกใช้ tempfile.NamedTem ContemporaryFile () ส่งคืนหมายเลขอ้างอิงของไฟล์หลังจากการสร้างไฟล์จริง
มีวิธีรับเฉพาะชื่อไฟล์หรือไม่?

# 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')
...

7
NamedTemporaryFileรับประกันชื่อเฉพาะ (อาจ) โดยลองใช้และลองอีกครั้งหากมีอยู่ การได้รับเพียงชื่อไม่สามารถรับประกันได้ว่าคุณสามารถสร้างไฟล์ได้จริงในภายหลังคุณกำลังเปิดรับสภาพการแข่งขันของคนอื่นที่ใช้ชื่อเดียวกันก่อนหน้าคุณ
Joachim Isaksson

5
@ Joachim True มีสภาพการแข่งขันที่นี่และเป็นที่ต้องการหลีกเลี่ยงสิ่งนั้น อย่างไรก็ตามบางครั้งคุณต้องส่งชื่อไฟล์ชั่วคราวไปยังฟังก์ชัน (ไฟล์ที่เปิดอยู่ภายใน) การมีชื่อแบบสุ่มให้โอกาสที่ดีกว่ามากที่สภาพการแข่งขันจะไม่เป็นปัญหา ฉันคิดว่ามีความจำเป็นที่จะต้องระบุชื่อไฟล์ชั่วคราวที่ดีเพื่อลดโอกาสที่จะเกิดความล้มเหลวของเงื่อนไขการแข่งขัน แน่นอนว่าการเพิ่มคำนำหน้าและคำต่อท้ายที่ดีตามกระบวนการทำงานและงานที่กำลังดำเนินการจะช่วยให้มีโอกาสเกิดการชนกันน้อยลง
PolyMesh

@PolyMesh คุณสามารถหลีกเลี่ยงสภาวะการแย่งชิงได้โดยการสร้างไดเร็กทอรีชั่วคราวจากนั้นใช้ไฟล์ชื่อคงที่ภายใน ดังนั้นฟังก์ชันของคุณจึงยอมรับไดเร็กทอรีแทนที่จะเป็นไฟล์และจะสร้างไฟล์เดียวกันเสมอ
DylanYoung

ใช้ tarfile และส่ง fileobj
Wyrmwood

คำตอบ:


68

หากคุณต้องการชื่อไฟล์ temp คุณเท่านั้นที่สามารถเรียกใช้ฟังก์ชัน tempfile ภายใน_get_candidate_names():

import tempfile

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

โทรnextอีกครั้งจะกลับชื่ออื่นเป็นต้นซึ่งไม่ได้ให้เส้นทางไปยังโฟลเดอร์ temp หากต้องการรับไดเร็กทอรี 'tmp' เริ่มต้นให้ใช้:

defult_tmp_dir = tempfile._get_default_tempdir()
% results in: /tmp 

3
วิธีที่ดีกว่าในการสร้างไดเร็กทอรีชั่วคราวคือการtemp_dir = tempfile.mkdtemp(prefix='some-prefix_')สร้างไดเร็กทอรีชั่วคราวอย่างปลอดภัยและส่งคืนสตริงด้วยพา ธ สัมบูรณ์
Emanuel Ey

4
สิ่งสำคัญคือต้องชี้ให้เห็นว่าnext(tempfile._get_candidate_names())ไม่จำเป็นต้องส่งคืนเส้นทางที่ไม่มีอยู่นั่นเป็นเหตุผลที่อินเทอร์เฟซ tempfile ระดับผู้ใช้สามารถลองชื่อได้หลายชื่อจนกว่าจะพบชื่อที่ไม่ได้ใช้ :
Eli Korvigo

1
หนึ่งสามารถใช้ประชาชนแทนส่วนตัวtempfile.gettempdir() tempfile._get_default_tempdir()
flonk

@EmanuelEy สิ่งสำคัญที่ต้องจำไว้เมื่อใช้tempfile.mkdtempงานผู้ใช้มีหน้าที่รับผิดชอบในการลบไดเรกทอรีชั่วคราวและเนื้อหาเมื่อดำเนินการเสร็จสิ้น
Daniel Braun

49

ฉันคิดว่าวิธีที่ง่ายและปลอดภัยที่สุดในการทำสิ่งนี้คือ:

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

ไดเร็กทอรีชั่วคราวถูกสร้างขึ้นเพื่อให้คุณเข้าถึงได้เท่านั้นดังนั้นจึงไม่ควรมีปัญหาด้านความปลอดภัย แต่จะไม่มีไฟล์ที่สร้างขึ้นดังนั้นคุณสามารถเลือกชื่อไฟล์ที่คุณต้องการสร้างในไดเร็กทอรีนั้นได้

แก้ไข: ใน Python 3 ตอนนี้คุณสามารถใช้tempfile.TemporaryDirectory()เป็นตัวจัดการบริบทเพื่อจัดการการลบให้คุณได้:

with tempfile.TemporaryDirectory() as tmp:
  path = os.path.join(tmp, 'something')
  # use path

1
ดังที่ Daniel Braun กล่าวไว้ข้างต้น: สิ่งสำคัญที่ต้องจำไว้ว่าเมื่อใช้tempfile.mkdtempงานผู้ใช้มีหน้าที่รับผิดชอบในการลบไดเรกทอรีชั่วคราวและเนื้อหาเมื่อทำเสร็จแล้ว
bitinerant

5
หากคุณใช้tempfile.TemporaryDirectory()เป็นตัวจัดการบริบทระบบจะลบให้คุณ
gerrit

17

อาจจะสายนิดหน่อย แต่มีอะไรผิดปกติหรือไม่?

import tempfile
with tempfile.NamedTemporaryFile(dir='/tmp', delete=False) as tmpfile:
    temp_file_name = tmpfile.name
f = gzip.open(temp_file_name ,'wb')

40
without creating actual file in Pythonรหัสนี้จริงจะสร้างแฟ้มชั่วคราวเพื่อให้ได้รับชื่อของมันในขณะที่คำถามที่มันบอกว่า
Jakub Kukul

สิ่งนี้ไม่ตอบคำถาม
herve

ทำงานให้ฉันอย่างสมบูรณ์แบบ ขอขอบคุณ!
shargors

10

tempfile.mktemp() ทำเช่นนี้.

แต่โปรดทราบว่าเลิกใช้แล้ว อย่างไรก็ตามจะไม่สร้างไฟล์และเป็นฟังก์ชันสาธารณะใน tempfile เมื่อเทียบกับการใช้ไฟล์_get_candidate_names().

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


1
“ แม้ว่ามันจะล้มเหลว แต่ก็ยอมรับได้”; สภาพการแข่งขันไม่ได้เป็นเพียงความเสี่ยงต่อความล้มเหลว แต่เป็นความเสี่ยงด้านความปลอดภัย (ดูtempfile.mktempเอกสารประกอบ) ดังนั้นจึงไม่ควรถือว่าเป็นที่ยอมรับ
bignose

6
@bignose เป็นปัญหาด้านความปลอดภัยที่อาจเกิดขึ้น ขึ้นอยู่กับสิ่งที่คุณต้องการทำสภาพแวดล้อมการดำเนินการที่คุณอยู่ ฯลฯ ที่กล่าวไว้: การทำบางอย่างอาจปลอดภัยos.path.join(tempfile.mkdtemp(), 'something')กว่าอย่างน้อยก็มีการสร้างไดเร็กทอรีขึ้น (และเป็นของคุณฉันคิดว่า)
Alec

5

เมื่อรวมคำตอบก่อนหน้านี้ทางออกของฉันคือ:

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

กำหนดsome_idทางเลือกหากไม่จำเป็นสำหรับคุณ


อีกครั้งอาจไม่มีชื่อผู้สมัครจริง นี่คือคำตอบที่ถูกต้อง: stackoverflow.com/a/45803022/6387880
j4hangir

1
อย่างไรก็ตามมีแนวโน้มว่าจะต้องสร้างชื่อแบบสุ่ม อย่างไรก็ตามเพื่อให้แน่ใจว่าหาก_get_candidate_names()ไม่มีอยู่เราสามารถตั้งค่าเริ่มต้นเป็นตัวสร้างสตริงกึ่งสุ่มได้ ตัวอย่างเช่น uuid
juanmirocks

4

ดังที่ Joachim Isaksson กล่าวในความคิดเห็นหากคุณได้รับชื่อคุณอาจมีปัญหาหากมีโปรแกรมอื่นใช้ชื่อนั้นก่อนที่โปรแกรมของคุณจะทำ โอกาสที่จะผอม แต่ไม่เป็นไปไม่ได้

ดังนั้นสิ่งที่ปลอดภัยที่จะทำในสถานการณ์เช่นนี้คือการใช้ GzipFile () GzipFile( [filename[, mode[, compresslevel[, fileobj]]]])คอนสตรัคเต็มรูปแบบซึ่งมีลายเซ็น ดังนั้นคุณสามารถส่งไฟล์ open fileobj และชื่อไฟล์ได้เช่นกันหากต้องการ ดูรายละเอียดในเอกสาร gzip

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.