Как перенаправить вывод 'print' в файл, используя python? - PullRequest
137 голосов
/ 22 августа 2011

Я хочу перенаправить печать в файл .txt, используя python.У меня есть цикл for, который будет «печатать» выходные данные для каждого из моих файлов .bam, в то время как я хочу перенаправить ВСЕ эти выходные данные в один файл.Поэтому я попытался поставить

 f = open('output.txt','w'); sys.stdout = f

в начале моего сценария.Однако я ничего не получаю в файле .txt.Мой сценарий:

#!/usr/bin/python

import os,sys
import subprocess
import glob
from os import path

f = open('output.txt','w')
sys.stdout = f

path= '/home/xug/nearline/bamfiles'
bamfiles = glob.glob(path + '/*.bam')

for bamfile in bamfiles:
    filename = bamfile.split('/')[-1]
    print 'Filename:', filename
    samtoolsin = subprocess.Popen(["/share/bin/samtools/samtools","view",bamfile],
                                  stdout=subprocess.PIPE,bufsize=1)
    linelist= samtoolsin.stdout.readlines()
    print 'Readlines finished!'
    ........print....
    ........print....

Так в чем проблема?Любой другой способ кроме этого sys.stdout?

Мне нужен мой результат, похожий на:

Filename: ERR001268.bam
Readlines finished!
Mean: 233
SD: 10
Interval is: (213, 252)

Ответы [ 11 ]

195 голосов
/ 23 августа 2011

Наиболее очевидный способ сделать это - напечатать на объект файла:

with open('out.txt', 'w') as f:
    print >> f, 'Filename:', filename     # Python 2.x
    print('Filename:', filename, file=f)  # Python 3.x

Однако перенаправление stdout также работает для меня.Это, вероятно, хорошо для одноразового скрипта, такого как:

import sys

orig_stdout = sys.stdout
f = open('out.txt', 'w')
sys.stdout = f

for i in range(2):
    print 'i = ', i

sys.stdout = orig_stdout
f.close()

Перенаправление извне из самой оболочки - еще один хороший вариант:

./script.py > out.txt

Другие вопросы:

Какое первое имя файла в вашем скрипте?Я не вижу его инициализированным.

Мое первое предположение - то, что glob не находит никаких bamfiles, и поэтому цикл for не запускается.Убедитесь, что папка существует, и распечатайте bamfiles в своем скрипте.

Также используйте os.path.join и os.path.basename для управления путями и именами файлов.

60 голосов
/ 22 августа 2011

Вы можете перенаправить печать с помощью оператора >>.

f = open(filename,'w')
print >>f, 'whatever'     # Python 2.x
print('whatever', file=f) # Python 3.x

В большинстве случаев лучше просто записать в файл нормально.

f.write('whatever')

или, если у вас есть несколько элементов, которые вы хотите написать с пробелами, например print:

f.write(' '.join(('whatever', str(var2), 'etc')))
29 голосов
/ 30 июня 2015

Это прекрасно работает:

import sys
sys.stdout=open("test.txt","w")
print ("hello")
sys.stdout.close()

Теперь привет будет записан в файл test.txt.Обязательно закройте stdout с close, без него содержимое не будет сохранено в файле

27 голосов
/ 04 июля 2016

Python 2 или Python 3 Ссылка API:

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)

Файл аргумент должен быть объектом с write(string) методом;если он отсутствует или будет использоваться None, sys.stdout.Поскольку напечатанные аргументы преобразуются в текстовые строки, print() нельзя использовать с объектами файлов в двоичном режиме.Для этого используйте file.write(...).

Поскольку объект файла обычно содержит метод write(), все, что вам нужно сделать, это передать файл объект в свой аргумент.

Запись / перезапись в файл

with open('file.txt', 'w') as f:
    print('hello world', file=f)

Запись / добавление в файл

with open('file.txt', 'a') as f:
    print('hello world', file=f)
14 голосов
/ 01 января 2018

Не используйте print, используйте logging

Вы можете изменить sys.stdout, чтобы указать на файл, но это довольно неуклюжий и негибкий способ решения этой проблемы.Вместо использования print используйте модуль logging.

С logging вы можете печатать так же, как если бы вы набрали stdout, или вы также можете записать выводв файл.Вы даже можете использовать различные уровни сообщений (critical, error, warning, info, debug), например, чтобы печатать только основные проблемы на консоли, но при этом регистрировать второстепенные действия кода вфайл.

Простой пример

Импорт logging, получение logger и установка уровня обработки:

import logging
logger = logging.getLogger()
logger.setLevel(logging.DEBUG) # process everything, even if everything isn't printed

Если вы хотите печатать на стандартный вывод:

ch = logging.StreamHandler()
ch.setLevel(logging.INFO) # or any other level
logger.addHandler(ch)

Если вы также хотите записать в файл (если вы хотите только записать в файл, пропустите последний раздел):

fh = logging.FileHandler('myLog.log')
fh.setLevel(logging.DEBUG) # or any level you want
logger.addHandler(fh)

