2013-06-10 9 views
8

をファイルに書かれた最後の文字の上に私は、SQLファイルを出力Pythonアプリケーションがあります。データが利用可能になった。これはforループ内で行われていない「バックスペース」

sql_string = "('" + name + "', " + age + "')," 
output_files['sql'].write(os.linesep + sql_string) 
output_files['sql'].flush() 

は、それが書かれています。アプリケーションの実行が終了したときに最後のカンマ文字を「バックスペース」してセミコロンに置き換える方法はありますか?改行の前にコンマを出力し、特定の '書き込み'が最初の書き込みであるかどうかを判断するためにグローバルなBoolを使用することで回避策を考案できると確信しています。しかし、私はそれを "バックスペース"することができれば、アプリケーションはもっときれいになると思う。もちろん、Pythonの方が簡単な方法かもしれません!

insertの値の行をリストに入れてからリストを畳み込むことは、このユースケースでは実行可能な解決策ではありません。

+0

あなたは実際にそこに行きたくはありません。出力ファイルを非常に一般的なものにして、パイプ、名前付きパイプ、TCP接続やHTTPポストフィールドなどを表すオブジェクトにすることができます。これらの中には副作用があり、最後の文字を取り戻すことはできません。 –

+0

@ qarma:ありがとうございます。特定のケースでは、私の '出力ファイル'は一般的ではなく、私が記述したテキストファイルですが、私が注意しなければならない副作用がありますか?これはDebian派生OS上で実行されることに注意してください。さらに、なぜ私は出力ファイルを非常に汎用的なものにしたいのか分かりませんが、おそらくあなたは解明することができますか? – dotancohen

答えて

8

使用は後方、そして新しい文字を書き、あなたのカーソルを1バイト(文字)を移動しよう)しかし、状況を避ける方が良いでしょう。

+1

ハックの+1。私はこれがバイナリファイルでのみ動作すると想像します。ファイルがテキストモードで開かれていて、最後の文字が複雑なユニコードだった場合、私は 'seek'がロールバックするバイト数を知っているのではないかと疑います。 –

+0

ありがとう、これは実現可能性があります。実際には、ファイルは 'a +'としてオープンされています(前に存在しないことが期待されます)。 「最後の文字」は常にカンマになります。これは安全ですか? – dotancohen

+0

やや安全です。多少醜い、はい。 – kqr

0

「w」ではなく「wb」というバイナリ形式でファイルを開いてみてください。これは最も簡単な変更である

f.seek(-1, os.SEEK_CUR) 
f.write(";") 

、あなたの現在のコード(「ワーキングコード」を維持することは「理想的なコードを」打つ:

4

新しい行を追加する前にコンマを追加するのはどうですか?

first_line = True 

... 

sql_string = "('" + name + "', " + age + "')" 

if not first_line: 
    output_files['sql'].write(",") 
first_line = False 

output_files['sql'].write(os.linesep + sql_string) 
output_files['sql'].flush() 

... 

output_files['sql'].write(";") 
output_files['sql'].flush() 

あなたの質問でこれを言及しなかった - 私は、これはコンマを求め、それらを上書きするよりもメンテナに非常に明確だと思います。

EDIT:上記溶液は(望ましくない)、あなたのコード内でグローバルなブール値を必要とするので、あなたの代わりにヘルパークラスにファイル書き込み動作をラップすることができます:

class SqlFileWriter: 

    first_line = True 

    def __init__(self, file_name): 
     self.f = open(file_name) 

    def write(self, sql_string): 
     if not self.first_line: 
      self.f.write(",") 
     self.first_line = False 

     self.f.write(os.linesep + sql_string) 
     self.f.flush() 

    def close(self): 
     self.f.write(";") 
     self.f.close() 


output_files['sql'] = SqlFileWriter("myfile.sql") 
output_files['sql'].write("('" + name + "', '" + age + "')") 

これは、すべてのSQL表記をカプセル化ロジックを単一のクラスにまとめ、コードを読み込み可能にすると同時に呼び出し元コードを単純化します。

+0

ありがとうございます。このアプローチの問題は、この特定のアプリケーションでは実現不可能なグローバルな「ブール」を維持することです。 – dotancohen

+0

私は、ファイル操作をヘルパークラスにラップすることによって、グローバルな 'bool'を避ける方法を提案する答えを更新しました。 – seanhodges

+0

Seanさんありがとうございました。私がコードに新しい機能を導入する準備ができたら、私はこのように扱います。 – dotancohen

0

使用ジェネレータ、例えば:ハードコアイテレータの使用のために

def with_separator(data, sep): 
    first = True: 
    for datum in data: 
     if first: 
      first = False 
     else: 
      yield sep 
     yield datum 

with open("sdfasdfas", "w") as outf: 
    for x in with_separator(sql_get_rows(), ",\n"): 
     outf.write(x) 
     # flush if needed 

、このあなたが始める必要があります。

In [11]: list(itertools.imap("".join, itertools.izip(itertools.chain([""], itertools.repeat(",\n")), "abc"))) 
Out[11]: ['a', ',\nb', ',\nc'] 

データが不可欠APIを使用している場合、それは反復可能ではない、send()データへジェネレータ:

def write_with_separator(filename, sep): 
    with file(filename, "w"): 
     first = True 
     yield None 
     while True: 
      datum = yield None 
      if first: 
       first = False 
      else: 
       fout.write(sep) 
      fout.write(datum) 
      # flush if needed 

writer = write_with_separator("somefilename", ",\n") 
writer.next() # can't send to just-started generator 

# to be called when you get data 
for row in sql_get_rows(): 
    writer.send(row) 
+0

ありがとうございます。しかし、私が 'first_output'にいるかどうかを知るためにグローバルboolを維持することができないのと同じ理由で、ジェネレータも役に立たないでしょう。私は、辞書を爆発させることは、このユースケースのための実現可能な解決策ではないことをOPで言及した。 – dotancohen

関連する問題