13

ファイルへの書き込み方法とファイルからの読み取り方法は知っていますが、ファイル全体をメモリに読み込んで操作し、ファイル全体を書き換える以外に、ファイルを変更する方法がわかりません。大きなファイルの場合、これはあまり生産的ではありません。

append と write の違いがよくわかりません。

例えば

次を含むファイルがある場合:

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

Person2 を含む行を削除するにはどうすればよいですか?

4

4 に答える 4

15

行を削除するには、いくつかの方法があります。

  • 削除をシミュレートします。つまり、行の内容をスペースで上書きするだけです。後でファイルを読み取って処理するときは、そのような空の行を無視してください。

    長所: これは簡単かつ迅速です。短所:データの実際の削除ではなく(ファイルは縮小されません)、ファイルの読み取り/処理時にさらに作業を行う必要があります。

    コード:

    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 の回答には、このアプローチを示すスニペットがあります。

于 2013-05-19T19:50:38.413 に答える
7

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

いくつかの「妥協」ソリューションは、ファイルを1行ずつ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'

さらに効率的には、ファイルを読み書きで開き、削除したい位置までスキップしてから、残りのデータを元に戻すことです。今それをしてください)。

于 2013-05-19T19:53:45.327 に答える
4

ファイルを開いて行ごとに読み取り、保持したい行を新しいファイルに追加することができます。これにより、元のファイルを破壊することなく、保持する行を最大限に制御できます。

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

于 2013-05-19T19:50:41.983 に答える
0

ここを読む:

File.open('output.txt', 'w') do |out_file|
  File.open('input.txt', 'r').each do |line|
    out_file.print line.sub('Person2', '')
  end
end
于 2013-05-19T19:47:17.490 に答える