Как перенаправить вывод "print" в файл с помощью python?

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

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

в начале моего script. Однако я ничего не получаю в TXT файле. Мой script:

#!/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)

Ответ 1

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

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()

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

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

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

Ответ 2

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

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')))

Ответ 3

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

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

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

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

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

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

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

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

Ответ 4

Это отлично работает:

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

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

Ответ 5

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

./script.py

чтобы запустить файл, используйте

./script.py > <filename>

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

Важно отметить, что "script.py" нужно сделать исполняемым для ./script.py для запуска.

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

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

Ответ 6

Не используйте 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.

Ответ 7

Вам может не понравиться этот ответ, но я думаю, что это ПРАВЫЙ. Не изменяйте назначение 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()

Ответ 8

Изменение значения sys.stdout изменяет назначение всех вызовов для печати. Если вы используете альтернативный способ изменения адресата печати, вы получите тот же результат.

Ваша ошибка в другом месте:

  • это может быть в коде, который вы удалили для своего вопроса (откуда появляется имя файла для вызова?)
  • также может быть, что вы не ожидаете сброса данных: если вы печатаете на терминале, данные размываются после каждой новой строки, но если вы печатаете в файл, он только краснеет, когда буфер stdout заполняется (4096 байт в большинстве систем).

Ответ 9

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

Ответ 10

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

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