- PR -

バイナリデータを比較するには

投稿者投稿内容
ネーブル
常連さん
会議室デビュー日: 2006/08/26
投稿数: 27
投稿日時: 2006-09-12 02:03
お世話になります、いつも質問ばかりで申し訳ございません宜しくお願いいたします。

[概要]
符号無のバイナリデータの書込まれた数十メガからギガクラスの二つのファイルを開き、BinaryReaderメソッドで1Byteづつ読込み、
差異があった場合その現れた位置を配列diffへ保存する。という動作を期待しています。

[問題点1]
読込むバイト数をdestFileName->Lengthで取得できません。
50Mくらいのファイルでも14回でwhileブロックが終了してしまいます。

[問題点2]
バイナリデータを比較する場合、このように1バイトづつではないと比較できないのでしょうか?
512、1024バイト単位で読込んで比較した方がディスクアクセスが少なくて速い気がするのですが。

コード:

private:
// 転送データ比較
void DataComparison( String^ FileName, String^ destFileName )
{

BinaryReader^ binReader = gcnew BinaryReader( File::openRead( FileName ));

BinaryReader^ binReader2 = gcnew BinaryReader( File::openRead( destFileName ));

array<Int64>^ diff = gcnew array<Int64>(destFileName->Length);

UInt16 foo = binReader->ReadUInt16();

UInt16 bar = binReader2->ReadUInt16();

Int64 counter = 0;

Int64 i = 0;

try
{
while ( destFileName->Length )
{
if ( foo != bar )
{
diff[i] = counter;
i++;
}
counter++;
}
}
catch (Exception^ e)
{
MessageBox::Show(FileName, e->ToString());
}
finally
{
if ( binReader || binReader2 != nullptr )
{
binReader->Close();
binReader2->Close();
}
}
return;
}



[ メッセージ編集済み 編集者: ネーブル 編集日時 2006-09-12 02:29 ]

[ メッセージ編集済み 編集者: ネーブル 編集日時 2006-09-12 02:29 ]

[ メッセージ編集済み 編集者: ネーブル 編集日時 2006-09-12 02:30 ]
なちゃ
ぬし
会議室デビュー日: 2003/06/11
投稿数: 872
投稿日時: 2006-09-12 02:33
引用:

ネーブルさんの書き込み (2006-09-12 02:03) より:
[問題点1]
読込むバイト数をdestFileName->Lengthで取得できません。
50Mくらいのファイルでも14回でwhileブロックが終了してしまいます。


何やってんだかさっぱり分かりません。
いったいこのプログラムは何をしたいんでしょうか?
にー
常連さん
会議室デビュー日: 2006/04/30
投稿数: 35
投稿日時: 2006-09-12 06:38
投稿したプログラムは、本当にテスト中のものですか?

>[問題点1]
>while( destFileName->Length )

これでは、無限ループしてしまいます。
投稿したプログラムがテスト中でない場合、14回というのは比較対象側のファイル名を指しているのでしょうけど。


>[問題点2]

質問の内容と、やりたい内容にギャップがありませんか?
登録したプログラムがやりたい内容を推測すると、それぞれのファイルを全て読み取って全内容を比較したい、って感じになっています。
もし本当に512バイトずつ比較したいのであれば、
  binReader->ReadUInt16();
などは、ループでくくる必要がありますから。

どうせなら、テスト中のものを見やすいように編集して再度投稿されたら如何でしょうか?
ピカード
常連さん
会議室デビュー日: 2006/09/01
投稿数: 37
お住まい・勤務地: 関西
投稿日時: 2006-09-12 09:15
基本を確認してから、再度質問した方がよいでしょう。
http://ja.gotdotnet.com/QuickStart/howto/default.aspx?url=/quickstart/howto/doc/anagrams.aspx
mio
ぬし
会議室デビュー日: 2005/08/25
投稿数: 734
お住まい・勤務地: 神奈川県
投稿日時: 2006-09-12 09:37
>[問題点1]
ファイルの長さを取りたいのに、ファイル「名」の長さを取ってますね。
しかも、読み込んでいって変わるのは、「ファイルのサイズ」ではなく「現在位置からの残りのサイズ」でしょう。

>[問題点2]
ReadBytes?
読み込みがループに入ってない…というのは、すでに上げられてますね。

あと、finallyでのcloseは、面倒でも別々のifにするほうが良いと思いますが。
readerができててreader2ができていないと、まずくないですか。

なぜreaderとreader2の判定が違うんだろう…。
Jubei
ぬし
会議室デビュー日: 2002/03/02
投稿数: 830
お住まい・勤務地: 関西
投稿日時: 2006-09-12 10:26
諸農です。

投稿されているコードが何をしているかは判りませんというのはコメントされている皆さんと同じ意見なんですが、気になる点が一つあります。

例えば、10バイトのデータAとBがあるとします。
Aデータの中身:0123456789
Bデータの中身:0123456789

Bデータを変更して11バイトにします。
#3バイト目、または4バイト目に「2」のデータを挿入です。
変更後のBデータの中身:01223456789

このデータを比較判定するときに、

引用:

差異があった場合その現れた位置を配列diffへ保存する。という動作を期待しています。



と言うことは、上記のA,Bデータを比較した場合、4バイト目以降最後までが「差違のある状態」となり、配列diffにはインデックスとして4,5,6,7,8,9,10(ゼロオリジンですよね?)と格納されるのが正解でしょうか?

