256

Pythonを使用して印刷を.txtファイルにリダイレクトしたい。すべての出力を1つのファイルにリダイレクトしたいときに、各.bamファイルの出力を行うforループがあります。だから私は入れようとしました:print

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/xxx/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!'

だから問題は何ですか?これ以外の方法はありますsys.stdoutか?

結果は次のようになります。

Filename: ERR001268.bam
Readlines finished!
Mean: 233
SD: 10
Interval is: (213, 252)
4

14 に答える 14

379

これを行う最も明白な方法は、ファイルオブジェクトに出力することです。

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

ただし、stdoutのリダイレクトも機能します。次のような1回限りのスクリプトではおそらく問題ありません。

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

Python 3.4以降、標準ライブラリでこれを行うために使用できる単純なコンテキストマネージャーがあります。

from contextlib import redirect_stdout

with open('out.txt', 'w') as f:
    with redirect_stdout(f):
        print('data')

シェル自体から外部にリダイレクトすることも別のオプションであり、多くの場合、次のようになります。

./script.py > out.txt

その他の質問:

スクリプトの最初のファイル名は何ですか?初期化されていません。

私の最初の推測では、globはbamfileを検出しないため、forループは実行されません。フォルダが存在することを確認し、スクリプトにbamfileを出力します。

また、os.path.joinとos.path.basenameを使用して、パスとファイル名を操作します。

于 2011-08-22T20:00:19.063 に答える
96

引数を使用してprintをリダイレクトできfileます(Python 2>>では代わりに演算子がありました)。

f = open(filename,'w')
print('whatever', file=f) # Python 3.x
print >>f, 'whatever'     # Python 2.x

ほとんどの場合、通常どおりファイルに書き込む方がよいでしょう。

f.write('whatever')

または、次のように、間にスペースを入れて書き込みたい項目が複数ある場合print

f.write(' '.join(('whatever', str(var2), 'etc')))
于 2011-08-22T19:56:33.870 に答える
48

Python2またはPython3APIリファレンス:

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

file引数は、write(string)メソッドを持つオブジェクトである必要があります。存在しない場合、またはNonesys.stdoutが使用されます。印刷された引数はテキスト文字列に変換さprint()れるため、バイナリモードのファイルオブジェクトでは使用できません。これらについては、file.write(...)代わりに使用してください。

通常、ファイルオブジェクトにはメソッドが含まれているためwrite()必要なのはファイルオブジェクトを引数に渡すことだけです。

ファイルへの書き込み/上書き

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

ファイルへの書き込み/追加

with open('file.txt', 'a') as f:
    print('hello world', file=f)
于 2016-07-04T13:45:25.713 に答える
39

これは完全に機能します:

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

これで、helloがtest.txtファイルに書き込まれます。を必ず閉じてください。これがないstdoutclose、コンテンツはファイルに保存されません。

于 2015-06-30T12:15:25.490 に答える
35

使用しないでくださいprint、使用してくださいlogging

sys.stdoutファイルを指すように変更することもできますが、これはこの問題を処理するためのかなり不格好で柔軟性のない方法です。を使用する代わりにprintloggingモジュールを使用してください。

を使用loggingすると、と同じように印刷しstdoutたり、出力をファイルに書き込んだりすることができます。さまざまなメッセージレベル(、、、、、)を使用してcritical、たとえば、主要な問題のみをコンソールに出力し、マイナーなコードアクションをファイルに記録することもできますerrorwarninginfodebug

簡単な例

をインポートloggingして取得しlogger、処理レベルを設定します。

import logging
logger = logging.getLogger()
logger.setLevel(logging.DEBUG) # process everything, even if everything isn't printed

stdoutに印刷する場合:

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より高度な機能の使用について詳しくは、Pythonドキュメントの優れたloggingチュートリアルをご覧ください。

于 2018-01-01T20:54:59.340 に答える
13

