如何使用python将'print'输出重定向到文件?

Loo*_*ast 151 python file-writing

我想使用python将打印重定向到.txt文件.我有一个'for'循环,它会'打印'我的每个.bam文件的输出,而我想将所有这些输出重定向到一个文件.所以我试着把

 f = open('output.txt','w'); sys.stdout = f
Run Code Online (Sandbox Code Playgroud)

在我的脚本开头.但是我在.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....
Run Code Online (Sandbox Code Playgroud)

所以有什么问题?除了这个sys.stdout之外的任何其他方式?

我需要我的结果如下:

Filename: ERR001268.bam
Readlines finished!
Mean: 233
SD: 10
Interval is: (213, 252)
Run Code Online (Sandbox Code Playgroud)

Gri*_*ave 224

最明显的方法是打印到文件对象:

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

但是,重定向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()
Run Code Online (Sandbox Code Playgroud)

从shell本身重定向是另一个好的选择:

./script.py > out.txt
Run Code Online (Sandbox Code Playgroud)

其他问题:

脚本中的第一个文件名是什么?我没有看到它初始化.

我的第一个猜测是glob没有找到任何bamfiles,因此for循环不会运行.检查文件夹是否存在,并在脚本中打印出bamfiles.

另外,使用os.path.join和os.path.basename来操作路径和文件名.

  • +1哈哈,你可以得到我的upvote,因为如果你绝对必须以错误的方式做到这一点,这是正确的方法...但我仍然说你应该用常规文件输出来做. (4认同)
  • @my我不相信这样的简单脚本不好. (3认同)
  • 如果不需要,更改 sys.stdout 的错误做法。 (2认同)
  • 如何在控制台上重定向并打印输出?当 stdrr 重定向时,Python 中的“print()”似乎无法显示? (2认同)

agf*_*agf 64

您可以使用>>操作员重定向打印.

f = open(filename,'w')
print >>f, 'whatever'     # Python 2.x
print('whatever', file=f) # Python 3.x
Run Code Online (Sandbox Code Playgroud)

在大多数情况下,您最好只是正常写入文件.

f.write('whatever')
Run Code Online (Sandbox Code Playgroud)

或者,如果你想要用几个空格写下几个项目,例如print:

f.write(' '.join(('whatever', str(var2), 'etc')))
Run Code Online (Sandbox Code Playgroud)

  • 如果有很多输出语句,这些语句会很快变老。海报原创想法有效;脚本还有其他问题。 (2认同)

小智 30

这非常有效:

import sys
sys.stdout=open("test.txt","w")
print ("hello")
sys.stdout.close()
Run Code Online (Sandbox Code Playgroud)

现在hello将被写入test.txt文件.确保关闭stdouta close,没有它,内容将不会保存在文件中

  • 但是,即使我们执行sys.stdout.close(),如果您在python shell中键入任何内容,也会显示错误,提示为“ ValueError:对关闭文件的I / O操作。” http://imgur.com/a/xby9P 。最好的方法是遵循@Gringo Suave发布的内容 (2认同)

Yeo*_*Yeo 30

Python 2Python 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)
Run Code Online (Sandbox Code Playgroud)

写入/附加到文件

with open('file.txt', 'a') as f:
    print('hello world', file=f)
Run Code Online (Sandbox Code Playgroud)

  • 我只是困惑为什么一些早期的答案是猴子修补全局`sys.stdout` :( (4认同)
  • 假设您有一些遗留代码 (2.7),整个文件中都带有打印语句(而不是日志)。现在,您希望将它们记录到文件中以用于调试/调查目的。在这种情况下,修改全局标准输出比修改每个打印语句更好。只是我的观点。 (4认同)

jpy*_*ams 18

不要使用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
Run Code Online (Sandbox Code Playgroud)

如果要打印到标准输出:

ch = logging.StreamHandler()
ch.setLevel(logging.INFO) # or any other level
logger.addHandler(ch)
Run Code Online (Sandbox Code Playgroud)

如果你还想写一个文件(如果你只想写一个文件跳过最后一节):

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

然后,无论您在哪里使用,都可以使用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')
Run Code Online (Sandbox Code Playgroud)

要了解有关使用更多高级logging功能的更多信息,请阅读loggingPython文档中的优秀教程.


Aar*_*our 12

最简单的解决方案不是通过python; 它通过壳.从你的文件的第一行(#!/usr/bin/python)我猜你是在UNIX系统上.只需print像往常一样使用语句,并且不要在脚本中打开文件.当你去运行文件时,而不是

./script.py
Run Code Online (Sandbox Code Playgroud)

要运行该文件,请使用

./script.py > <filename>
Run Code Online (Sandbox Code Playgroud)

在哪里替换<filename>您希望输出进入的文件的名称.该>令牌告诉(最)弹到标准输出设置为以下令牌描述的文件.

这里需要提到的一件重要事情是"script.py"需要可执行./script.py才能运行.

所以在运行之前./script.py,执行此命令

chmod a+x script.py (使脚本可执行所有用户)

  • ./script.py> <filename> 2>&1您还需要捕获stderr.2>&1会做到这一点 (3认同)

yun*_*nus 10

如果您使用的是 Linux,我建议您使用该tee命令。实现是这样的:

python python_file.py | tee any_file_name.txt
Run Code Online (Sandbox Code Playgroud)

如果您不想更改代码中的任何内容,我认为这可能是最好的解决方案。您也可以实现记录器,但您需要对代码进行一些更改。


mac*_*ing 5

您可能不喜欢这个答案,但我认为这是正确的答案。除非绝对必要,否则不要更改您的标准输出目的地(也许您正在使用仅输出到标准输出的库???在这里显然不是这种情况)。

我认为作为一个好习惯,您应该提前将数据准备为字符串,然后打开文件并立即写入整个内容。这是因为输入/输出操作打开文件句柄的时间越长,该文件发生错误的可能性就越大(文件锁定错误、I/O 错误等)。只需在一次操作中完成所有操作,就不会出现何时可能出错的问题。

下面是一个例子:

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')
Run Code Online (Sandbox Code Playgroud)

然后,当您完成收集每个列表项一行的“数据行”后,您可以将它们与一些'\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!!!"
Run Code Online (Sandbox Code Playgroud)

但是,如果您有大量数据要写入,则可以一次写入一个。我认为它与您的应用程序无关,但这是替代方案:

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()
Run Code Online (Sandbox Code Playgroud)

  • @Gringo:我感谢您的批评并享受激烈的辩论。尽管我们在某些方面存在分歧,但我仍然尊重您的观点,因为很明显您有充分的理由采取自己的立场。感谢您合理地结束它并度过一个美好的夜晚。:P (2认同)