2005年9月26日月曜日

プログラミング言語の比較(3回目)

★JAVAで作成1(ioパッケージ利用)

JAVAでは、2通りの方法でファイルコピーを行えます。今回はその内の1つである、ioパッケージ利用編です。
JAVAのバージョンは1.4を使用します。

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class CopyByJava1 {
  public void execute(String src, String dest) throws IOException {
    int buffer_size = 2048;
    byte[] buffer = new byte[buffer_size];

    InputStream in = null;
    OutputStream out = null;
    try {
      // ファイルのオープン & ストリームのバッファサイズ指定
      in = new BufferedInputStream(new FileInputStream(src), buffer_size);
      out = new BufferedOutputStream(new FileOutputStream(dest), buffer_size);

      // コピー実行
      int readsize;
      while((readsize = in.read(buffer)) != -1) {
        out.write(buffer, 0, readsize);
      }
    }
    finally {
      // ファイルクローズ
      try {
        if(in != null) {
          in.close();
        }
      }
      catch(IOException e) {
      }
      try {
        if(out != null) {
          out.close();
        }
      }
      catch(IOException e) {
      }
    }
  }

  public static void main(String[] args) {
    if(args.length < 2) {
      System.out.println("java CopyByJava1 [コピー元ファイルパス] [コピー先ファイルパス]");
      return;
    }
    else if(args[0].equals(args[1])) {
      System.out.println("コピー元とコピー先が同じです。");
      return;
    }

    long start = System.currentTimeMillis();
    try {
      new CopyByJava1().execute(args[0], args[1]);
    }
    catch(IOException e) {
      e.printStackTrace();
      return;
    }
    long end = System.currentTimeMillis();
    System.out.println((end - start)/1000.0 + " 秒経過");
  }
}

前回と同じく、以下の項目をちょっとだけ見てみましょう。

  • クラス
  • 例外処理機構
  • リソースの解放

▽クラス

クラスが登場する点はC++と同じです。但し、自作しているCopyByJava1クラスがあります。

JAVAは単独でメソッド(C/C++における関数のこと)が存在出来ません。

必ず、クラスのメンバーとしてメソッドが存在します。このルールは mainメソッドにも当てはまる為、最低でも1つのクラスが必要になります。



▽例外処理機構

try-catchは同じです。但し、JAVAではfinallyが存在します。

tryブロックに処理が入った場合、例外の発生有無に関らず、必ずfinallyブロックを通ります。

処理が成功・失敗のいずれであっても、行う処理が有る場合にfinallyを用います。



▽リソースの解放

JAVAではC++と同じくクラスが登場する事は、先ほど説明しました。

では何故、C++で必要の無かったファイルのクローズを行っているのでしょう?

JAVAにはデストラクタが無いのでしょうか?それともFileInputStreamやFileOutputStreamクラスのデストラクタでは自動的にファイルをクローズしてくれないのでしょうか?

答えは否です。デストラクタに相当する物(finalizeメソッド)も有りますし、該当クラスのfinalizeメソッドでファイルのクローズも行われます。

JAVAでは、C/C++に無い機能としてガーベッジコレクションがあります。これにより、動的に確保したメモリ(上に構築されたクラス)の解放はプログラマが意識する必要が無いので、プログラマとしては非常に助かります。

しかし、ファイルディスクプリタやソケットなどの非メモリ・リソースはこの対象外であり、これらは(finalizeメソッドの中で処理すれば)メモリ回収のついでとして解
放されるだけです。

つまり、メモリ・リソースが潤沢に存在しても、非メモリ・リソースの不足が発生する可能性があります。この様な状態を極力起さない為には、プログラマが責任を持っ
て非メモリ・リソースの解放を行う事が必要になります。(その為に、先のfinallyを利用してファイルクローズを行っています)



次回は、もう1つのJAVAである、nioパッケージ利用編です。