最も簡単な解決策はPythonを使用することではありません。そのシェルを介して。ファイルの最初の行から(#!/usr/bin/python)UNIXシステムを使用していると思います。通常どおりにステートメントを使用printし、スクリプトでファイルをまったく開かないでください。あなたがファイルを実行するために行くとき、代わりに

./script.py

ファイルを実行するには、

./script.py > <filename>

<filename>ここで、出力を送信するファイルの名前に置き換えます。>トークンは、(ほとんどの)シェルに次のトークンで記述されたファイルにstdoutを設定するように指示します。

ここで言及する必要がある重要なことの1つは、「script.py」を実行可能にする必要があるということ./script.pyです。

したがって./script.py、実行する前に、このコマンドを実行してください

chmod a+x script.py (スクリプトをすべてのユーザーに対して実行可能にします)

于 2011-08-22T20:24:09.613 に答える
10

Linuxを使用している場合は、このteeコマンドを使用することをお勧めします。実装は次のようになります。

python python_file.py | tee any_file_name.txt

コード内で何も変更したくない場合は、これが最善の解決策になると思います。ロガーを実装することもできますが、コードにいくつかの変更を加える必要があります。

于 2018-01-23T15:51:35.177 に答える
5

あなたはこの答えが気に入らないかもしれませんが、私はそれが正しいものだと思います。どうしても必要な場合を除いて、stdoutの宛先を変更しないでください(おそらく、stdoutにのみ出力するライブラリを使用している場合は、ここでは明らかにそうではありません)。

良い習慣として、事前にデータを文字列として準備してから、ファイルを開いてすべてを一度に書き込む必要があると思います。これは、入出力操作がファイルハンドルを開いている時間が長いほど、このファイルでエラーが発生する可能性が高くなるためです(ファイルロックエラー、I / Oエラーなど)。すべてを1回の操作で実行するだけで、いつ問題が発生したかは疑問の余地がありません。

次に例を示します。

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

そして、リスト項目ごとに1行の「データ行」の収集がすべて完了したら、それらをいくつかの'\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!!!"

ただし、書き込むデータが多い場合は、一度に1つずつ書き込むことができます。私はそれがあなたのアプリケーションに関連しているとは思いませんが、ここに代替案があります:

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()
于 2011-08-22T20:20:07.950 に答える
3

リダイレクトstdoutが問題に対して機能する場合、GringoSuaveの答えはそれを行う方法の良いデモンストレーションです。

さらに簡単にするために、次のステートメントを使用して、簡潔な一般化された呼び出し構文にコンテキストマネージャーを使用するバージョンを作成しました。with

from contextlib import contextmanager
import sys

@contextmanager
def redirected_stdout(outstream):
    orig_stdout = sys.stdout
    try:
        sys.stdout = outstream
        yield
    finally:
        sys.stdout = orig_stdout

これを使用するには、次のようにします(Suaveの例から派生)。

with open('out.txt', 'w') as outfile:
    with redirected_stdout(outfile):
        for i in range(2):
            print('i =', i)

printモジュールが気に入らない方法で使用した場合に、選択的にリダイレクトするのに役立ちます。唯一の欠点(そしてこれは多くの状況での問題です)は、の値が異なる複数のスレッドstdoutが必要な場合は機能しないことですが、より優れた、より一般化された方法である間接モジュールアクセスが必要です。この質問に対する他の回答で、その実装を確認できます。

于 2019-01-06T04:48:39.813 に答える
1

私は次の方法を使用してこれをクラックすることができます。組み込みの印刷機能の代わりにこの印刷機能を使用して、コンテンツをファイルに保存します。

from __future__ import print_function
import builtins as __builtin__

log = open("log.txt", "a")

def print(*args):
    newLine = ""
    for item in args:
        newLine = newLine + str(item) + " "
    newLine = (
        newLine
        + """
"""
    )
    log.write(newLine)
    log.flush()
    __builtin__.print(*args)
    return
于 2021-09-18T19:51:54.350 に答える
0

sys.stdoutの値を変更すると、印刷するすべての呼び出しの宛先が変更されます。別の方法で印刷先を変更しても、同じ結果が得られます。

あなたのバグはどこかにあります:

  • 質問のために削除したコードに含まれている可能性があります(開くための呼び出しのファイル名はどこから来ていますか?)
  • データがフラッシュされるのを待っていない可能性もあります。端末で印刷する場合、データは新しい行ごとにフラッシュされますが、ファイルに印刷する場合は、stdoutバッファーがいっぱい(4096バイト)のときにのみフラッシュされます。ほとんどのシステムで)。
