Как перенаправить вывод "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()