複数のファイルをマージする

1.概要

パソコンで色んなデータを扱う場合、複数ファイルの連結(マージ)する作業は比較的多いと思います。 筆者の場合は、Excel VBAやPythonなどで作成したスクレイピングプログラムでWeb上から収集したデータを CSVなどに出力して加工する場合も多いです。このようなデータを蓄積して1つのファイルに連結(マージ)後、 DB(データベース)を新規作成して、初期インポート用のファイルとして利用しています。 定期的に決まったフォーマットで同じ作業のものは、簡単なバッチファイル(bat)を作って実行させています。 バッチファイルは、WMI(Windows Management Instrumentation)やPower Shellの登場で枯れた技術のように 思われがちですが、企業のIT部門などでは、まだまだ、広く利用されていて現役で活躍しています。 手軽で簡単であり、高速性を求めなければ便利ですね。ただ、会社なとでバッチファイルを他の人に使わせようとした時に、 マージ対象とするファイルやディレクリ―が変更となった場合やマージ後の出力ファイル名が他のシステムと 関連していたりすると、当然変更が必要となるため、その都度、作成者が面倒を見ることになります。 そのような事情から、他の人が使うことを前提とした場合は、GUIで操作画面がある実行形式(exe)のツール があった方が便利です。今回は、筆者が作成したマージツールを紹介します。

2.ファイルマージツール

2-1.ソースコード

概要で説明しましたが、バッチファイルによる簡単なサンプルを載せておきます。下記のサンプルですが、 必要に応じて、9行目のタイトル名と17行目の処理対象ファイルの拡張子(ワイルドカード)とマージ後の出力ファイル名 を適時修正して利用して下さい。マージ対象ファイルが格納されているディレクトリーは指定していませんので、 追加するか、同一ディレクリ―にバッチファイルを置いて実行させて下さい。どこにでもある簡単なものですみません。 雛形として利用して頂けたらと思います。バッチの命令としては、type命令copy命令で同等の処理ができますが、 copy命令の方がやや高速に処理できるようです。

@echo off
setlocal
cd /d %~dp0

echo.
echo.
echo ***********************************************************
echo.
echo    CSVファイルのマージ処理
echo.
echo.
echo ***********************************************************
echo.
echo.

rem ***** マージ開始 *****
copy *.csv > CSVマージ済み.csv

echo 処理が完了しました。何かキーを押してください。
echo.

pause >nul
endlocal
exit

続いて紹介するのが、テキストファイルマージツールです。プログラム言語は、HSP(Hot soup Processer)3.51で 作成しています。HSPとは、20年以上前からサポートが続けられて進化している国産のスクリプト言語です。 最近では、M-1グランプリで優勝したマジカルラブリーの野田クリスタルさんが自作ゲームの開発に利用していることが 話題となり、再び注目されています。HSPに興味がありましたら、下記の公式サイトを覗いてみて下さい。 筆者もちょつとしたツールやアクセサリーなどを開発するのに20年以上前から愛用しています。

プログラミング言語HSP公式サイト : HSPTV
URL : http://hsp.tv/index2.html

下記のリストは、今回紹介するテキストファイルマージツール(tfmarge)のHSPソースコード(HSPユーザー向け)です。 HSPの開発環境を構築している人は、HSPのスクリプトエディタに読み込み、実行して見て下さい。 HSPの開発環境をインストールしていない場合は、HSP公式サイトから入手して下さい。

