Python pathlib копирование файлов
. как скопировать файл с помощью pathlib в Python 2.7?
ОТВЕТЫ
Ответ 1
Так что по этому поводу?
Проблема в том, что pathlib.Path создайте объект PosixPath , если вы используете Unix/Linux, WindowsPath , если вы используете Microsoft Windows.
Но shutil.copy() принимает строку в качестве аргумента. Так что просто используйте функцию str() здесь, когда вы используете функцию str() для объекта Path , он вернет путь, который объект Path называет строкой.
Ответ 2
Причина для shutil.copy() не работает в том, что вы не используете последние Python, Python 3.6 shutil.copy() можете обрабатывать объекты Path (или их подклассы). Для более старых версий Python это вызывает ошибку, потому что в тех реализациях shutil ожидаются строковые аргументы для аргументов типа copy , а не pathlib.Path .
На самом деле вы хотите написать:
Вы можете подклассифицировать Path для включения такого метода и адаптировать создание my_file . Мне легче просто трансформировать/обезьяна-патч/утка-пробить его на существующий pathlib.Path
Вы можете поместить этот код в любом месте, пока он выполняется, до вызова метода .copy в любом из экземпляров Path . Аргумент .copy() может быть файлом или каталогом.
Ответ 3
Начиная с Python 3.5, без импорта shutil , вы можете сделать:
Для Python 2.7 pathlib2 предоставляет read_bytes , read_text , write_bytes и write_text .
Файл будет загружен в память, поэтому этот метод не подходит для файлов, размер которых превышает доступную для машин память.
Согласно комментариям, можно использовать write_bytes и read_bytes для копирования текстовых файлов, но если вам нужно иметь дело с кодировкой во время копирования write_text , read_text предоставляет преимущество двух дополнительных параметров:
- encoding - это имя кодировки, используемой для декодирования или кодирования файла.
- errors - это необязательная строка, которая определяет, как должны обрабатываться ошибки кодирования и декодирования.
Они оба имеют то же значение, что и в open() .
Ответ 4
Как shutil был преобразован для принятия pathlib.Path объектов в Python 3.6
Поскольку это казалось довольно волшебным, я решил немного изучить, как это реализовано, чтобы увидеть, смогу ли я использовать это волшебство в своих собственных классах.
Объект, представляющий путь к файловой системе. Объект, подобный пути, - это либо объект str или bytes, представляющий путь, либо объект, реализующий протокол os.PathLike. Объект, который поддерживает протокол os.PathLike, может быть преобразован в путь файловой системы str или bytes путем вызова функции os.fspath(); os.fsdecode() и os.fsencode() могут использоваться для гарантии результата str или bytes, соответственно. Представлено PEP 519.
Абстрактный базовый класс для объектов, представляющих путь к файловой системе, например, pathlib.PurePath.
Новое в версии 3.6.
abstractmethod __fspath__()
Возвращает представление пути к файловой системе объекта.
Метод должен возвращать только объект str или bytes, причем предпочтение отдается str.
Ключевые коммиты реализации выглядят так:
-
, который в основном изменяет точку манипуляции пути самого низкого уровня в Modules/posixmodule.c , который добавляет __fspath__ к pathlib.PurePath
Если вы хотите реализовать свои собственные классы, подобные путям, вы можете сделать это следующим образом:
Протестировано в Python 3.6.7, Ubuntu 18.10.
Ответ 5
Вы можете использовать метод переименования pathlib вместо shutil.move().
The problem is pathlib.Path create a PosixPath object if you're using Unix/Linux, WindowsPath if you're using Microsoft Windows.
With older versions of Python, shutil.copy requires a string as its arguments. For them, use the str function here.
Don't take this personal: I though pathlib was made to make things easier. I guess I stick with using plain old strings like I used to do.
I would also have expected Pathlib to be able to copy a file, given that it can move/rename and unlink/delete files.
@AndrewWagner the difference, if I had to guess, is that moving and deleting files are purely filesystem operations, where you just update filesystem metadata. Copying involves actually writing out new data, so maybe the pathlib people thought it was out of scope.
If anyone is wondering why shutil.move doesn't work the same way in Python
The cause for shutil.copy() not working is that you are not using the latest Python, Python 3.6 shutil.copy() can handle Path objects (or subclasses thereof). That for older versions of Python this throws an error is because those implementations of shutil expect string arguments for copy , and not pathlib.Path type arguments.
What you actually want to be able to write is:
You can subclass Path to include such a method, and adapt the creation of my_file . I find it easier to just graft/monkey-patch/duck-punch it on the existing pathlib.Path
You can put this code anywhere you like, as long as it gets executed before calling the .copy method on any of the Path instances. The argument to .copy() can be a file or a directory.
I'd say pathlib does not provide this functionality because that's not what it's meant for - just as os.path was not meant for file handling itself. The module's functionality is about file handling and file's metadata, but not about file handling, as far as I know.
@mr.zog I don't think your intended audience will get notified that you wrote a comment when you just put in a name. You should consult the help on formatting of comments where it clearly states to use the @ character
@Bram Vanroy "The module's functionality is about file handling and file's metadata, but not about file handling" is a bit contradictory. What did you intend to convey?
Although Path is primarily designed to represent a file path, it also provides mkdir() and exists() and such, so it is natural to expect it to do a lot of what shutil does. A proper separation of concerns would probably have Path and File and Folder with File/Folder being created from a Path and File have getPath() etc. Then once you have a File or Folder it's pretty obvious it makes sense to have copy(), copytree() etc on those objects instead of on Path. I use Path everywhere I can, btw.
Since Python 3.5, without importing shutil , you can do:
For Python 2.7, pathlib2 provides the read_bytes , read_text , write_bytes and write_text methods.
The file will be loaded in memory, so this method is not suitable for files larger than the machines available memory.
As per the comments, one can use write_bytes and read_bytes to copy text files, but if you need to deal with the encoding at copy time write_text an read_text present the advantage of two extra parameters:
- encoding is the name of the encoding used to decode or encode the file
- errors is an optional string that specifies how encoding and decoding errors are to be handled
They both have the same meaning as in open() .
With this method a sufficiently large file would crash Python with a MemoryError . shutil.copy doesn't have this problem because it uses shutil.copyfileobj which buffers larger files into smaller chunks.
This copies the file's contents, but not file permissions, ownership, access policies, or other file metadata. OP's comment actually says that s/he wants to "copy the file," not just the data it contains.
How shutil was converted to accept pathlib.Path objects in Python 3.6
As mentioned at in this answer, shutil in Python 3.6 can take pathlib.Path objects.
Since this felt quite magic, I decided to investigate a little bit how it was implemented to see if I would be able to reuse this magic on my own classes.
The improvement was a result of PEP 519.
This generalized a lot of stdlib functionality, and documentation was not consistently updated as a result, including most of shutil which as of 3.7 only documents support in a single function. Welcome to the joys of dynamic typing.
Where documented, the stlib links to the glossary for "path-like objects".
An object representing a file system path. A path-like object is either a str or bytes object representing a path, or an object implementing the os.PathLike protocol. An object that supports the os.PathLike protocol can be converted to a str or bytes file system path by calling the os.fspath() function; os.fsdecode() and os.fsencode() can be used to guarantee a str or bytes result instead, respectively. Introduced by PEP 519.
and that then links to the documentation of os.PathLike :
An abstract base class for objects representing a file system path, e.g. pathlib.PurePath.
New in version 3.6.
abstractmethod __fspath__()
Return the file system path representation of the object.
The method should only return a str or bytes object, with the preference being for str.
shutil has many methods you can use. One of which is:
- Copy the contents of the file named src to a file named dst . Both src and dst need to be the entire filename of the files, including path.
- The destination location must be writable; otherwise, an IOError exception will be raised.
- If dst already exists, it will be replaced.
- Special files such as character or block devices and pipes cannot be copied with this function.
- With copy , src and dst are path names given as str s.
Another shutil method to look at is shutil.copy2() . It's similar but preserves more metadata (e.g. time stamps).
If you use os.path operations, use copy rather than copyfile . copyfile will only accept strings.
@Owen Indeed it can, but the directory has to already exist. By the way, as long as the target directory already exists, dst can either end or not end with a trailing slash, it doesn't matter.
shutil does not actually copy files. There's a big fat warning right at the top of the docs. "this means that file owner and group are lost as well as ACLs. On Mac OS, the resource fork and other metadata are not used. This means that resources will be lost and file type and creator codes will not be correct. On Windows, file owners, ACLs and alternate data streams are not copied."
Function | Copies metadata | Copies permissions | Uses file object | Destination may be directory |
---|---|---|---|---|
shutil.copy | No | Yes | No | Yes |
shutil.copyfile | No | No | No | No |
shutil.copy2 | Yes | Yes | No | Yes |
shutil.copyfileobj | No | No | Yes | No |
copy2(src,dst) is often more useful than copyfile(src,dst) because:
- it allows dst to be a directory (instead of the complete target filename), in which case the basename of src is used for creating the new file;
- it preserves the original modification and access info (mtime and atime) in the file metadata (however, this comes with a slight overhead).
Here is a short example:
I am trying to randomly copy 100k files from 1 million files. copyfile is considerably faster than copy2
In Python, you can copy the files using
1) Копирование файлов с помощью shutil модуля
shutil.copyfile подпись
shutil.copy подпись
shutil.copy2 подпись
shutil.copyfileobj подпись
2) Copying files using os module
os.popen signature
os.system signature
3) Копирование файлов с помощью subprocess модуля
subprocess.call подпись
Использование однострочных команд - плохой стиль кодирования (гибкость, надежность и безопасность), вместо этого используйте ['copy', sourcefile, destfile] синтаксис везде, где это возможно, особенно если параметры вводятся пользователем.
os.popen устарела в течение некоторого времени. и check_output не возвращает статус, но вывод (который в случае пуст copy/cp )
shutil на самом деле не копирует файлы. Там в большом предупреждении жира прямо в верхней части документации . "это означает, что теряются владелец файла и группа, а также списки управления доступом. В Mac OS вилка ресурсов и другие метаданные не используются. Это означает, что ресурсы будут потеряны, а тип файла и коды создателя будут неправильными. В Windows владельцы файлов, списки управления доступом и альтернативные потоки данных не копируются ».
Копирование файла - относительно простая операция, как показано в примерах ниже, но вместо этого вы должны использовать для этого модуль shutil stdlib .
Если вы хотите скопировать по имени файла, вы можете сделать что-то вроде этого:
Некоторое время назад я заметил, что модуль называется shutil (единственное число), а не shutils (множественное число), и действительно, он находится в Python 2.3. Тем не менее, я оставляю эту функцию здесь в качестве примера.
Скопируйте содержимое файла с именем src в файл с именем dst. Место назначения должно быть доступно для записи; в противном случае возникнет исключение IOError. Если dst уже существует, он будет заменен. Специальные файлы, такие как символьные или блочные устройства и каналы, не могут быть скопированы с помощью этой функции. src и dst - имена путей, заданные в виде строк.
Взгляните на filesys для всех функций обработки файлов и каталогов, доступных в стандартных модулях Python.
Пример копирования каталога и файла - из материалов Тима Голдена о Python:
Во-первых, я сделал для вас исчерпывающий перечень методов shutil.
Во-вторых, объясните методы копирования в примерах:
- shutil.copyfileobj(fsrc, fdst[, length]) manipulate opened objects
- shutil.copyfile(src, dst, *, follow_symlinks=True) Copy and rename
- shutil.copy() Copy without preseving the metadata
- shutil.copy2() Copy with preseving the metadata
Рекурсивно копировать все дерево каталогов с корнем src, возвращая целевой каталог
Для небольших файлов и использования только встроенных модулей Python вы можете использовать следующий однострочный файл:
Как упоминалось в комментариях @maxschlepzig ниже, это не оптимальный способ для приложений, где файл слишком велик или когда память критична, поэтому следует отдавать предпочтение ответу Свати .
Вы могли бы использовать os.system('cp nameoffilegeneratedbyprogram /otherdirectory/')
или как я это сделал,
где rawfile имя, которое я создал внутри программы.
Это решение только для Linux
Начиная с Python 3.5 для небольших файлов (например, текстовых файлов, небольших файлов в формате JPEG) можно делать следующее:
write_bytes перезапишет все, что было в месте назначения
А затем кто-то использует код (случайно или намеренно) в большом файле . Использование функций из shutil обрабатывает все особые случаи за вас и дает вам душевное спокойствие.
Для больших файлов я прочитал файл построчно и прочитал каждую строку в массив. Затем, когда массив достигнет определенного размера, добавьте его в новый файл.
это кажется немного избыточным, поскольку писатель должен обрабатывать буферизацию. for l in open('file.txt','r'): output.write(l) должен работать найти; просто настройте буфер выходного потока в соответствии с вашими потребностями. или вы можете пройти по байтам, перебирая попытку с помощью output.write(read(n)); output.flush() где n - количество байтов, которое вы хотите записать за раз. у обоих из них также нет условия для проверки того, что является бонусом.
Да, но я подумал, что, возможно, это будет легче понять, потому что он копирует целые строки, а не их части (на случай, если мы не знаем, сколько байтов в каждой строке).
Это ужасно. Он выполняет ненужную работу без уважительной причины. Это не работает для произвольных файлов. Копия не идентична байтам, если входные данные имеют необычные окончания строк в таких системах, как Windows. Как вы думаете, почему это может быть проще для понимания, чем вызов функции копирования в shutil ? Даже при игнорировании shutil простой цикл чтения / записи блоков (с использованием небуферизованного ввода-вывода) прост, был бы эффективным и имел бы гораздо больше смысла, чем этот, и, следовательно, его, безусловно, легче обучить и понять.
3) Copying files using subprocess module
subprocess.call signature
Using single-string commands is bad coding style (flexibility, reliability and security), instead use ['copy', sourcefile, destfile] syntax wherever possible, especially if the parameters are from user input.
shutil is built-in, no need to provide non-portable alternatives. The answer could be actually improved by removing the system dependent solutions, and after that removal, this answer is just a copy of the existing answers / a copy of the documentation.
os.popen is deprecated for a while now. and check_output doesn't return the status but the output (which is empty in the case of copy/cp )
shutil does not actually copy files. There's a big fat warning right at the top of the docs. "this means that file owner and group are lost as well as ACLs. On Mac OS, the resource fork and other metadata are not used. This means that resources will be lost and file type and creator codes will not be correct. On Windows, file owners, ACLs and alternate data streams are not copied."
You can use one of the copy functions from the shutil package:
Copying a file is a relatively straightforward operation as shown by the examples below, but you should instead use the shutil stdlib module for that.
If you want to copy by filename you could do something like this:
I noticed a while ago that the module is called shutil (singular) and not shutils (plural), and indeed it is in Python 2.3. Nevertheless I leave this function here as an example.
Copy the contents of the file named src to a file named dst. The destination location must be writable; otherwise, an IOError exception will be raised. If dst already exists, it will be replaced. Special files such as character or block devices and pipes cannot be copied with this function. src and dst are path names given as strings.
Take a look at filesys for all the file and directory handling functions available in standard Python modules.
Directory and File copy example - From Tim Golden's Python Stuff:
For small files and using only python built-ins, you can use the following one-liner:
This is not optimal way for applications where the file is too large or when memory is critical, thus Swati's answer should be preferred.
Firstly, I made an exhaustive cheatsheet of shutil methods for your reference.
Secondly, explain methods of copy in exmaples:
- shutil.copyfileobj(fsrc, fdst[, length]) manipulate opened objects
- shutil.copyfile(src, dst, *, follow_symlinks=True) Copy and rename
- shutil.copy() Copy without preseving the metadata
- shutil.copy2() Copy with preseving the metadata
Recursively copy an entire directory tree rooted at src, returning the destination directory
You could use os.system('cp nameoffilegeneratedbyprogram /otherdirectory/')
where rawfile is the name that I had generated inside the program.
This is a Linux only solution
As of Python 3.5 you can do the following for small files (ie: text files, small jpegs):
write_bytes will overwrite whatever was at the destination's location
And then someone uses the code (accidentally or purposefully) on a large file… Using functions from shutil handles all the special cases for you and gives you peace of mind.
For large files, what I did was read the file line by line and read each line into an array. Then, once the array reached a certain size, append it to a new file.
this seems a little redundant since the writer should handle buffering. for l in open('file.txt','r'): output.write(l) should work find; just setup the output stream buffer to your needs. or you can go by the bytes by looping over a try with output.write(read(n)); output.flush() where n is the number of bytes you'd like to write at a time. both of these also don't have an condition to check which is a bonus.
Yes, but I thought that maybe this could be easier to understand because it copies entire lines rather than parts of them (in case we don't know how many bytes each line is).
This is awful. It does unnecessary work for no good reason. It doesn't work for arbitrary files. The copy isn't byte-identical if the input has unusual line endings on systems like Windows. Why do you think that this might be easier to understand than a call to a copy function in shutil ? Even when ignoring shutil , a simple block read/write loop (using unbuffered IO) is straight forward, would be efficient and would make much more sense than this, and thus is surely easier to teach and understand.
Проблема заключается в том, чтобы pathlib.Path создать PosixPath объект, если вы используете Unix/Linux, WindowsPath если вы используете Microsoft Windows.
В более старых версиях Python shutil.copy в качестве аргументов требуется строка. Для них используйте str функцию здесь.
@guettli На самом деле, если вы используете my_file.as_posix() Windows, он вернет C:/etc/hosts . Так что это не имеет значения.
Не принимайте это близко к сердцу: я думал, что pathlib был создан, чтобы упростить задачу. Думаю, я придерживаюсь старых простых струн, как раньше.
Я также ожидал, что Pathlib сможет скопировать файл, учитывая, что он может перемещать/переименовывать и отсоединять/удалять файлы.
@AndrewWagner разница, если мне пришлось догадаться, заключается в том, что перемещение и удаление файлов - это чисто операции с файловой системой, когда вы просто обновляете метаданные файловой системы. Копирование включает в себя запись новых данных, поэтому, возможно, разработчики pathlib думали, что это выходит за рамки.
Если кому-то интересно, почему Shutil.move не работает так же в Python
Причина shutil.copy() того, что вы не работаете, заключается в том, что вы не используете последнюю версию Python, Python 3.6 shutil.copy() может обрабатывать Path объекты (или их подклассы). То, что для более старых версий Python это вызывает ошибку, связано с тем, что эти реализации shutil ожидают строковых аргументов для copy , а не pathlib.Path аргументов типа.
То, что вы на самом деле хотите написать, это:
Вы можете создать подкласс Path, чтобы включить такой метод, и адаптировать создание my_file . Я считаю, что проще просто привить/залатать обезьяной/утиным перфоратором на существующем pathlib.Path
Вы можете разместить этот код где угодно, если он выполняется до вызова .copy метода в любом из Path экземпляров. Аргументом .copy() может быть файл или каталог.
Я бы сказал, что pathlib не предоставляет эту функциональность, потому что это не то, для чего она предназначена - точно так же, как os.path она не предназначена для самой обработки файлов. Функциональность модуля связана с обработкой файлов и метаданными файлов, но не об обработке файлов, насколько мне известно.
@ mr.zog Я не думаю, что ваша целевая аудитория получит уведомление о том, что вы написали комментарий, когда просто введете имя. Вам следует обратиться к справке по форматированию комментариев , где четко указано, что нужно использовать @ символ
@Bram Vanroy «Функциональность модуля связана с обработкой файлов и метаданными файла, но не с обработкой файлов» немного противоречива. Что вы хотели донести?
Хотя Path в первую очередь предназначен для представления пути к файлу, он также предоставляет mkdir() и exists() и тому подобное, поэтому естественно ожидать, что он будет делать многое из того, что делает Shutil. Правильное разделение проблем, вероятно, будет иметь путь, файл и папку с файлом/папкой, созданным из пути, а файл имеет getPath() и т. д. Затем, когда у вас есть файл или папка, совершенно очевидно, что имеет смысл иметь copy(), copytree() и т. д. для этих объектов, а не для пути. Я использую Path везде, где могу, кстати.
Начиная с Python 3.5, без импорта shutil вы можете сделать:
Для Python 2.7 pathlib2 предоставляет методы read_bytes , read_text и write_bytes . write_text
Файл будет загружен в память, поэтому этот метод не подходит для файлов, размер которых превышает объем доступной памяти машины.
Согласно комментариям, можно использовать write_bytes и read_bytes для копирования текстовых файлов, но если вам нужно иметь дело с кодировкой во время копирования write_text , read_text используйте два дополнительных параметра:
- encoding имя кодировки, используемой для декодирования или кодирования файла
- errors необязательная строка, указывающая, как должны обрабатываться ошибки кодирования и декодирования.
Оба они имеют то же значение, что и в open() .
С помощью этого метода достаточно большой файл приведет к сбою Python с расширением MemoryError . shutil.copy у него нет этой проблемы, потому что он использует shutil.copyfileobj , который буферизует большие файлы в более мелкие фрагменты.
При этом копируется содержимое файла , но не права доступа к файлу, права собственности, политики доступа или другие метаданные файла . Комментарий OP на самом деле говорит, что он / она хочет «скопировать файл», а не только содержащиеся в нем данные.
Как shutil было преобразовано для приема pathlib.Path объектов в Python 3.6
Как уже упоминалось в этом ответе , Shutil в Python 3.6 может принимать pathlib.Path объекты.
Поскольку это выглядело довольно волшебно, я решил немного изучить, как это было реализовано, чтобы посмотреть, смогу ли я повторно использовать это волшебство в своих собственных классах.
Улучшение было результатом PEP 519 .
Там, где это задокументировано, stlib ссылается на глоссарий для «путеподобных объектов» .
An object representing a file system path. A path-like object is either a str or bytes object representing a path, or an object implementing the os.PathLike protocol. An object that supports the os.PathLike protocol can be converted to a str or bytes file system path by calling the os.fspath() function; os.fsdecode() and os.fsencode() can be used to guarantee a str or bytes result instead, respectively. Introduced by PEP 519.
и затем ссылки на документацию os.PathLike :
An abstract base class for objects representing a file system path, e.g. pathlib.PurePath.
New in version 3.6.
abstractmethod __fspath__()
Return the file system path representation of the object.
The method should only return a str or bytes object, with the preference being for str.
Ключевые коммиты реализации выглядят следующим образом:
-
, который в основном изменяет точку манипулирования путями самого низкого уровня в Modules/posixmodule.c , что добавляет __fspath__ к pathlib.PurePath
Если вы хотите реализовать свои собственные классы, подобные пути, вы можете сделать это так:
shutil есть много методов, которые вы можете использовать. Один из них:
- Скопируйте содержимое файла с именем src в файл с именем dst . Оба src и dst должны быть полными именами файлов, включая путь.
- Место назначения должно быть доступно для записи; в противном случае IOError возникнет исключение.
- Если он dst уже существует, он будет заменен.
- Специальные файлы, такие как символьные или блочные устройства и каналы, не могут быть скопированы с помощью этой функции.
- С copy , src и dst - имена путей, заданные как str s.
Другой shutil способ посмотреть - это shutil.copy2() . Он похож, но сохраняет больше метаданных (например, отметок времени).
Если вы используете os.path операции, используйте copy вместо copyfile . copyfile будет принимать только строки.
Обратите внимание, что это не атомарная операция. Будьте осторожны, используя его в многопоточном приложении.
Обратите внимание, что он не может обрабатывать такие сокращения, как ~ , но он может работать с относительными путями
Функция | Копирует метаданные | Разрешения на копирование | Использует файловый объект | Назначением может быть каталог |
---|---|---|---|---|
shutil.copy | Нет | да | Нет | да |
shutil.copyfile | Нет | Нет | Нет | Нет |
shutil.copy2 | да | да | Нет | да |
shutil.copyfileobj | Нет | Нет | да | Нет |
copy2(src,dst) часто бывает полезнее, чем copyfile(src,dst) потому, что:
- это позволяет dst быть каталог (вместо полного целевого файла), в этом случае базовый из src используются для создания нового файла;
- он сохраняет исходную информацию о модификации и доступе (mtime и atime) в метаданных файла (однако это связано с небольшими накладными расходами).
Вот небольшой пример:
Я пытаюсь случайным образом скопировать 100k файлов из 1 миллиона файлов. copyfile значительно быстрее, чем copy2
Вы можете использовать одну из функций копирования из shutil пакета:
@lightalchemist Я просто использовал vim в качестве блокнота, скопировал использованные символы Unicode из таблицы википедии и скопировал результат в редактор stackoverflow для окончательной полировки.
OK. YMMV, но я думаю, что косметические изменения и подобные незначительные улучшения лучше вносить в существующие ответы, а не дублировать их.
В Python вы можете копировать файлы, используя
2) Копирование файлов с помощью os модуля
os.popen подпись
os.system подпись
1) Copying files using shutil module
shutil.copyfile signature
shutil.copy signature
shutil.copy2 signature
shutil.copyfileobj signature
Читайте также: