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

我想使用python将打印重定向到.txt文件 . 我有一个'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)

回答(10)

3 years ago

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

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 and os.path.basename来操作路径和文件名 .

3 years ago

您可以使用 >> 运算符重定向打印 .

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 years ago

Python 2或Python 3 API参考:print(* objects,sep ='',end ='\ n',file = sys.stdout,flush = False)file参数必须是具有write(string)方法的对象;如果它不存在或None,将使用sys.stdout . 由于打印的参数转换为文本字符串,因此print()不能与二进制模式文件对象一起使用 . 对于这些,请改用file.write(...) .

由于file object通常包含 write() 方法,因此您需要做的就是将file object传递给其参数 .

写入/覆盖文件

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

写入/附加到文件

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

3 years ago

这非常有效:

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

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

3 years ago

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

./script.py

要运行该文件,请使用

./script.py > <filename>

<filename> 替换为您希望输出进入的文件的名称 . > 令牌告诉(大多数)shell将stdout设置为由以下标记描述的文件 .

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

因此,在运行 ./script.py 之前,请执行此命令

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

3 years ago

不要使用打印,请使用日志记录

您可以将 sys.stdout 更改为指向文件,但这是一种非常笨重且不灵活的方法来处理此问题 . 而不是使用 print ,使用logging模块 .

使用 logging ,您可以像 stdout 一样进行打印,或者也可以将输出写入文件 . 您甚至可以使用不同的消息级别( criticalerrorwarninginfodebug ),例如,仅将主要问题打印到控制台,但仍将次要代码操作记录到文件中 .

一个简单的例子

导入 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 tutorial in the Python docs .

3 years ago

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

我认为,作为一个好习惯,您应该提前准备数据作为字符串,然后打开您的文件并立即编写整个文件 . 这是因为输入/输出操作是打开文件句柄的时间越长,此文件发生错误的可能性就越大(文件锁定错误,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')

然后当你完成每个列表项的一行收集"data lines"时,你可以用一些 '\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!!!"

但是,如果要写入大量数据,则 could 一次写入一个数据 . 我没有't think it'与您的申请相关,但这里是替代方案:

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

3 years ago

更改sys.stdout的值确实会更改目标所有打印电话 . 如果您使用其他方法更改打印目的地,您将获得相同的结果 .

你的错误在别的地方:

  • 它可能在你为你的问题删除的代码中(文件名来自哪里打开调用?)

  • 也可能是您没有等待刷新数据:如果在终端上打印,则在每个新行之后刷新数据,但如果打印到文件,则仅在stdout缓冲区已满时刷新(4096)大多数系统上的字节数) .

3 years ago

如果你使用linux我建议你使用 tee 命令实现就像这个python python_file.py |tee any_file_name.txt 如果你不想改变代码中的任何东西,我认为这可能是最好的解决方案,你也可以实现 Logger ,但你需要做一些改变在代码中 .

3 years ago

用于扩展循环的打印功能的东西

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