Шаг 171.
Основы языка Python.
Работа с файлами и каталогами. Перенаправление ввода/вывода

    На этом шаге мы рассмотрим способы перенаправления ввода/вывода.

    При рассмотрении методов для работы с файлами говорилось, что значение, возвращаемое методом fileno(), всегда будет больше числа 2, т. к. число 0 закреплено за стандартным вводом stdin, 1 - за стандартным выводом stdout, a 2 - за стандартным выводом сообщений об ошибках stderr. Все эти потоки имеют некоторое сходство с файловыми объектами. Например, потоки stdout и stderr поддерживают метод write(), предназначенный для вывода сообщений, а поток stdin - метод readline(), служащий для получения вводимых пользователем данных. Если этим потокам присвоить ссылку на объект, поддерживающий файловые методы, то можно перенаправить стандартные потоки в соответствующий файл. Для примера так и сделаем.

>>> import sys                  # Подключаем модуль sys
>>> tmp_out  = sys.stdout       # Сохраняем ссылку на sys.stdout
>>> f = open (r"file.txt", "a") # Открываем файл на дозапись
>>> sys.stdout  = f             # Перенаправляем вывод в файл
>>> print ("Пишем строку в файл")
>>> sys.stdout = tmp_out        # Восстанавливаем стандартный вывод
>>> print ("Пишем строку в стандартный вывод")
Пишем строку в стандартный вывод
>>> f.close ()                  # Закрываем файл

    В этом примере мы вначале сохранили ссылку на стандартный вывод в переменной tmp_out. С помощью этой переменной можно в дальнейшем восстановить вывод в стандартный поток.

    Функция print() напрямую поддерживает перенаправление вывода. Для этого используется параметр file, который по умолчанию ссылается на стандартный поток вывода. Например, записать строку в файл можно так:

>>> f = open(r"file.txt", "a")
>>> print ("Пишем строку в файл", file=f)
>>> f.close ()

    Параметр flush, поддержка которого появилась в Python 3.3, позволяет указать, когда следует выполнять непосредственное сохранение данных из промежуточного буфера в файл. Если его значение равно False (это, кстати, значение по умолчанию), сохранение будет выполнено лишь после закрытия файла или после вызова метода flush(). Чтобы указать интерпретатору Python выполнять сохранение после каждого вызова функции print(), следует присвоить этому параметру значение True. Пример:

>>> f = open(r"file.txt", "a")
>>> print ("Пишем строку в файл", file = f, flush = True)
>>> print ("Пишем другую строку в файл", file = f, flush = True)
>>> f .close ()

    Стандартный ввод stdin также можно перенаправить. В этом случае функция input() будет читать одну строку из файла при каждом вызове. При достижении конца файла возбуждается исключение EOFError. Для примера выведем содержимое файла с помощью перенаправления потока ввода:

# -*- coding: utf-8 -*-
import sys
tmp_in = sys.stdin          # Сохраняем ссылку на sys. stdin
f = open(r"file.txt", "r")  # Открываем файл на чтение
sys.stdin = f	            # Перенаправляем ввод
while True:
    try:
        line = input()	# Считываем строку из файла
        print(line)	# Выводим строку
    except EOFError:	# Если достигнут конец файла,
        break           # выходим из цикла
sys.stdin = tmp_in	# Восстанавливаем стандартный ввод
f.close()               # Закрываем файл
input ()
Архив с файлом можно взять здесь.

    Результат работы приложения:

String1
String2
Пишем строку в файл
Пишем строку в файл

    Если необходимо узнать, ссылается ли стандартный ввод на терминал или нет, можно воспользоваться методом isatty(). Метод возвращает True, если объект ссылается на терминал, и False - в противном случае. Примеры:

>>> tmp_in = sys.stdin # Сохраняем ссыпку на sys.stdin
>>> f = open(r"file.txt", "r")
>>> sys.stdin = f      # Перенаправляем ввод
>>> sys.stdin.isatty() # He ссылается на терминал
False
>>> sys.stdin = tmp_in # Восстанавливаем стандартный ввод
>>> sys.stdin.isatty() # Ссылается на терминал
True
>>> f.close ()         #  Закрываем файл

    Перенаправить стандартный ввод/вывод можно также с помощью командной строки. Для примера создадим в папке C:\book файл tests.py со следующим кодом:

# -*- coding: utf-8 -*-
import sys
tmp_in = sys.stdin          # Сохраняем ссылку на sys. stdin
f = open(r"file.txt", "r")  # Открываем файл на чтение
sys.stdin = f	            # Перенаправляем ввод
while True:
    try:
        line = input()	# Считываем строку из файла
        print(line)	# Выводим строку
    except EOFError:	# Если достигнут конец файла,
        break           # выходим из цикла
sys.stdin = tmp_in	# Восстанавливаем стандартный ввод
f.close()               # Закрываем файл
input ()
Архив с файлами можно взять здесь.

    Запускаем командную строку и переходим в папку со скриптом, выполнив команду: cd C:\book. Теперь выведем содержимое созданного ранее текстового файла file.txt (его содержимое может быть любым), выполнив команду:

  C:\Python34\python.exe tests.ру < file.txt   

    Перенаправить стандартный вывод в файл можно аналогичным образом. Только в этом случае символ < необходимо заменить символом >. Изменим файл tests.ру следующим образом:

# -*- coding: utf-8  -*-
print("String") # Эта строка будет записана в файл
Архив с файлом можно взять здесь.

    Теперь перенаправим вывод в файл file.txt, выполнив команду:

  C:\Python34\python.exe tests.py > file.txt

    В этом режиме файл file.txt будет перезаписан. Если необходимо добавить результат в конец файла, следует использовать символы >>. Пример дозаписи в файл:

  C:\Python34\python.exe tests.py >> file.txt

    С помощью стандартного вывода stdout можно создать индикатор выполнения процесса непосредственно в окне консоли. Чтобы реализовать такой индикатор, нужно вспомнить, что символ перевода строки в Windows состоит из двух символов: \r (перевод каретки) и \n (перевод строки). Таким образом, используя только символ перевода каретки \r, можно перемещаться в начало строки и перезаписывать ранее выведенную информацию. Рассмотрим вывод индикатора процесса на примере:

# -*- coding: utf-8  -*-
import sys, time
for i in range(5, 101, 5):
    sys.stdout.write("\r ... %s%%" % i) # Обновляем индикатор
    sys.stdout.flush()	                # Сбрасываем содержимое буфера
    time.sleep(1)	                # Засыпаем на 1 секунду
    sys.stdout.write("\rПроцесс завершен\n")
input ()
Архив с файлом можно взять здесь.

    Сохраняем код в файл и запускаем его с помощью двойного щелчка. В окне консоли записи будут заменять друг друга на одной строке каждую секунду (рисунок 1).


Рис.1. Результат работы приложения (показаны выборочные итерации)

    Так как данные перед выводом будут помещаться в буфер, мы сбрасываем их на диск явным образом с помощью метода flush().

    На следующем шаге мы рассмотрим сохранение объектов в файл.




Предыдущий шаг Содержание Следующий шаг