Разрезание файлов переносимым способом

razrezanie fajlov perenosimym sposobom Законченные системные программы

Так как на всех компьютерах в моем доме стоит Python, на помощь приходит простой переносимый сценарий на этом языке. В примере 6.5 приводится программа на языке Python, которая распределяет содержимое одного файла по группе файлов меньшего размера, которые сохраняются в каталоге.

Пример 6.5. PP4E\System\Filetools\split.py

#!/usr/bin/python

############################################################################## разрезает файл на несколько частей; сценарий join.py объединяет эти части в один файл; данный сценарий является настраиваемой версией стандартной команды split в Unix; поскольку сценарий написан на языке Python, он с тем же успехом может использоваться в Windows и легко может быть модифицирован; благодаря тому, что он экспортирует функцию, его логику можно импортировать и повторно использовать в других приложениях;

##############################################################################

import sys, os kilobytes = 1024

megabytes = kilobytes * 1000 chunksize = int(1.4 * megabytes) # по умолчанию: примерный размер дискеты

def split(fromfile, todir, chunksize=chunksize):

if not os.path.exists(todir): # ошибки обрабатывает вызвавший

os.mkdir(todir) # создать каталог для фрагментов

else:

for fname in os.listdir(todir): # удалить все существующие файлы os.remove(os.path.join(todir, fname))

partnum = 0 input = open(fromfile, ‘rb’) # двоичный режим: без декодирования и

# без преобразования символов конца # строки

while True: # eof = прочтена пустая строка

chunk = input.read(chunksize) # прочитать кусок <= chunksize if not chunk: break partnum += 1 filename = os.path.join(todir, (‘part%04d% partnum)) fileobj = open(filename, ‘wb’) fileobj.write(chunk) fileobj.close() # или просто open().write()

input.close() assert partnum <= 9999 # сортировка в join невозможна,

return partnum # если будет 5 цифр

if __name__ == ‘__main__’:

if len(sys.argv) == 2 and sys.argv[1] == ‘-help’: print(‘Use: split.py [file-to-split target-dir [chunksize]]’) else:

if len(sys.argv) < 3: interactive = True fromfile = input(‘File to be split? ‘) # ввод данных, если # запущен щелчком мыши todir = input(‘Directory to store part files? ‘) else:

interactive = False fromfile, todir = sys.argv[1:3] # аргументы командной строки if len(sys.argv) == 4: chunksize = int(sys.argv[3]) absfrom, absto = map(os.path.abspath, [fromfile, todir]) print(‘Splitting’, absfrom, ‘to’, absto, ‘by’, chunksize)

try:

parts = split(fromfile, todir, chunksize) except:

print(‘Error during split:’)

print(sys.exc_info()[0], sys.exc_info()[1]) else:

print(‘Split finished:’, parts, ‘parts are in’, absto) if interactive: input(‘Press Enter key’) # пауза, если сценарий # запущен щелчком мыши

По умолчанию этот сценарий разрезает исходный файл на фрагменты, примерно равные размеру дискеты, — идеальные для перемещения больших файлов между не связанными между собой компьютерами. Самое важное здесь — это полностью переносимый программный код; данный сценарий будет работать на любом компьютере, где нет своей встроенной программы для разрезания файлов. Главное, чтобы на компьютере был установлен интерпретатор Python. Ниже приводится пример использования этого сценария для разрезания самоустанавливаю- щегося выполняемого файла Python 3.1 в Windows в текущем каталоге (для экономии места я опустил некоторые строки, которые выводит команда dir; в Unix воспользуйтесь командой lsl):

C:\temp> cd C:\temp

C:\temp> dir python-3.1.msi …часть строк опущена… 06/27/2009 04:53 PM 13,814,272 python-3.1.msi

1 File(s) 13,814,272 bytes

0 Dir(s) 188,826,189,824 bytes free

C:\temp> python C:\\PP4E\System\Filetools\split.py -help

Use: split.py [file-to-split target-dir [chunksize]]

C:\temp> python C:\\P4E\System\Filetools\split.py python-3.1.msi pysplit

Splitting C:\temp\python-3.1.msi to C:\temp\pysplit by 1433600

Split finished: 10 parts are in C:\temp\pysplit

C:\temp> dir pysplit

часть строк опущена

02/21/2010

11

:13 AM

<DIR> .

02/21/2010

11

:13 AM

<DIR> ..

02/21/2010

11

:13 AM

1,433,600 part0001

02/21/2010

11

:13 AM

1,433,600 part0002

02/21/2010

11

:13 AM

1,433,600 part0003

02/21/2010

11

:13 AM

1,433,600 part0004

02/21/2010

11

:13 AM

1,433,600 part0005

02/21/2010

11