于 2011-08-22T20:05:14.863 に答える
0

Python 3では、次を再割り当てできますprint

#!/usr/bin/python3

def other_fn():
    #This will use the print function that's active when the function is called
    print("Printing from function")

file_name = "test.txt"
with open(file_name, "w+") as f_out:
    py_print = print #Need to use this to restore builtin print later, and to not induce recursion
   
    print = lambda out_str : py_print(out_str, file=f_out)
    
    #If you'd like, for completeness, you can include args+kwargs
    print = lambda *args, **kwargs : py_print(*args, file=f_out, **kwargs)
    
    print("Writing to %s" %(file_name))

    other_fn()  #Writes to file

    #Must restore builtin print, or you'll get 'I/O operation on closed file'
    #If you attempt to print after this block
    print = py_print

print("Printing to stdout")
other_fn() #Writes to console/stdout

印刷はグローバルスコープで再割り当てされているため、出力other_fnのみを切り替えることに注意してください。関数内で印刷を割り当てる場合、通常、印刷は影響を受けません。すべての印刷呼び出しに影響を与える場合は、 globalキーワードを使用できます。other_fn

import builtins

def other_fn():
    #This will use the print function that's active when the function is called
    print("Printing from function")

def main():
    global print #Without this, other_fn will use builtins.print
    file_name = "test.txt"
    with open(file_name, "w+") as f_out:

        print = lambda *args, **kwargs : builtins.print(*args, file=f_out, **kwargs)

        print("Writing to %s" %(file_name))

        other_fn()  #Writes to file

        #Must restore builtin print, or you'll get 'I/O operation on closed file'
        #If you attempt to print after this block
        print = builtins.print

    print("Printing to stdout")
    other_fn() #Writes to console/stdout

print個人的には、出力ファイル記述子を新しい関数にベイクすることで、関数を使用するという要件を回避したいと思います。

file_name = "myoutput.txt"
with open(file_name, "w+") as outfile:
    fprint = lambda pstring : print(pstring, file=outfile)
    print("Writing to stdout")
    fprint("Writing to %s" % (file_name))
于 2020-12-08T19:04:27.567 に答える
0

これが私がファイル/ログに印刷するために使用した別の方法です...組み込みの印刷関数を変更して、現在のタイムスタンプでtempディレクトリ内のファイルにログを記録し、stdoutに印刷します。スクリプト内でこれを行うことの唯一の本当の利点は、既存のprintステートメントを変更する必要がないことです。

print('test')
test

元の印刷機能を新しい変数にコピーします

og_print = print
og_print('test2')
test2

既存の印刷機能を上書きする

def print(*msg):
    '''print and log!'''
    # import datetime for timestamps
    import datetime as dt
    # convert input arguments to strings for concatenation
    message = []
    for m in msg:
        message.append(str(m))
    message = ' '.join(message)
    # append to the log file
    with open('/tmp/test.log','a') as log:
        log.write(f'{dt.datetime.now()} | {message}\n')
    # print the message using the copy of the original print function to stdout
    og_print(message)
print('test3')
test3

表示ファイル

cat /tmp/test.log
2022-01-25 10:19:11.045062 | test3

ファイルを削除

rm /tmp/test.log
于 2022-01-25T15:28:58.783 に答える
-1

ループの印刷機能を拡張するもの

x = 0
while x <=5:
    x = x + 1
    with open('outputEis.txt', 'a') as f:
        print(x, file=f)
    f.close()
于 2017-07-16T19:34:04.957 に答える