Затем, где бы вы ни использовалиprint используйте один из logger методов:

# print(foo)
logger.debug(foo)

# print('finishing processing')
logger.info('finishing processing')

# print('Something may be wrong')
logger.warning('Something may be wrong')

# print('Something is going really bad')
logger.error('Something is going really bad')

Чтобы узнать больше об использовании более продвинутых logging функций, прочитайте превосходное руководство logging в документации по Python .

13 голосов
/ 23 августа 2011

Самое простое решение - не через Python;его через оболочку.Из первой строки вашего файла (#!/usr/bin/python) я предполагаю, что вы работаете в системе UNIX.Просто используйте print операторы, как вы это обычно делаете, и вообще не открывайте файл в вашем скрипте.Когда вы запускаете файл, вместо

./script.py

для запуска файла используйте

./script.py > <filename>

, где вы заменяете <filename> на имя файла, который вы хотите вывестиидти в.Токен > сообщает (большинству) оболочек, чтобы установить стандартный вывод для файла, описанного следующим токеном.

Одна важная вещь, о которой следует упомянуть, это то, что «script.py» должен быть выполнен исполняемым./script.py для запуска.

Поэтому перед запуском ./script.py выполните эту команду

chmod a+x script.py (сделайте сценарий исполняемым для всех пользователей)

4 голосов
/ 23 августа 2011

Вам может не понравиться этот ответ, но я думаю, что он правильный.Не меняйте место назначения stdout, если это не является абсолютно необходимым (может быть, вы используете библиотеку, которая выводит только stdout - здесь явно не так).

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

Вот пример:

out_lines = []
for bamfile in bamfiles:
    filename = bamfile.split('/')[-1]
    out_lines.append('Filename: %s' % filename)
    samtoolsin = subprocess.Popen(["/share/bin/samtools/samtools","view",bamfile],
                                  stdout=subprocess.PIPE,bufsize=1)
    linelist= samtoolsin.stdout.readlines()
    print 'Readlines finished!'
    out_lines.extend(linelist)
    out_lines.append('\n')

И затем, когда вы все закончите, собирая свои строки данных"одна строка на элемент списка, вы можете объединить их с некоторыми '\n' символами, чтобы сделать все это выводимым;может быть, даже обернуть ваш оператор вывода в блок with, для дополнительной безопасности (автоматически закроет ваш дескриптор вывода, даже если что-то пойдет не так):

out_string = '\n'.join(out_lines)
out_filename = 'myfile.txt'
with open(out_filename, 'w') as outf:
    outf.write(out_string)
print "YAY MY STDOUT IS UNTAINTED!!!"

Однако если у вас есть много данных для записи, вы может писать по одному кусочку за раз.Я не думаю, что это имеет отношение к вашей заявке, но вот альтернатива:

out_filename = 'myfile.txt'
outf = open(out_filename, 'w')
for bamfile in bamfiles:
    filename = bamfile.split('/')[-1]
    outf.write('Filename: %s' % filename)
    samtoolsin = subprocess.Popen(["/share/bin/samtools/samtools","view",bamfile],
                                  stdout=subprocess.PIPE,bufsize=1)
    mydata = samtoolsin.stdout.read()
    outf.write(mydata)
outf.close()
2 голосов
/ 23 января 2018

Если вы используете Linux, я предлагаю вам использовать tee команду, реализация идет так: Python python_file.py |tee any_file_name.txt если вы не хотите что-либо менять в коде, я думаю, что это может быть наилучшим из возможных решений, вы также можете реализовать регистратор, но вам нужно внести некоторые изменения в код.

0 голосов
/ 06 января 2019

Если перенаправление stdout работает для вашей проблемы, Ответ Гринго Суаве является хорошей демонстрацией того, как это сделать.

Чтобы сделать его еще проще , я создал версию, использующую contextmanagers для краткого обобщенного синтаксиса вызова, используя оператор with:

from contextlib import contextmanager
import sys

@contextmanager
def redirected_stdout(outstream):
    orig_stdout = sys.stdout
    try:
        sys.stdout = outstream
        yield
    finally:
        sys.stdout = orig_stdout

Чтобы использовать его, вы просто делаете следующее (полученный из примера Суаве):

with open('out.txt', 'w') as outfile:
    with redirected_stdout(outfile):
        for i in range(2):
            print('i =', i)

Это полезно для выборочного перенаправления print, когда модуль использует его так, как вам не нравится. Единственный недостаток (а во многих ситуациях это является нарушителем правил) заключается в том, что он не работает, если требуется несколько потоков с разными значениями stdout, но для этого требуется лучший, более обобщенный метод: косвенный доступ к модулю. Вы можете увидеть реализацию этого в других ответах на этот вопрос.

0 голосов
/ 16 июля 2017

Что-то для расширения функции печати для петель

x = 0
while x <=5:
    x = x + 1
    with open('outputEis.txt', 'a') as f:
        print(x, file=f)
    f.close()
...