Программирование на Python: Часть 8. Файловая система

В этой статье мы узнаем как работать с файлами и файловой системой.

Сергей Яковлев, Консультант, независимый специалист

Яковлев Сергей — независимый разработчик с многолетним опытом прикладного и системного программирования; вносит вклад в развитие open-source на своем персональном сайте www.iakovlev.org. Консультант.



02.09.2010

После изучения классов в Python мы перейдем к работе с файлами и файловой системой. Функции и объекты, описанные в этой главе, позволят вам сохранять данные между вызовами программы, а также обмениваться данными между программами.

Сегодня мы рассмотрим следующие темы.

  1. Как открыть файл.
  2. Базовые файловые методы.
  3. Стандартный ввод/вывод.
  4. Произвольный доступ.
  5. Построчная работа с файлами.
  6. Закрытие файла.
  7. Итерация.
  8. Pickling.
  9. Бинарные файлы – модуль struct.
  10. Работа с файловой системой.

1. Как открыть файл

Открыть файл можно с помощью функции open:

  open(name[, mode[, buffering]])

Функция возвращает файловый объект. Обязателен только первый аргумент. Если остальные параметры отсутствуют, файл будет доступен на чтение. Таблица режимов (mode) функции open:

'r' – чтение.

'w' – запись.

'a' – добавление.

'b' – бинарный режим.

'+' – чтение/запись.

Режим '+' может быть добавлен к остальным режимам. По умолчанию питон открывает файлы в текстовом режиме. Для открытия файла в бинарном режиме на чтение можно добавить 'rb'. Третий параметр устанавливает размер буферизации при работе с файлом. По умолчанию он выключен, и чтение/запись идет напрямую с диска на диск. Для включения буфера третий параметр должен быть отличным от нуля.


2. Базовые файловые методы

В питоне многие объекты являются файлами: стандартный ввод sys.stdin, стандартный вывод sys.stdout, объекты, открываемые функцией urllib.urlopen и т.д.

Запись в файл:

>>> f = open('my_file', 'w')
>>> f.write('Hello, ')
>>> f.write('World!')
>>> f.close()

Чтение:

>>> f = open('my_file', 'r')
>>> f.read(5)
'Hello'
>>> f.read()
', World!'

3. Стандартный ввод/вывод

В командной строке можно записать подряд несколько команд, передавая результат работы от одной команды к другой по конвейеру – или по каналу (pipe):

  cat my_file | python test.py

Первая команда – cat – пишет содержимое текстового файла my_file на стандартный вывод sys.stdout . Вторая команда запускает питоновский файл, который читает стандартный ввод sys.stdin , подсчитывает в нем количество слов и выводит результат:

test.py:
import sys
text = sys.stdin.read()
words = text.split()
wordcount = len(words)
print 'Wordcount:', wordcount

Канал – или пайп (pipe) – это конструкция, объединяющая стандартный вывод со стандартным вводом и позволяющая обмениваться данными между двумя командами.


4. Произвольный доступ

По умолчанию метод read() читает данные последовательно по порядку, от начала и до конца файла. Для произвольного доступа к файлу есть функция seek:

  seek(offset[, whence])

offset – смещение в байтах относительно начала файла;

whence – по умолчанию равен нулю, указывает на то, что смещение берется относительно начала файла.

Пример:

>>> f = open(r'my_file', 'w')
>>> f.write('01234567890123456789')
>>> f.seek(5)
>>> f.write('Hello, World!')
>>> f.close()
>>> f = open(r'my_file')
>>> f.read()
'01234Hello, World!89'

Функция tell() возвращает текущую позицию файла.


5. Построчная работа с файлами

Обычно мы имеем дело с текстовыми файлами. Прочитать одну строку:

  file.readline()

Функция readline() без параметра читает всю строку, наличие параметра указывает функции максимальное число символов строки, которое будет прочитано. Прочитать все строки и вернуть список строк:

  file.readlines()

Записать строки в файл:

  file.writelines()

Пример. Прочитать файл и записать его содержимое в другой файл:

f = open(r'my_file')
lines = f.readlines()
f.close()
lines[0] = "This is a my_file2 \n" # изменяем 1-ю строку
f = open(r'my_file2','w')
f.writelines(lines)
f.close()

6. Закрытие файла

Для закрытия файла есть метод close(). Обычно файл закрывается сам после того, как вы выходите из программы, но файлы нужно закрывать вручную по нескольким причинам.

  1. Питон может буферизировать запись в файл ваших данных, что может привести к неожиданным эффектам и возникновению ошибок.
  2. У операционной системы есть ограничение на число одновременно открытых файлов.
  3. При доступе к файлу из разных мест одновременно и на чтение, и на запись необходимо синхронизировать файловые операции. Буферизация записи может привести к тому, что запись уже произошла, а данных в файле еще нет.

Для полной уверенности в закрытии файла можно использовать блок try/finally:

  try:
     # Тут идет запись в файл
  finally:
     file.close()

Можно также использовать менеджер контекста, который в любом случае закроет файл:

 with open("my_file") as somefile:
    do_something(somefile)

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


7. Итерация

Итерация по файлу является базовой операцией и имеет множество вариантов. Использование функции read() для байтового чтения:

f = open(filename)
while True:
  char = f.read(1)
  if not char: break
  process(char)
f.close()

Построчное чтение текстовых файлов и функция readline():

f = open(filename)
while True:
  line = f.readline()
  if not line: break
  process(line)
f.close()

Файл сам может выступать в роли итератора:

for line in open(filename):
  process(line)

8. Pickling

Практически любой тип объекта может быть сохранен на диске в любой момент его жизни, а позже прочитан с диска. Для этого есть модуль pickle:

import pickle
t1 = [1, 2, 3]
s = pickle.dumps(t1)
t2 = pickle.loads(s)
print t2
[1, 2, 3]

Здесь есть небольшой нюанс: t1 и t2 будут двумя разными объектами, хотя и идентичными.


9. Бинарные файлы

Стандартный модуль struct позволяет преобразовывать объекты в структуры C в виде строк в бинарном формате и обратно. Данные в строке располагаются в соответствии со строкой формата. Эти возможности могут быть использованы для чтения и сохранения в двоичном формате.

Функции этого модуля:

   pack(format, value1, value2 ...)

Возвращает строку, содержащую значения value1 ..., упакованные в соответствии с форматом. Количество и тип аргументов должны соответствовать значениям, которые требует строка формата format.

   unpack(format, string)

Распаковывает строку string в соответствии с форматом format и возвращает кортеж объектов.

   calcsize(format)

Возвращает размер структуры (т.е. длину строки), соответствующей формату format.

Таблица основных форматов
===========================
Format      C Type          Python 	
===========================
c             char               string of length 1 	 
?             Bool              bool 	
i 	   int                  integer 	 
l 	   long               integer 	 
f 	   float               float 	 
d 	   double           float 	 
s 	   char[]            string

Перед символом формата может идти число, обозначающее количество повторений. Например, строка формата '4h' полностью эквивалентна строке 'hhhh'. Символы пропуска между символами формата игнорируются, однако символы пропуска между числом и символом формата не допускаются.

Число перед символом формата 's' интерпретируется как длина строки, а не число повторений. То есть '10s' обозначает строку из 10 символов, в то время как '10c' – 10 раз по одному символу.

Можно изменить порядок следования байтов вручную:

  < - little-endian
  > - big-endian

В следующем примере мы упаковываем в структуру два числа – целое и float, строку из пяти символов, сохраняем в бинарный файл, а потом извлекаем из файла:

from struct import *
out = open("123.bin", "wb")    
format = "if5s"                
data   = pack(format, 24,12.48,'12345')
out.write(data)
out.close()
input = open("123.bin", "rb")
data = input.read()
input.close()
format = "if5s"                   # one integer
value,value2,value3 = unpack(format, data) # note the ',' in 'value,': 
	unpack apparently returns a n-uple
print value
print value2
print value3
print calcsize(format)

>>> 24
>>> 12.4799995422
>>> 12345
>>> 13

10. Работа с файловой системой

Стандартный модуль os имеет интерфейс работы с файловой системой. Каждая программа имеет текущий каталог. Функция os.getcwd возвращает текущий каталог:

import os
cwd = os.getcwd()
print cwd

Проверить наличие файла в текущем каталоге:

  os.path.exists('my_file')

Вывести список файлов и подкаталогов для данного каталога:

  os.listdir(path)

Следующий пример рекурсивно выводит список всех файлов и подкаталогов для данного каталога:

import os
def walk(dir):
  for name in os.listdir(dir):
    path = os.path.join(dir, name)
    if os.path.isfile(path):
        print path
    else:
        walk(path)
walk(path)

В следующем примере мы получим статистическую информацию о текущем каталоге: общий размер каталога в байтах, число файлов, число подкаталогов. Стандартная функция os.path.walk имеет три параметра: каталог, пользовательская функция, список для подсчета:

import os, sys
def getlocaldata(sms,dr,flst):
   for f in flst:
      fullf = os.path.join(dr,f)
      if os.path.islink(fullf): continue # don't count linked files
      if os.path.isfile(fullf):
          sms[0] += os.path.getsize(fullf)
          sms[1] += 1
      else:
          sms[2] += 1
def dtstat(dtroot):
   sums = [0,0,1] # 0 bytes, 0 files, 1 directory so far
   os.path.walk(dtroot,getlocaldata,sums)
   return sums

report = dtstat('.')
print report

В следующем примере сделана интерпретация системной утилиты grep. В текущем каталоге будут найдены файлы с питоновским расширением, в которых будет найдена поисковая строка 'import os':

import os, sys, fnmatch

mask = '*.py'
pattern = 'import os'

def walk(arg,dir,files):
   for file in files:
     if fnmatch.fnmatch(file,mask):
        name = os.path.join(dir,file)
        try:
          data = open(name,'rb').read()
          if data.find(pattern) != -1:
            print name
        except:
            pass    
os.path.walk('.',walk,[])

Заключение

Сегодня мы узнали, что файловые объекты поддерживают чтение/запись. Для корректной работы с данными файл нужно программно закрывать. Файлы можно открывать в различных режимах. Стандартный ввод/вывод – это тоже файлы. Можно построчно читать и писать в файл. К файлам можно применять байтовую и построчную итерацию. Любые объекты могут быть сохранены на диске в произвольный момент времени в произвольном состоянии и позже восстановлены путем считывания с диска. Чтение/запись можно выполнять в бинарном режиме, соблюдая совместимость со структурами на языке си. Интерфейс с операционной системой позволяет писать компактные программы, дополняющие стандартные утилиты операционной системы.

Приведенные примеры проверены на версии питона 2.6.

< Предыдущая статья. Следующая статья >

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Linux, Open source
ArticleID=515163
ArticleTitle=Программирование на Python: Часть 8. Файловая система
publish-date=09022010