首页 文章

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

提问于
浏览
112

我想使用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 回答

  • 13

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

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

  • 0

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

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

    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)
    
  • 168

    这非常有效:

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

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

  • 8

    最简单的解决方案不是通过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 (使脚本可执行所有用户)

  • 52

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

    您可以将 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 .

  • 28

    你可能不喜欢这个答案,但我认为这是正确的答案 . 除非绝对必要,否则不要更改你的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()
    
  • 4

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

    你的错误在别的地方:

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

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

  • -1

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

  • 0

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

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

相关问题