Ruby - 新旧2つのテキストファイルの差分ファイル作成!

Updated:


今日は、新旧2つのテキストファイルの差分ファイルを作成する方法を試してみました。

ここで言う2つのテキストファイルとは、全く別物ではなく、旧テキストファイルに追記していったものが新テキストファイルとなっています。

通常、Ruby で差分ファイルを作成しようと考えた場合、以下のようになると思います。

file_diff.puts open( file_new, "r" ).readlines
             - open( file_old, "r" ).readlines

しかし、当方で検証してみた結果、以下のデメリットを確認しました。

  • 読み込んだ2つのテキストファイルの内容を配列に確保するため、大サイズのテキストファイルだとメモリエラーになる。
  • 空白行が削除されてしまう(上記のスクリプトの場合だけ?)

というわけで、テキストファイルを1行ずつ読み込んで差分ファイルを作成する方法を試行!

処理手順概要

  • 旧テキストファイルの行数をカウント
  • 新テキストファイルを順次読み込む

  • 旧テキストファイルの行数分は読み飛ばし
  • 旧テキストファイルの行数分より後ろの行は差分ファイルへ書き込む

※2つのファイルを同時に1行ずつ読んで双方を比較する方法もありますが、数万行レベルになると処理が遅くなるし、新テキストファイルが旧テキストファイルに追記した形になっていると最初からわかっているので、読み飛ばす方法を採っています。

Ruby スクリプト

参考までに、今回の検証で使用した Ruby スクリプトです。 ※検証環境は、Windows XP (SP3) + Ruby 1.9.2-p290 です。

# -*- coding: utf-8 -*-
#
# 新旧2つのテキストファイルの差分ファイルを作成
#
# date          name            version
# 2011.11.19    mk-mode         1.00 新規作成
#
# Copyright(C)2011 mk-mode.com All Rights Reserved.
#--------------------------------------------------
#++

class DiffText

  # 定数
  FILE_OLD  = "D:\\work\\file_old.txt"
  FILE_NEW  = "D:\\work\\file_new.txt"
  FILE_DIFF = "D:\\work\\file_diff.txt"

  # [CLASS] 差分作成処理
  class Diff

    # INTIALIZE
    def initialize

      # 各種件数
      @cnt_old  = 0
      @cnt_new  = 0
      @cnt_diff = 0

    end

    # 行数取得 ( FILE_OLD )
    def get_linecount_old

      begin

        # ファイルOPEN
        file_old  = open( FILE_OLD,  "r" )

        while line = file_old.gets
          @cnt_old += 1
        end

        puts "LINE COUNT ( OLD  ) = #{@cnt_old}"

      ensure

        # FILE CLOSE ( 意図的に )
        file_old.close

      end

    end

    # 差分ファイル作成
    def make_diff_file

      begin

        # ファイルOPEN
        file_new  = open( FILE_NEW,  "r" )
        file_diff = open( FILE_DIFF, "w" )

        while line = file_new.gets
          @cnt_new += 1
          unless @cnt_new > @cnt_old
            next
          else
            @cnt_diff += 1
            file_diff.puts( line )
          end
        end

        puts "LINE COUNT ( NEW  ) = #{@cnt_new}"
        puts "LINE COUNT ( DIFF ) = #{@cnt_diff}"

      ensure

        # FILE CLOSE ( 意図的に )
        file_new.close
        file_diff.close

      end

    end

  end

  #### MAIN ####

  # インスタンス化 ( 差分ファイル作成処理クラス )
  obj_diff = Diff.new

  # 行数取得 ( 旧ファイル )
  obj_diff.get_linecount_old

  # 差分ファイル作成
  obj_diff.make_diff_file

end

これでメモリエラーは発生しなくなりました。 応用したいと思っている処理に適用してみることにします。

以上。





 

Sponsored Link

 

Comments