マージ処理は、bload命令とbsave命令によるファイルのオフセット値を指定しての読み込みと書き込み による処理のため、比較的高速な処理が実現できています。一応、バイナリーデータもマージ可能です。
	;***** テキストファイルマージ (tfmarge.hsp) *****
	
	;***** 実行ファイル自動作成 ****
	#packopt type 0
	#packopt name "tfmarge"
	#packopt runtime "hsprt"
	#packopt hide 1

	;***** notepad命令形式文字列ソート *****
	#module
	#uselib "kernel32.dll"
	#cfunc lstrcmp "lstrcmpA" int,int
	
	#deffunc ntsort var buf,int flag
	sdim buf2,99999
	notesel buf : max=notemax
	repeat max
	sdim temp,256
	notesel buf : noteget temp,cnt
	repeat max
		sdim temp2,256
		notesel buf2 : noteget temp2,cnt
		if temp2="" : noteadd temp,cnt : break
		ret=lstrcmp(varptr(temp),varptr(temp2))
		if flag=0{
			if ret<0 {	;昇順
			noteadd temp,cnt
			break
			}
		}else{
			if ret>0 {	;降順
			noteadd temp,cnt
			break
			}
		}
		loop
	loop
	buf=buf2
	return
	#global

	#ifndef xdim
	#uselib "kernel32.dll"
	#func global VirtualProtect@_xdim "VirtualProtect" var,int,int,var
	#define global xdim(%1,%2) dim %1,%2: VirtualProtect@_xdim %1,%2*4,$40,x@_xdim
	#endif

	#module
	#uselib "ole32.dll"
	#func  CoTaskMemFree "CoTaskMemFree" int
	#uselib "shell32.dll"
	#cfunc SHBrowseForFolder "SHBrowseForFolderA" int
	#cfunc SHGetPathFromIDList "SHGetPathFromIDListA" int,int
	#uselib "user32.dll"
	#func  SendMessage "SendMessageA" int,int,int,int

	#deffunc BrowseFolder str _szTitle, str _defaultfolder
		szTitle = _szTitle : inifldr = _defaultfolder : sdim retfldr, 260 : xdim fncode, 8
		fncode = $08247c83,$8b147501,$ff102444,$68016a30,$00000466,$102474ff,$330450ff,$0010c2c0
		hbdata = varptr(inifldr), varptr(SendMessage)
		BROWSEINFO = hwnd, 0, varptr(retfldr), varptr(szTitle), 3, varptr(fncode), varptr(hbdata), 0
		pidl = SHBrowseForFolder(varptr(BROWSEINFO))
		fret = SHGetPathFromIDList(pidl,varptr(retfldr))
		CoTaskMemFree pidl
		mref stt,64 : stt = fret
	return retfldr
	#global

	#uselib "comctl32.dll"
	#func  InitCommonControlsEx "InitCommonControlsEx" sptr
	#cfunc CreateStatusWindow "CreateStatusWindow" int,sptr,int,int
	#uselib  "user32.dll"
	#func  DestroyWindow "DestroyWindow" int
	#func  InvalidateRect "InvalidateRect" int,int,int
	#func  GetWindowRect "GetWindowRect" int,var

	#define VER_TFAPPRI 1.0
	#define MAXPATH		260
	#define CB_GETLBTEXT    $00000148  
	#define EM_SETMARGINS	$000000D3
	#define EC_LEFTMARGIN	$00000001
	#define EC_RIGHTMARGIN	$00000002
	#define SB_SETTEXT		$00000401
	#define ctype MAKELONG(%1,%2) (%1&$ffff|(%2<<16))

	sdim instdir, MAXPATH
	sdim genename,MAXPATH
	sdim Folder,  MAXPATH
	sdim tmpstr,64
	sdim s,1024*5
	sdim buf
	sdim cb
	sdim temp
	sdim outname,48
	
	;***** 起動ディレクトリ取得 *****
	if hspstat&1=0 { instdir=dirinfo(1)+"¥¥" : chdir dirinfo(1)
	} else {
		instdir=dirinfo(0)+"¥¥"
	}
	;***** GUI画面作成 *****
	screen 0,580,200,0
	sysfont 17  : syscolor 8
	BarName="テキストファイルマージ Ver"+strf("%.1f",VER_TFAPPRI)+"  (tfmarge)"
	title BarName
	font "Meiryo UI",12,0 : objmode 2
	color 0,0,0 : pos 11,15 : mes "対象先"	
	pos 55,11 : input Folder,400,20
	sendmsg objinfo(0,2), EM_SETMARGINS, EC_LEFTMARGIN|EC_RIGHTMARGIN,MAKELONG(2,0)
	objsize 46,24 : pos 459,8: button "参照", *dirset
	wcard="*.*¥n*.txt¥n*.dat¥n*.csv¥n*.htm¥n*.html¥n*.css¥n*.xml¥n*.log"
	pos 11,43 : mes "拡張子"
	font "Meiryo UI",14,0 : objmode 2
	n=1 : objsize 80,24 : pos 55,38: combox n,120,wcard
	font "Meiryo UI",12,0 : objmode 2
	pos 150,43 : mes "出力ファイル名"
	font "Meiryo UI",12,0 : objmode 2
	pos 235,40 : input outname,220,20
	sendmsg objinfo(3,2), EM_SETMARGINS, EC_LEFTMARGIN|EC_RIGHTMARGIN,MAKELONG(2,0)
	objsize 46,24 : pos 459,37: button gosub "自動", *autoname
	objsize 60,50 : pos 510,11: button "マージ", *marge

	;***** StatusBar object setting *****
	gosub *statusGen
	gosub *statusMsg
	gosub *statusstring

	gsel 0,1
	;***** 割込み処理 *****
	onexit goto  *owari
	onclick gosub *msgclr
	stop

*dirset
	;***** フォルダ選択ダイアログを起動 *****
    BrowseFolder "フォルダを選択してください", dir_cur
    if stat {
        Folder = refstr+"¥¥"
    }
    objprm 0,Folder
	stop

