ファイルサーバ更改

【容量1.3TB、110万ファイルのサーバ更改事例】

お客様先のWindows Server 2008 R2を新しいWindows Server OSに更改しています。 今回、アドバイザとして案件に参画し、お客様先エンジニアの皆さんがRobocopyを実施するのを眺めるお仕事でした。

ファイル件数が合わない!?

ところが、Robocopyを実施したところ、移行元と移行先のファイルサイズ、ファイル件数が合わない!
差異を抽出したいのですが、移行元、移行先ともに約110万ファイル・・・

こんなとき、Excelなどのツールは遅くてほぼ使えません。(というか、1,048,576が最大行数)
フリーソフトDiffツールなどを試しても、遅くて反応なし・・・
Windowsが標準で提供する、fcコマンドは動作が速かったけど、差異が多く発生すると結果が見づらいので使えず。
サクラエディタのDiffパッケージはそこそこ動作が速かったけど、結果を別ファイルに取り込めない・・・

社内ファイルサーバ更改なら、創意ラボ株式会社へ

というワケで、110万行と110万行の突合をするスクリプトを緊急で作成することになりました。言語はWindows環境なら、どのサーバでも絶対使えるVBScriptを採用しました。

検索範囲を狭めることができそうだったので、実行時間は1時間~2時間程度だったと思います。 30分で作成したスクリプトにしては上出来だったと思います。

緊急で作ったスクリプトなので変数名とか適当ですが、公開しますので、皆様のお仕事において参考になれば幸いです。

ファイルサーバ1に存在して、ファイルサーバ2に存在しないレコードを抽出しますが、逆のパターン(ファイルサーバ2に存在してファイルサーバ1に存在しない)も、このVBScriptで実行できます。

ちなみに、実行結果ですが、ファイル名として使えない文字や、Robocopy中に更新してしまったなどの理由で、100件程度抽出されました。良い仕事ができました!

'=================================
'ファイルサーバ1に存在して、ファイルサーバ2に存在しないファイル名を抽出
'=================================

'=================================
'以下のコマンドプロンプトを実行した結果より、旧サーバと新サーバの差異を調べる
'dir [ディレクトリ名] /A-D /B /S > [ファイル格納場所]
'【例】dir D:\filesvr /A-D /B /S > .\Desktop\result_old.txt
'コマンドプロンプトで上記のコマンドを実施すると、サブフォルダ内を含むファイル名が抽出される
'=================================

'とりあえず 200万行(ファイル数が多ければ改変)
dim x(2000000),y(2000000)

'ファイルサーバ1のコマンド結果ファイル
a = "result_old.txt"

'ファイルサーバ2のコマンド結果ファイル
b = "result_new.txt"

'ファイルサーバ1に存在して、ファイルサーバ2に存在しない行を抽出
outfile = "旧にあって新にないファイル名.txt"

Dim objFSO      ' FileSystemObject
Dim objFile     ' ファイル読み込み用

'=================================
' ファイルサーバ1
'=================================

Set objFSO = WScript.CreateObject("Scripting.FileSystemObject")
i = 0

If Err.Number = 0 Then
    Set objFile = objFSO.OpenTextFile(a)
    If Err.Number = 0 Then

        Do While objFile.AtEndOfStream <> True
            x(i)= objFile.ReadLine
	    i = i + 1
        Loop

        objFile.Close
    Else
        WScript.Echo "ファイルオープンエラー: " & Err.Description
    End If
Else
    WScript.Echo "エラー: " & Err.Description
End If

'配列xの、最後の行数をmaxxと定義する
maxx = i - 1

Set objFile = Nothing
Set objFSO = Nothing

'=================================
' ファイルサーバ2
'=================================

Set objFSO = WScript.CreateObject("Scripting.FileSystemObject")
i = 0

If Err.Number = 0 Then
    Set objFile = objFSO.OpenTextFile(b)
    If Err.Number = 0 Then

        Do While objFile.AtEndOfStream <> True
            y(i)= objFile.ReadLine
	    i = i + 1
        Loop

        objFile.Close
    Else
        WScript.Echo "ファイルオープンエラー: " & Err.Description
    End If
Else
    WScript.Echo "エラー: " & Err.Description
End If

'配列yの、最後の行数をmaxyと定義する
maxy = i - 1


Set objFile = Nothing
Set objFSO = Nothing


Set objFSO = WScript.CreateObject("Scripting.FileSystemObject")
	Set objFile = objFSO.OpenTextFile(outfile , 2, True)

'配列xの、最後の行数をmaxxと定義する
'配列yの、最後の行数をmaxyと定義する

'配列xの、最初の行数をminxと定義する
'配列yの、最初の行数をminyと定義する
minx = 0
miny = 0

'=================================
' 比較
'=================================

'ループ1
for i = minx to maxx
	
	cnt = 0 '同じファイル名未検出の状態を cnt = 0とする

'進捗見たいので、50000件ごとにメッセージボックスを表示
	if i mod 50000 = 0 then 
		msgbox(i & " " & x(i))
		msgbox(i & " " & y(i))
	end if

'検索範囲を狭めたいので、検索範囲の最大値をmaxyyと定義する
'ファイルサーバ1とファイルサーバ2の差異があまり多くなかったので・・・
	maxyy = miny + 10000
	if maxyy > maxy then maxyy = maxy

'ループ2(ネスト)
	for j = miny to maxyy
		if x(i) = y(j) then
		
		'同じファイル名検出された場合は、次以降検索範囲を狭めたい
		'検索範囲の最小値を現在の行としたいが、それだと取りこぼしの可能性がある
		'そのため、現在の行-5000を検索範囲の最小値 miny と再定義する
			miny = j - 5000
			if miny <= 0 then miny = 0 
		
		'同じファイル名を検出したら cnt = 1 としてループ2を抜ける
			cnt = 1
			exit for
		end if
	next

'ループ2抜けたときに、未検出のままだったら、outfileにそのファイル名を書き込み		
	if cnt=0 then objFile.WriteLine x(i)
next

msgbox("作業完了")