Reputation: 1273
I know that it is possible to create a temporary file, and write the data of the file I wish to copy to it. I was just wondering if there was a function like:
create_temporary_copy(file_path)
Upvotes: 26
Views: 34937
Reputation: 7897
I wanted a more generic context manager which can copy files to the temp dir. In case this helps anyone with this issue:
from contextlib import contextmanager
from pathlib import Path
from shutil import copytree
from tempfile import TemporaryDirectory
from typing import Iterator
@contextmanager
def temporary_directory(source_dir: Path | None = None) -> Iterator[Path]:
"""Create a tempory directory for use within this context, yield its path, and purge on exit.
Args:
source_dir (Path | None, optional): A path to a directory to copy to the temporary
directory. Defaults to None.
Raises:
FileNotFoundError: Raised if source_dir is passed but does not exist or was not found.
ValueError: Raised if source_dir is passed but is to a file, not a directory.
Yields:
Iterator[Path]: The path to the temporary directory with the source directory
files within it.
"""
if source_dir is not None and not source_dir.exists():
raise FileNotFoundError(f"{source_dir!s} does not exist")
if source_dir is not None and not source_dir.is_dir():
raise ValueError(f"{source_dir!s} is not a directory")
with TemporaryDirectory() as temp_dir:
if source_dir is not None:
copytree(source_dir, temp_dir, dirs_exist_ok=True)
yield Path(temp_dir).absolute()
Upvotes: 0
Reputation: 31
You can try this to create a temporary file and then a copy. I like to set delete=False in case I need to do something to the temp file before creating the copy. The temp file is then closed manually and thus deleted:
import shutil, tempfile, os
temp_file = tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False)
#Do something to temp file
shutil.copyfile('copy_name.txt', temp_file.name)
temp_file.close()
Upvotes: 0
Reputation: 361
The following is more concise (OP's ask) than the selected answer. Enjoy!
import tempfile, shutil, os
def create_temporary_copy(path):
tmp = tempfile.NamedTemporaryFile(delete=True)
shutil.copy2(path, tmp.name)
return tmp.name
Upvotes: 8
Reputation: 177
This isn't quite as concise, and I imagine there may be issues with exception safety, (e.g. what happens if 'original_path' doesn't exist, or the temporary_copy object goes out of scope while you have the file open) but this code adds a little RAII to the clean up. The difference here to using NamedTemporaryFile directly is that rather than ending up with a file object, you end up with a file, which is occasionally desirable (e.g. if you plan to call out to other code to read it, or some such.)
import os,shutil,tempfile
class temporary_copy(object):
def __init__(self,original_path):
self.original_path = original_path
def __enter__(self):
temp_dir = tempfile.gettempdir()
base_path = os.path.basename(self.original_path)
self.path = os.path.join(temp_dir,base_path)
shutil.copy2(self.original_path, self.path)
return self.path
def __exit__(self,exc_type, exc_val, exc_tb):
os.remove(self.path)
in your code you'd write:
with temporary_copy(path) as temporary_path_to_copy:
... do stuff with temporary_path_to_copy ...
# Here in the code, the copy should now have been deleted.
Upvotes: 16
Reputation: 9853
A variation on @tramdas's answer, accounting for the fact that the file cannot be opened twice on windows. This version ignores the preservation of the file extension.
import os, shutil, tempfile
def create_temporary_copy(src):
# create the temporary file in read/write mode (r+)
tf = tempfile.TemporaryFile(mode='r+b', prefix='__', suffix='.tmp')
# on windows, we can't open the the file again, either manually
# or indirectly via shutil.copy2, but we *can* copy
# the file directly using file-like objects, which is what
# TemporaryFile returns to us.
# Use `with open` here to automatically close the source file
with open(src,'r+b') as f:
shutil.copyfileobj(f,tf)
# display the name of the temporary file for diagnostic purposes
print 'temp file:',tf.name
# rewind the temporary file, otherwise things will go
# tragically wrong on Windows
tf.seek(0)
return tf
# make a temporary copy of the file 'foo.txt'
name = None
with create_temporary_copy('foo.txt') as temp:
name = temp.name
# prove that it exists
print 'exists', os.path.isfile(name) # prints True
# read all lines from the file
i = 0
for line in temp:
print i,line.strip()
i += 1
# temp.close() is implicit using `with`
# prove that it has been deleted
print 'exists', os.path.isfile(name) # prints False
Upvotes: 6
Reputation: 448
A slight variation (in particular I needed the preserve_extension
feature for my use case, and I like the "self-cleanup" feature):
import os, shutil, tempfile
def create_temporary_copy(src_file_name, preserve_extension=False):
'''
Copies the source file into a temporary file.
Returns a _TemporaryFileWrapper, whose destructor deletes the temp file
(i.e. the temp file is deleted when the object goes out of scope).
'''
tf_suffix=''
if preserve_extension:
_, tf_suffix = os.path.splitext(src_file_name)
tf = tempfile.NamedTemporaryFile(suffix=tf_suffix)
shutil.copy2(src_file_name, tf.name)
return tf
Upvotes: 0
Reputation: 6166
There isn't one directly, but you can use a combination of tempfile
and shutil.copy2
to achieve the same result:
import tempfile, shutil, os
def create_temporary_copy(path):
temp_dir = tempfile.gettempdir()
temp_path = os.path.join(temp_dir, 'temp_file_name')
shutil.copy2(path, temp_path)
return temp_path
You'll need to deal with removing the temporary file in the caller, though.
Upvotes: 30