*autoname
	;***** 日付時刻をファイル名と仮設定する *****
	outname =str(gettime(0))
	outname+=strf("%02d",gettime(1))
	outname+=strf("%02d",gettime(3))
	outname+=strf("%02d",gettime(4))
	outname+=strf("%02d",gettime(5))
	outname+=strf("%02d",gettime(6))
	;コンボボックスの選択文字列を取得(拡張子)
	sendmsg objinfo(2,2),CB_GETLBTEXT,n,varptr(temp) 
	p=strlen(temp)
	outname+=strmid(temp,1,p-1)
	objprm 3,outname
	return

*statusMsg
	;***** ステータスバー初期メッセージ *****
	String=" ファイルマージ(連結)する対象先ディレクトリを指定して下さい。"
	return

*statusGen
	;***** ステータスバーを作成 *****
	InitCommonControlsEx icx : String=""
	stshwnd=CreateStatusWindow($50000803,String,hwnd,0)
	InvalidateRect stshwnd,0,1
	dim rc,4 : GetWindowRect stshwnd,rc : sh = rc(3)-rc(1)
	return

*statusstring
	;***** ステータスバーに文字列を設定 *****
	sendmsg stshwnd,SB_SETTEXT,0,varptr(String)
	return

*msgclr
	;***** メッセージクリア *****
	color 255,255,255 : boxf 19,109,320,122 : color 0,0,0
	return

*marge
	;***** マージ処理開始 *****
	gosub *msgclr
	if Folder="" {
		dialog "ファイルマージする対象フォルダを指定して下さい。",0
		stop
	}
	chdir Folder
	; 指定ディレクトリのファイル名のみを取得
	sendmsg objinfo(2,2),CB_GETLBTEXT,n,varptr(cb) 
	dirlist s,cb,1 : num=stat
	
	; ファイル名を五十音別に昇順ソート
	ntsort s, 0
	; 出力ファイルの空の実体を作成する
	notesel buf
	if outname="" {
		String=" 出力ファイル名が省略されたので、日付時刻のファイル名を仮設定しました。"
		gosub *statusstring
		gosub *autoname
	}
	genename=Folder+outname
	notesave genename
	notesel s
	
	; 1個目のファイルをマージする
	noteget tmpstr,0
	exist Folder+tmpstr
	if strsize=-1 {
		dialog "指定したディレクトリにはファイルがありません。",0 : stop
	}
	sdim filebuf,strsize
	bload Folder+tmpstr,filebuf,strsize
	bsave genename,filebuf,strsize,0
	offset=strsize

	; n個目のファイルをマージする
	repeat num,1
		noteget tmpstr,cnt
		exist Folder+tmpstr : sdim filebuf,strsize
		if strsize=-1 : break
		bload Folder+tmpstr,filebuf,strsize
		bsave genename,filebuf,strsize,offset
		fsize =strsize : offset+=fsize
	loop
	exist genename
	pos 20,110 : mes "ファイルのマージ処理が完了しました。"+"   "+strsize+"byte"
	outname = ""
	gosub *statusMsg
	gosub *statusstring
	stop
	
*owari
	;***** 終了処理  *****
	onexit 0
	DestroyWindow stshwnd
	end

2-2.ツールの使い方

テキストファイルマージツール(tfmarge)の使い方です。ツールをダウンロードしたら、任意の場所で解凍して下さい。
    (1)tfmarge.exeをダブルクリックして起動させます。
    (2)連結(マージ)対象のファイルが格納されているディレクリ―を参照ボタンをクリックして
         選択します。
    (3)拡張子をプルダウンよりクリックして選択します。
    (4)マージ後の出力ファイル名(拡張子含む)を入力します。自動ボタンをクリックすると
         日付時刻形式のファイル名が作成されます。※省略時も同じです。
    (5)マージボタンをクリックしてマージ処理を実行します。
    (5)マージ対象ファイル数や容量にも依りますが、比較的高速に処理されます。
         完了後、tfmarge.exeを閉じて下さい。
プルダウンより指定できる拡張子は限られますが、マージ対象とするファイルフォルダに拡張子は違うけど、 同一フォーマットのデータを入れて、プルダウンで*.*を選択すれば全てのファイルがマージに対応可能となります。

3.ダウンロード

掲載しているソースコードのライセンスは、CC0 (クレジット表示不要、改変可、商用可) とします。自由に利用して頂いてかまいません。 テキストファイルマージツール(tfmarge)は下記からダウンロードして下さい。ソースコードも同梱しています。

ダウンロード

コメント

このブログの人気の投稿

Excelアドインで日本語形態素解析

階層構造JSONファイルの作成

HSPでコマンドプロンプトを制御する

TOP