« 2012年5月 | トップページ | 2013年12月 »

2013年10月

Java:文字コード変換ツールを作る(2)コマンドラインツール その1

今回は,前回の記事で作成した文字コード変換プログラムに機能追加してコマンドラインツールに仕立てます。今回作成するツールの仕様は以下になります。

【仕様】
1. コマンドライン引数にファイルまたはディレクトリのパスを指定することができる。
1.1. 引数にファイルが指定されたときは,そのファイルを変換処理する。
1.2. 引数にディレクトリが指定されたときは,そのディレクトリに含まれるファイルを一括変換する。
1.3. 引数が指定されていない場合は,カレントディレクトリに含まれるファイルを一括変換する。
2. 出力ファイルは入力ファイルと同じディレクトリに作成する。
3. 出力ファイルのファイル名は,入力ファイル名の拡張子の前に拡張子「utf8」を追加する。
  例:「XXX.txt」→「XXX.utf8.txt」
3.1. ファイル名に拡張子がない場合は,拡張子を「utf8」にする。

【実装】
以上の仕様を実現するために,必要な機能を実装していきます。

■出力ファイルのファイル名を生成する。

入力ファイルのファイル名から出力ファイルのファイル名を生成します。
処理内容は,入力ファイルのファイル名をピリオドで分割してからピリオドで連結し直します。このとき最後の連結の前に「utf8」を挿入します。

import java.io.File;
import java.util.regex.Pattern;

public class ConvtoUTF8
{
  //----------------------------------------------------------------------
  private static final String EXTENSION_NAME = "utf8";
  private static final Pattern PAT_SEPA_PERIOD = Pattern.compile("[.]");
  //----------------------------------------------------------------------
  /**
   * 拡張子を「.XX」から「.utf8.XX」に変更したファイル名を作る.
   * 拡張子がない場合は拡張子を「.utf8」にする.
   * @param file 入力ファイル.
   * @return 生成した出力ファイル名.
   */
   private static String buildOutputFileName (
     File  file)
   {
     StringBuilder buff = new StringBuilder();
     String fileName = file.getName();
     String[] sepas = PAT_SEPA_PERIOD.split(fileName);
     if (1 < sepas.length) {
       int maxlen = sepas.length - 1;
       int index = 0;
       for (; index < maxlen; index++) {
         buff.append(sepas[index]).append(".");
       }
       buff.append(EXTENSION_NAME).append(".").append(sepas[index]);
     }
     else {
       buff.append(fileName).append(".").append(EXTENSION_NAME);
     }
     return buff.toString();
   }
}

※上記コードでは,整形のため空白部分は全角スペースを使用しています。

■1入力ファイルに対して1出力ファイルを生成する。

処理対象が,1ファイルの場合とディレクトリの場合があるので,まず入力ファイル1つに対する変換処理をまとめたメソッドを作ります。二種類の処理はこのメソッドの呼び出し方の違いで実現します。

ここでは最初に出力ファイル名を生成しますが,生成した出力ファイル名と同名の入力ファイルが存在していた場合の対応としては,単に当該ファイルの変換処理をスキップしているだけです。

※下記コードの「ConvtoUTF8.convertFile(infile, outfile);」は前回作成したコード変換プログラムです。

import java.io.IOException;

public class ConvtoUTF8
{
  //----------------------------------------------------------------------
  /**
   * 1入力ファイルのコード変換処理を行う。
   * @param parent 入力ファイルが保存されているディレクトリ。
   * @param infile 入力ファイル。
   */
   private static void convertOneFile (
     File  parent,
     File  infile)
     throws IOException
   {
     if (infile.canRead()) {
       String outFileName = ConvtoUTF8.buildOutputFileName(infile);
       File outfile = new File(parent, outFileName);
       if (!outfile.exists()) {
         ConvtoUTF8.convertFile(infile, outfile);
         System.out.println(infile.getName());
       }
     }
   }
}

※上記コードでは,整形のため空白部分は全角スペースを使用しています。

■上記コードを起動するmain関数。

main関数の引数(args)にはコマンドライン引数が文字列の配列として格納されています。argsの最初の要素を処理対象のファイルまたはディレクトリパスとして取得します。
引数に何も指定されていない場合はargsは空の配列です。この場合はカレントディレクトリを処理対象にします。カレントディレクトリは「File dir = new File(".");」で取得することができます。

