2010年5月19日水曜日

SQL-Server 2008 Expressのクエリーから、ファイルのコード変換をするクエリーをSQLCLRで作る






かなり具合が悪くて仕事を休んでしまいましたが、寝ているのはかなり辛いものですね。頭がにぶると困るので、布団の中で今回の記事の題材を作ってました。

今回の記事では、SQL-Server 2008 Experssのクエリーから、ファイルのコード変換が出来る関数を作ってみました。
Shift_JISのファイルをEBCDICコードのファイルに変換する関数(SQLCLR_JtoE)、逆に、EBCDICのファイルをShift_JISに、任意のレコード長に揃えて変換する関数(SQLCLR_EtoJ)です。

コアとなる関数を一つ作り、内部的にそのコア関数をパラメータ変えて呼び出すように作ってあります。

プライベートではほとんど使わないでしょうけど、仕事でやってると、EBCDICとShift_JISのファイルのコード変換ってめちゃくちゃ使用頻度が高かったりします。

SQL-Serverのクエリーから直接ファイル変換ができちゃうとなると、ストアドプロシージャ一本でプログラムが済んだりして、結構プログラム設計が変わってゆくのではないでしょうか。

(SQLCLRの登録などは過去の記事をご参考になさって下さい。)

■実行例■

-- ----------------------------
-- Shift_JISファイルを、
-- EBCDICファイルに変換
-- ----------------------------
SELECT dbo.SQLCLR_JtoE('C:\TEST\SJIS.TXT','C:\TEST\EBCDIC.000');


-- ----------------------------
-- EBCDICファイルを、
-- Shift_JISファイルに変換
-- 16バイト長で出力する場合
-- バイト長は任意。でも割り切れない場合は空白で補完して整列。
-- ----------------------------
SELECT dbo.SQLCLR_EtoJ('C:\TEST\EBCDIC.000','C:\TEST\MODORI_SJIS.TXT',16);


■コード■

(無償版のVisual C# 2010 Expressでプログラムを書いています。)
(インデントは消えています。)
(全角の<>は半角に読み替えて下さい)

//*******************************************************************************
//* 列挙体
//*******************************************************************************
//-------------------------------------
// EJ変換モード
//-------------------------------------
private enum ConvertMode
{
EBCDIC_to_SJIS = 1, //EBCDICコードからSJISコード変換
SJIS_to_EBCDIC //SJISコードからEBCDICコード変換
}

//*******************************************************************************
// * ローカル関数
//*******************************************************************************
//------------------------------------
//EJファイルコード変換コア関数
//------------------------------------
private static Int32 Core_EJConvert(
string p_input_name,
string p_output_name,
Int32 p_length,
ConvertMode p_conv_mode
)
{
//エンコーダ
Encoding enc_input = null;
Encoding enc_output = null;
//変換元ファイル用
StreamReader obj_R = null;
//変換先ファイル用
StreamWriter obj_W = null;
//インデックス
Int32 i;
//変換元ファイル内容読み込みレコードエリア
string str_rec;
//結果格納エリア
Int32 int_result = 0;

try
{
//モードに応じたエンコーダーの決定
if (p_conv_mode.Equals(ConvertMode.EBCDIC_to_SJIS))
{
enc_input = Encoding.GetEncoding("IBM290");
enc_output = Encoding.GetEncoding("Shift_JIS");
}
else if (p_conv_mode.Equals(ConvertMode.SJIS_to_EBCDIC))
{
enc_input = Encoding.GetEncoding("Shift_JIS");
enc_output = Encoding.GetEncoding("IBM290");
}


//変換元ファイルのオープン
obj_R = new StreamReader(p_input_name, enc_input);
//変換先ファイルのオープン
obj_W = new StreamWriter(p_output_name, false, enc_output);

//モードに応じた変換
if (p_conv_mode.Equals(ConvertMode.EBCDIC_to_SJIS))
{ //EBCDICファイルからShift_JISファイルへの変換
//EBCDICファイルは一括して読み込まれる
str_rec = obj_R.ReadLine();

//全体のレコード長に対して中途半端な出力長が指定された場合の対策
if (str_rec.Length % p_length != 0)
{ //スペースで端数部分を補完する。
str_rec += new String(' ', p_length - (str_rec.Length % p_length));
}
int_result = str_rec.Length;

//@@@@@@@@@@[LOOP-START]@@@@@@@@@@
for (i = 0; i < str_rec.Length; i += p_length)
{
obj_W.WriteLine(str_rec.Substring(i, p_length));
}
//@@@@@@@@@@[LOOP-END ]@@@@@@@@@@
}
else if (p_conv_mode.Equals(ConvertMode.SJIS_to_EBCDIC))
{ //Shift_JISからEBCDICファイルへの変換
//@@@@@@@@@@[LOOP-START]@@@@@@@@@@
while (!(obj_R.EndOfStream))
{
str_rec = obj_R.ReadLine();
int_result += str_rec.Length;
obj_W.Write(str_rec);
}
//@@@@@@@@@@[LOOP-END ]@@@@@@@@@@
}

}
catch (System.Exception obj_err)
{
throw obj_err;
}
finally
{
if (obj_R != null)
{
obj_R.Close();
obj_R.Dispose();
}
if (obj_W != null)
{
obj_W.Close();
obj_W.Dispose();
}
}
return int_result;
}

//-------------------------------------
//Shift_JISファイルのEBCDIC変換
//-------------------------------------
[Microsoft.SqlServer.Server.SqlFunction]
public static SqlInt32 SQLCLR_JtoE(
SqlString p_input_name,
SqlString p_output_name
)
{
Int32 int_result = 0;
try
{ //自作関数Core_EJConvert()をJ->Eモードで使用
int_result = Core_EJConvert(
(string)p_input_name,
(string)p_output_name,
0,
ConvertMode.SJIS_to_EBCDIC
);
}
catch (System.Exception obj_err)
{ //例外が発生したらSQL-Serverに投げつけて強制終了させる
throw obj_err;
}
return (SqlInt32)int_result;
}


■SQL関数インターフェース■

-- *******************************************************
-- SQLCLRの関数インターフェース
-- *******************************************************
-- ----------------------------------------------
-- Shift_JISコードファイルをEBCDICコードファイル変換
-- (パラメータ説明)
-- @p_input_name : 変換したいShift_JISコードのファイル名(フルパス)
-- @p_output_name: 変換先のEBCDICコードファイル(フルパス)
-- -----------------------------------------------
create function SQLCLR_JtoE(
@p_input_name nvarchar(max),
@p_output_name nvarchar(max)
)
RETURNS int
AS EXTERNAL NAME ASSEMBLY_SQLCLR.CLS_SQLCLR.SQLCLR_JtoE;
GO

-- ----------------------------------------------
-- EBCDICコードファイルをShift_JISコードファイル変換
-- (パラメータ説明)
-- @p_input_name : 変換したいShift_JISコードのファイル名(フルパス)
-- @p_output_name: 変換先のEBCDICコードファイル(フルパス)
-- @p_length : レコード長(割り切れない時は空白で自動整列)
-- -----------------------------------------------
create function SQLCLR_EtoJ(
@p_input_name nvarchar(max),
@p_output_name nvarchar(max),
@p_length int
)
RETURNS int
AS EXTERNAL NAME ASSEMBLY_SQLCLR.CLS_SQLCLR.SQLCLR_EtoJ;
GO