:13 AM

1,433,600 part0006

02/21/2010

11

:13 AM

1,433,600 part0007

02/21/2010

11

:13 AM

1,433,600 part0008

02/21/2010

11

:13 AM

1,433,600 part0009

02/21/2010

11

:13 AM

911,872 part0010

 

10 File(s)

2 Dir(s)

13,814,272 bytes 188,812,328,960 bytes free

Каждый из

созданных здесь файлов фрагментов представляет один

двоичный кусок файла python-3.1.msi, достаточно маленький, чтобы поместиться на одной дискете. Действительно, если сложить вместе размеры созданных фрагментов, показанные командой dir, то получится точно то же число байтов, что и в оригинальном файле. Прежде чем пытаться снова сложить вместе эти файлы, рассмотрим несколько примечаний, касающихся сценария.

Режимы работы

Данный сценарий может получать свои параметры в интерактивном режиме или в режиме командной строки — он проверяет количество аргументов командной строки, чтобы определить, в каком режиме используется. В режиме командной строки сценарию передаются имя файла, который нужно разрезать, и каталог для сохранения фрагментов. При этом с помощью необязательного третьего аргумента можно переопределить установленный по умолчанию размер одного фрагмента.

В интерактивном режиме сценарий запрашивает имя файла и каталог для сохранения фрагментов в окне консоли с помощью функции input и перед завершением делает остановку, ожидая нажатия клавиши. Этот режим используется, когда программа запускается щелчком на значке файла, — в Windows параметры вводятся во всплывающем окне DOS, которое в этом случае не исчезает автоматически. Сценарий также показывает абсолютные пути для своих параметров (пропуская их через os.path.abspath), потому что в интерактивном режиме они могут быть не очевидны.

Двоичный режим доступа к файлам

Этот сценарий открывает входные и выходные файлы в двоичном режиме (rb, wb), потому что такие файлы, как выполняемые или аудиофайлы, должны обрабатываться переносимым способом, не как текст. В главе 4 мы узнали, что в Windows при работе с текстовыми файлами символы конца строки \r\n автоматически отображаются в \n при вводе, и \n отображается в \r\n при выводе. При работе с двоичными данными было бы нежелательно, чтобы \r исчезали при чтении и ненужные символы \r попадали бы при записи в выходной файл. Для файлов, открываемых в двоичном режиме в Windows, такая трансформация символа \r не производится, и искажения данных не происходит.

Кроме того, в Python 3.X при работе с файлами в двоичном режиме данные в сценарии представляются в виде объектов bytes, а не в виде кодированного текста str. При этом нам даже не приходится предусматривать выполнение каких-то особых действий — операции по обработке файлов, реализованные в сценарии, действуют одинаково и в Python 3.X, и в Python 2.X. Фактически двоичный режим является обязательным для версии 3.X, потому что данные, записываемые в выходной файл, вообще могут не быть текстом — текстовый режим необходим в версии 3.X, только когда приходится выполнять декодирование содержимого файла, которое может приводить к ошибкам при работе с настоящими двоичными файлами и с текстовыми файлами, полученными из других систем. Операция записи в двоичном режиме принимает объект типа bytes и подавляет кодирование символов Юникода, а также преобразование символов конца строки.

Закрытие файлов вручную

Этот сценарий также заботится о том, чтобы вручную закрыть используемые им файлы. Как мы видели в главе 4, часто это можно сделать одной строкой: open(partname, ‘wb’).write(chunk). Эта более короткая форма использует тот факт, что в текущей реализации Python файлы автоматически закрываются при уничтожении объектов файлов (то есть при утилизации их на этапе сборки мусора, когда не остается ссылок на объект файла). В этой строке объект файла будет уничтожен немедленно, потому что результат open является в выражении временным и ссылка на него не сохраняется в какой-либо долгоживущей переменной. Аналогично при выходе из функции split уничтожается объект файла input.

Однако есть вероятность, что такой режим автоматического закрытия в будущем может измениться. Более того, в Jython — реализации Python на языке Java — объекты, на которые нет ссылок, не уничтожаются с такой же поспешностью, как в стандартной реализации Python. Если сейчас или в будущем вам может потребоваться перейти на Java, а ваш сценарий в состоянии создать много файлов за короткий промежуток времени и, возможно, будет выполняться в системе, которая ограничивает количество открытых файлов в каждой программе, закрывайте файлы вручную. Поскольку функция split в этом модуле задумана как универсальный инструмент, в ней учтены варианты такого наихудшего развития событий. В главе 4 также упоминался менеджер контекста файла и инструкция with — они обеспечивают альтернативный способ гарантированного закрытия файлов.

Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, I том, 2011

Оцените статью
Секреты программирования
Добавить комментарий