処理対象のファイルまたはディレクトリが確定したら,ファイルの場合はそのファイルに対して,ディレクトリの場合はディレクトリに含まれる各ファイルに対して,さきに作成したconvertOneFile()メソッドを実行して変換処理を行います。

例外のcatchはツール全体のうちmain関数でのみ行います。これにより処理中に例外が発生した場合は,それ以降の処理をすべてキャンセルしてmain関数のcatchを実行して処理を終了させます。

 //----------------------------------------------------------------------
 /**
  * @param args コマンドライン引数。ファイルまたはディレクトリパス指定として解釈する。
  */
 public static void main(String[] args)
 {
   try {
     String pathStr = (0 < args.length)? args[0]: ".";
     File path = new File(pathStr);
     if (path.isDirectory()) {
       File[] files = path.listFiles();
       for (File file : files) {
         if (file.canRead()) {
           ConvtoUTF8.convertOneFile(path, file);
         }
       }
     }
     else if (path.canRead()) {
       ConvtoUTF8.convertOneFile(path.getParentFile(), path);
     }
   }
   catch (Exception ex) {
     ex.printStackTrace();
   }
 }
※上記コードでは,整形のため空白部分は全角スペースを使用しています。

以上の処理と前回のコード変換を1つのクラス(「ConvtoUTF8」クラス)にまとめると,変換ツールが完成します。


【著作権表記】上記コードを含む本ブログのプログラムコードは,私的利用可,商用利用可,改変しての利用可です。利用の際に作者に許諾を得る必要はありません。

■関連書籍をAmazonで検索:[Java]
やさしいJava 第5版 (「やさしい」シリーズ)



にほんブログ村 IT技術ブログへ にほんブログ村 IT技術ブログ プログラム・プログラマへ 人気ブログランキングへ ←この記事が役に立ったという方はクリックお願いします。


ノートンスタンダードバナー上新電機 パソコン買取サービス

| | トラックバック (0)

Java:文字コード変換ツールを作る(1)文字コード変換

JavaのStringクラスは文字コード変換機能を備えています。今回はこの機能を使って,ファイルから読み込んだテキストを文字コード変換して新規テキストファイルに出力するプログラムを作ってみます。
変換する文字コードは,とりあえず「MS932」(Shift_JIS)から「UTF-8」への変換にしました。
加えて「テキストを行単位で読み込んで変換し,出力時に各行の終わりに改行を出力する」ことで,改行コードを揃える機能をもたせます。改行コードはCRLFを出力します。

■Stringクラスの文字コード変換

Stringクラスの文字列を,文字コードを指定して取り出すのは以下のようなコードになります。

String str = "文字列";
byte[] utf8bytes = str.getBytes("utf-8");
取り出した結果はbyteの配列になります。このバイト列をファイルに書き出します。

改行について,JavaにおけるCRLFの文字列表現は「"\r\n"」です。(「\」はバックスラッシュ)
これより,CRLFのバイト列は以下のように取得します。

byte[] CRLF = "\r\n".getBytes("utf-8");

改行コードは固定なので,クラス変数で定義しても良いかと思います。しかしながら,クラス変数として以下のように書くと,コンパイルエラーになってしまいます。
private static final byte[] CRLF = "\r\n".getBytes("utf-8");
エラーの内容は,「UnsupportedEncodingException」例外が起きる可能性があるのでその対応が必要,というものです。クラス変数の初期化で例外対応が必要な場合は少々工夫が必要になります。この場合の初期化コードは以下のようにして対応できます。
※例外に対する処理は,文字コード指定が固定なので特に行いません。
private static final byte[] CRLF;
static {
  try {
    CRLF = "\r\n".getBytes("utf-8");
  } catch (UnsupportedEncodingException ex) {}
}
※上記コードでは,整形のため空白部分は全角スペースを使用しています。

■ファイルからテキスト入力

テキストファイルから文字コードを指定してテキストを読み込む処理は以下のようになります。
Javaでのテキスト入力処理としてはポピュラーなものかと思います。
ここで入力ファイルの文字コードは「MS932」を指定しています。

File infile = new File(入力テキストファイルのパス表現);
 
FileInputStream   finst = null;
InputStreamReader reader = null;
BufferedReader   in = null;
 
