2013-05-19 5 views
11

ファイルへの書き込み方法とファイルからの読み込み方法は分かっていますが、ファイル全体を読む以外にファイルを変更する方法はわかりませんそれを操作して、ファイル全体を書き換えます。大きなファイルの場合、これはあまり生産的ではありません。Rubyを使ってテキストファイルの途中にあるデータ行を削除するには

私は本当に追加と書き込みの違いを知りません。

など。

私が含まれているファイルがある場合:

Person1,will,23 
Person2,Richard,32 
Person3,Mike,44 

どのように私はちょうどPERSON2を含む行を削除することができるだろうか?

+0

沢、あなたはいつも私を助けています。したがって、プログラムがファイルを保存するたびに、ファイル全体が上書きされますか? – Senjai

+0

ファイルを読み取らずに削除する行を見つける方法を計画していますか?それはいつも特定の行番号ですか? –

+0

@Senjai Sergioは何かを助けてくれるかもしれないと示唆しており、それが正しければ私の以前のコメントは間違っています。申し訳ありません。 – sawa

答えて

13

あなたはいくつかの方法で行を削除することができます。

  • は、削除をシミュレートします。つまり、行の内容を空白で上書きするだけです。後で、ファイルを読み込んで処理するときに、そのような空行を無視するだけです。

    プロ:これは簡単で高速です。 小切手:データの実際の削除ではありません(ファイルは縮小されません)、ファイルの読み取り/処理時にはもっと多くの作業が必要です。

    コード:

    f = File.new(filename, 'r+') 
    f.each do |line| 
        if should_be_deleted(line) 
        # seek back to the beginning of the line. 
        f.seek(-line.length, IO::SEEK_CUR) 
    
        # overwrite line with spaces and add a newline char 
        f.write(' ' * (line.length - 1)) 
        f.write("\n") 
        end 
    end 
    f.close 
    
    File.new(filename).each {|line| p line } 
    
    # >> "Person1,will,23\n" 
    # >> "     \n" 
    # >> "Person3,Mike,44\n" 
    
  • 本当の削除を行います。これは、行が存在しなくなることを意味します。したがって、次の行を読み、現在の行を上書きする必要があります。その後、ファイルの終わりに達するまで、次のすべての行についてこれを繰り返します。これはエラーが起こりやすいタスク(長さが違う行など)のようですので、ここにエラーのない代替方法があります:一時ファイルを開き、削除したい行まで書いてください。削除したい、残りを一時ファイルに書き込む。元のファイルを削除し、名前を使用するように一時ファイルの名前を変更します。完了しました。

    これは技術的にファイルの全書き換えですが、尋ねた内容とは異なります。ファイルを完全にメモリにロードする必要はありません。一度に1行しか必要ありません。 Rubyはこのための方法を提供しています:IO#each_line

    プロ:予期しないことです。行が削除されます。コードを読む必要はありません。 短所:コードを削除するだけでなく、IO/CPU時間も削除できます。

    @ azgultのanswerにこのアプローチを示すスニペットがあります。

+0

ファイル全体を上書きすることなく、ファイルの一部だけを上書きすることはできますか? – sawa

+1

もちろん、可能です。書き込みモードでファイルを開き、必要なオフセットを求めて書き込みを開始します。 –

+0

書き込みモードでない場合、パーツを上書きするには読み取り/書き込みモード( 'r +'フラグ)が必要です。 – azgult

0

読むhere

File.open('output.txt', 'w') do |out_file| 
    File.open('input.txt', 'r').each do |line| 
    out_file.print line.sub('Person2', '') 
    end 
end 
+0

これは、ファイル全体を上書きします。 OPはそれをどうやって行うのかを知っていると思うし、それは尋ねられるものではない。 – sawa

+1

これは他の回答に従う唯一の方法と思われます。 – juanpastas

3

ファイルを開いて、新しいファイルに保存したい行を1行ずつ読み込むことができます。これにより、元のファイルを破壊することなく、どの行を保存するかを最大限に制御できます。

File.open('output_file_path', 'w') do |output| # 'w' for a new file, 'a' append to existing 
    File.open('input_file_path', 'r') do |input| 
    line = input.readline 
    if keep_line(line) # logic here to determine if the line should be kept 
     output.write(line) 
    end 
    end 
end 

あなたが最初と削除するチャンクの最後の位置がわかっている場合は、あなたが最初に読んでファイルを開くことができ、その後、最後まで追求し、読書を続けます。

readメソッドのパラメータを見て、ここで求めて読ん:

http://ruby-doc.org/core-2.0/IO.html#method-i-read

4

ファイルがその一部を除去することで書き換える必要、ディスクへのデータの連続ブロックとして、本質的に保存されているので少なくともそれの後に来るもの。これは、本質的に、あなたが言うように、大きなファイルにとって特に効率的ではないことを意味します。したがって、一般的には、問題が発生しないようにファイルサイズを制限することをお勧めします。

「妥協的な」ソリューションは、行単位でファイルを2番目のファイルにコピーし、それを最初のファイルに置き換えて移動させることです。これは、メモリにファイルをロードするが、任意のハードディスクアクセスを回避していません回避:

require 'fileutils' 

open('file.txt', 'r') do |f| 
    open('file.txt.tmp', 'w') do |f2| 
    f.each_line do |line| 
     f2.write(line) unless line.start_with? "Person2" 
    end 
    end 
end 
FileUtils.mv 'file.txt.tmp', 'file.txt' 

は、さらに効率的に読み書きするファイルを開き、削除してから、残りをシフトしたい位置まで進んだろうしかし、それはかなり醜いコードのためになります(そして私は今それをするように求められません)。

関連する問題