Aを基準に考えると10バイト目で読み取り終了するので11バイト目(インデックス10)は比較の対象にするのか、差違として配列diffに格納する必要があるのかどうかも決めないといけないのではないでしょうか。

また、上記A,Bデータの比較の場合、ダンプ出力して人間が目で見て頭で考えて判定するのであれば、単純に3バイト目or4バイト目に1バイトのデータが挿入されていて、それ以降はずれているだけだ、と判断が出来る場合もあると思います。そうした場合、配列diffにはインデックス3だけを格納するのでしょうか?またそうするのであればプログラムではどのようにして判断するつもりなのでしょうか。

秀丸をお持ちならテキストの比較機能があるので試していただけると判ると思いますが、差違が発見された後に継続して比較する場合、継続して比較する開始位置を再度決める必要があります。

浅学のため、全くの私見となりますが、レイアウトのないデータを比較するのであれば、開始位置から最初に発見された差違のインデックスを求めるのが限界なのではないかと感じます。

バイト比較で、しかもギガレベルのデータ比較で、差違のインデックスを全部配列に持たせることに無理があるのではないでしょうか。またそのようなインデックスが格納された配列を取得することに何かの意味があるとも思えないです。

レイアウトのないデータを比較するっていうのはすごく難しいと思います。


あ、データをソートしてシーケンシャルマッチするって事ではないですよね?

_________________
諸農和岳
Powered by Turbo Delphi & Microsoft Visual Studio 2005

十兵衛@わんくま同盟
http://blogs.wankuma.com/jubei/
ネーブル
常連さん
会議室デビュー日: 2006/08/26
投稿数: 27
投稿日時: 2006-09-16 19:12
どうも、返事が遅くなりました
おかげさまで、解決いたしました。
Jubeiさん
引用:

レイアウトのないデータを比較するのであれば、開始位置から最初に発見された差違のインデックスを求めるのが限界なのではないかと感じます。


差異をあらわすイメージとしては、DOSコマンドにあるようなCOMPのようなものですので、ファイルの先頭から何番目のデータが違う程度のものが出力できれば充分としました。
コード:

private:
// 転送データ比較
void DataComparison( String^ FileName, String^ destFileName )
{
FileStream^ fs1 = File::openRead( FileName );
FileStream^ fs2 = File::openRead( destFileName );

BinaryReader^ binReader1 = gcnew BinaryReader( fs1 );
BinaryReader^ binReader2 = gcnew BinaryReader( fs2 );

binReader1->BaseStream->Seek(0, SeekOrigin::Begin);
binReader2->BaseStream->Seek(0, SeekOrigin::Begin);
Int16 arg1, arg2;

int beginWrite = Environment::TickCount; //get the start time
MessageBox::Show(Convert::ToString( beginWrite ));
Int64 i = 0;
try
{
while (binReader1->PeekChar() > -1)
{
arg1 = binReader1->ReadInt16();
arg2 = binReader2->ReadInt16();
if (arg1 != arg2)
{
MessageBox::Show(Convert::ToString( i ), "不一致です");
break;
}
i++;

}

MessageBox::Show("データは全て一致しました");

int endWrite = Environment::TickCount; //get the end time

MessageBox::Show(Convert::ToString(endWrite));
}
catch (Exception^ e)
{
MessageBox::Show(FileName, e->ToString());
}
finally
{
if ( binReader1 != nullptr )
{
binReader1->Close();
binReader2->Close();
}
if ( binReader2 != nullptr )
{
binReader1->Close();
binReader2->Close();
}
}
return;
}



[ メッセージ編集済み 編集者: ネーブル 編集日時 2006-09-16 19:14 ]

[ メッセージ編集済み 編集者: ネーブル 編集日時 2006-09-16 19:15 ]

[ メッセージ編集済み 編集者: ネーブル 編集日時 2006-09-16 20:06 ]

[ メッセージ編集済み 編集者: ネーブル 編集日時 2006-09-16 22:24 ]

[ メッセージ編集済み 編集者: ネーブル 編集日時 2006-09-16 22:24 ]
Jubei
ぬし
会議室デビュー日: 2002/03/02
投稿数: 830
お住まい・勤務地: 関西
投稿日時: 2006-09-17 04:59
諸農です。

ちょっと読みにくいですね(^^;

引用:

差異をあらわすイメージとしては、DOSコマンドにあるようなCOMPのようなものですので、ファイルの先頭から何番目のデータが違う程度のものが出力できれば充分としました。


最初の差違だけが判ればいいと言うことですか。
スタート位置を指定できるようにした方がいいかも知れないですね。

引用:

コード:
      binReader1->BaseStream->Seek(0, SeekOrigin::Begin);
      binReader2->BaseStream->Seek(0, SeekOrigin::Begin);





なんか遠回りしているような。。


引用:

コード:
        while (binReader1->PeekChar() > -1)
        {
          arg1 = binReader1->ReadInt16();
          arg2 = binReader2->ReadInt16();





binReader2が参照しているファイルサイズがbinReader1が参照しているファイルサイズよりも小さい場合はどうするのですか?


引用:

コード:
      finally
      {
        if ( binReader1 != nullptr )
        {
          binReader1->Close();
          binReader2->Close();
        }
        if ( binReader2 != nullptr )
        {
          binReader1->Close();
          binReader2->Close();
        }
      }





なぜnullptrの判定をしているのでしょうか?


_________________
諸農和岳
Powered by Turbo Delphi & Microsoft Visual Studio 2005

十兵衛@わんくま同盟
http://blogs.wankuma.com/jubei/

スキルアップ/キャリアアップ(JOB@IT)