try {
  finst = new FileInputStream(infile);
  reader = new InputStreamReader(finst, "MS932");
  in = new BufferedReader(reader);
 
  String line;
  while ((line = in.readLine()) != null) {
    // 1行ごとの入力テキスト(=line)に対する処理をここで行う.
  }
}
finally {
  try {
    if (in != null) { in.close(); }
  } catch (IOException ex) {}
}
※上記コードでは,整形のため空白部分は全角スペースを使用しています。
注:ここでは例外をcatchしません。例外が発生したときは,finallyで後始末をしたあとで,呼び出し元で例外をcatchすることとします。

■バイト列データをファイルに出力

変換したbyte配列をファイルに書き出す処理は以下のようになります。

File outfile = new File(出力テキストファイルのパス表現);
 
FileOutputStream   foutst = null;
BufferedOutputStream out = null;
try {
  foutst = new FileOutputStream(outfile);
  out = new BufferedOutputStream(foutst);
 
  // 出力するデータの例.
  byte[] utf8bytes = "文字列".getBytes("utf-8");
  byte[] CRLF = "\r\n".getBytes("utf-8");
 
  // データを出力する.
  out.write(utf8bytes);
  out.write(CRLF);
  out.flush();
}
finally {
  try {
    if (out != null) { out.close(); }
  } catch (IOException ex) {}
}
※上記コードでは,整形のため空白部分は全角スペースを使用しています。
注:ここでは例外をcatchしません。例外が発生したときは,finallyで後始末をしたあとで,呼び出し元で例外をcatchすることとします。

■以上からファイル変換メソッドを作る

これまでのコードをまとめて変換プログラムを作ると,以下のようになります。
※出力バッファサイズの指定を追加しています。
こちらの記事の内容を反映しています(2015/07/05)。

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
 
public class ConvtoUTF8
{
  //----------------------------------------------------------------------
  private static final String INPUT_ENCODING = "MS932";
  private static final String OUTPUT_ENCODING = "utf-8"; 
  private static final int   OUTPUT_BUFFER_SIZE = 1024*64;
  private static final byte[] CRLF;
  static {
    try {
      CRLF = "\r\n".getBytes(OUTPUT_ENCODING);
    } catch (UnsupportedEncodingException ex) {}
  }
  //----------------------------------------------------------------------
  /**
   * 入力ファイルを読み込んで変換処理を行い,出力ファイルに書き出す.
   * 変換内容は,1)文字コードをMS932からUTF-8へ. 2)改行コードをCRLFに統一.
   * @param infile  入力ファイル.
   * @param outfile 出力ファイル.
   * @throws IOException
   */
  private static void convertFile (
    File  infile,
    File  outfile)
    throws IOException
  {
    FileInputStream finst = null;
    InputStreamReader reader = null;
    BufferedReader in = null;
 
    FileOutputStream    foutst = null;
    BufferedOutputStream out = null;
    try {
      finst = new FileInputStream(infile);
      reader = new InputStreamReader(finst, INPUT_ENCODING);
      in = new BufferedReader(reader);
 
      foutst = new FileOutputStream(outfile);
      out = new BufferedOutputStream(foutst, OUTPUT_BUFFER_SIZE);
 
      String line;
      while ((line = in.readLine()) != null) {
        out.write(line.getBytes(OUTPUT_ENCODING));
        out.write(CRLF);
      }
      out.flush();
    }
    finally {
      try {
        if (out != null) { out.close(); }
      } catch (IOException ex) {}
      try {
        if (in != null) { in.close(); }
      } catch (IOException ex) {}
    }
  }
}
※上記コードでは,整形のため空白部分は全角スペースを使用しています。

次回の記事及び次々回の記事にて,上記コードを使って文字コード変換コマンドラインツールを作ります。


【著作権表記】上記コードを含む本ブログのプログラムコードは,私的利用可,商用利用可,改変しての利用可です。利用の際に作者に許諾を得る必要はありません。

■関連書籍をAmazonで検索:[Java]
EFFECTIVE JAVA 第2版 (The Java Series)



にほんブログ村 IT技術ブログへ にほんブログ村 IT技術ブログ プログラム・プログラマへ 人気ブログランキングへ ←この記事が役に立ったという方はクリックお願いします。


ドミノ・ピザ【PC向けサイト】

| | トラックバック (0)

« 2012年5月 | トップページ | 2013年12月 »