ファイル読み書きごにょごにょ(Java)

1. バイナリファイル読み書きごにょごにょ処理の目的

Windows環境でバイナリファイルを読み書きしてごにょごにょ (大量作成&ランダム削除) します。 ※Linux環境でも少し手を加えれば実行可能です。

Javaコンパイル&実行できる環境が前提です。

Eclipseなどは使用せず、javacコマンドでコンパイルし、実行するプログラムサンプルです。

以下のJavaプログラムノウハウを含んでいます。

  • ファイルの読み書き
  • スレッド

2.準備作業

2.1.準備するファイル

適当な画像ファイル(1MB程度)を3つ準備してください。名前は以下に変更しC:\temp 配下に格納してください。

  • test1.jpg
  • test2.png
  • test3.jpg
  • test4.png
  • test5.jpg

2.2.作成するファイル

C:\xxxxx>tree /F
C:.
├─classes
├─META-INF
│      MANIFEST.MF   (ファイルの内容は下記参照)
│
└─src
    └─frw         (Javaファイルの内容は本記事の最後に記載
         FileReadWriteManager.java
         FileReadWriteThread.java
         FileRemoveThread.java
         FileWriteExecute.java

2.2.1.MANIFEST.MF

メインクラスを記述します。

 Main-Class: frw.FileReadWriteManager 

2.2.2.frwフォルダ配下のJavaファイル

Windows環境の場合、「SJIS」で作成してください。「UTF-8」だとコンパイルエラーになります。Javaクラスの記述内容は「4.ごにょごにょするソース」を参照してください。

3.ごにょごにょの処理概要

3.1.スレッド管理処理

3.1.1.ログ出力準備&スレッド起動(FileReadWriteManager.java)

FileReadWriteManagerクラスにてログ出力の準備を行い、「ファイル読み込み~ファイル書込み」を行うスレッド、および「ファイル削除」を行うスレッドを別スレッドで起動し、起動したすべてのスレッドが終了するまで待機します。

3.2.各スレッドの処理

3.2.1. ファイル読み込み~ファイル書込み (FileReadWriteThread.java)

準備したファイルを読み込み、C:\temp 配下に書込みします。書き込んだ後は、1000ms待機します。この待機時間中に「3.2.2.ファイル削除」処理によって書込んだファイルが削除されることがあります。※スレッド処理の検証目的です。

3.2.2.ファイル削除 (FileRemoveThread.java)

「3.2.1.のファイル書込み処理」で作成されたファイルをランダムに削除します。

※作成時間をキーにしているので、削除されない場合もあります。

4.ごにょごにょするソース

4.1. FileWriteExecute .java

4.1.1. Java8の場合

package frw;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;

public class FileWriteExecute {

  private static final int BUFFER_SIZE = 4096;
  SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");

  Timestamp StreamToFileWrite(PrintWriter logFile, String logMsg, InputStream inFileStream,
      String destFileName) {

    ReadableByteChannel inCh = Channels.newChannel(inFileStream);

    Path dest = Paths.get(destFileName);
    Timestamp timestampE = null;
    Long writeTime = null;

    try {
      Timestamp timestampS = new Timestamp(System.currentTimeMillis());
      logFile.println(sdf.format(timestampS) + logMsg + "ファイル書込み開始");
      FileChannel destChannel = FileChannel.open(dest, StandardOpenOption.CREATE,
          StandardOpenOption.WRITE);

      ByteBuffer buf = ByteBuffer.allocateDirect(BUFFER_SIZE);

      while (inCh.read(buf) != -1) {
        buf.flip();
        destChannel.write(buf);
        buf.clear();
      }
      timestampE = new Timestamp(System.currentTimeMillis());
      writeTime = timestampE.getTime() - timestampS.getTime();
      logFile.println(sdf.format(timestampE) + logMsg + "ファイル書込み終了(処理時間:" + writeTime.toString() + "ms)");
      // ダイレクトバッファを早期に開放する
      Method cleanerMethod = buf.getClass().getMethod("cleaner");
      cleanerMethod.setAccessible(true);
      Object cleaner = cleanerMethod.invoke(buf);
      Method cleanMethod = cleaner.getClass().getMethod("clean");
      cleanMethod.setAccessible(true);
      cleanMethod.invoke(cleaner);

    } catch (Exception e) {
      e.printStackTrace();
    }

    return timestampE;
  }
}

4.1.2. Java6の場合

package frw;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;

public class FileWriteExecute {

  private static final int BUFFER_SIZE = 4096;
  SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");

  Timestamp StreamToFileWrite(PrintWriter logFile, String logMsg, InputStream inFileStream,
      String destFileName) {

    ReadableByteChannel inCh = Channels.newChannel(inFileStream);

    Timestamp timestampE = null;
    Long writeTime = null;

    try {
      FileOutputStream outStream = new FileOutputStream(destFileName);
      Timestamp timestampS = new Timestamp(System.currentTimeMillis());
      logFile.println(sdf.format(timestampS) + logMsg + "ファイル書込み開始");
      FileChannel destChannel = outStream.getChannel();

      ByteBuffer buf = ByteBuffer.allocateDirect(BUFFER_SIZE);

      while (inCh.read(buf) != -1) {
        buf.flip();
        destChannel.write(buf);
        buf.clear();
      }
      timestampE = new Timestamp(System.currentTimeMillis());
      writeTime = timestampE.getTime() - timestampS.getTime();
      logFile.println(sdf.format(timestampE) + logMsg + "ファイル書込み終了(処理時間:" + writeTime.toString() + "ms)");
      // ダイレクトバッファを早期に開放する
      Method cleanerMethod = buf.getClass().getMethod("cleaner");
      cleanerMethod.setAccessible(true);
      Object cleaner = cleanerMethod.invoke(buf);
      Method cleanMethod = cleaner.getClass().getMethod("clean");
      cleanMethod.setAccessible(true);
      cleanMethod.invoke(cleaner);
      outStream.close();

    } catch (Exception e) {
      e.printStackTrace();
    }

    return timestampE;
  }
}

4.2.FileRemoveThread.java

package frw;

import java.io.File;
import java.io.PrintWriter;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;

public class FileRemoveThread extends Thread {

  private SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
  private SimpleDateFormat sdfFname = new SimpleDateFormat("yyyyMMddHHmmss");
  private PrintWriter logFile;
  private int num;
  private String destPath;
  private String destFileSuffix1;
  private String destFileSuffix2;

  public FileRemoveThread(PrintWriter logFile, int num, String destPath, String destFileSuffix1,
      String destFileSuffix2) {
    this.logFile = logFile;
    this.num = num;
    this.destPath = destPath;
    this.destFileSuffix1 = destFileSuffix1;
    this.destFileSuffix2 = destFileSuffix2;
  }

  public void run() {

    for (int i = 0; i < 10; i++) {

      String logMsg = " FileRemoveThread[" + num + "]" + (i + 1) + "度目の";
      Timestamp timestamp = new Timestamp(System.currentTimeMillis());
      logFile.println(sdf.format(timestamp) + logMsg + "処理開始");

      try {
        Thread.sleep(500);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }

      for (int j = 300; j < 900; j++) {
        for (int k = 1; k < 6; k++) {
          String destFileName = destPath + sdfFname.format(timestamp) + j + destFileSuffix1 + k
              + destFileSuffix2;

          File file = new File(destFileName);

          // ファイルの存在を確認する
          if (file.exists()) {
            // ファイルを削除する
            file.delete();
            timestamp = new Timestamp(System.currentTimeMillis());
            logFile.println(sdf.format(timestamp) + logMsg + "処理でファイル(" + destFileName + ")を削除しました。");
          }
        }
      }

      timestamp = new Timestamp(System.currentTimeMillis());
      logFile.println(sdf.format(timestamp) + logMsg + "処理終了");

    }
  }
}

4.3.FileReadWriteThread.java

package frw;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;

public class FileReadWriteThread extends Thread {

  private static final int SLEEP_TIME = 1000;
  private SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
  private SimpleDateFormat sdfFname = new SimpleDateFormat("yyyyMMddHHmmssSSS");
  private PrintWriter logFile;
  private String srcFilePath;
  private String destPath;
  private String destFileSuffix;
  private int thNum;

  public FileReadWriteThread(PrintWriter logFile, String srcFilePath, String destPath, String destFileSuffix, int thNum) {
    this.logFile = logFile;
    this.srcFilePath = srcFilePath;
    this.destPath = destPath;
    this.destFileSuffix = destFileSuffix;
    this.thNum = thNum;
  }

  public void run() {

    Long checkTime = null;

    for (int i = 0; i < 5; i++) {

      // 入力ファイル
      InputStream inFileStream = null;
      try {
        inFileStream = new FileInputStream(srcFilePath);
      } catch (FileNotFoundException e1) {
        e1.printStackTrace();
      }
      String logMsg = " FileReadWriteThread[" + thNum + "]" + (i + 1) + "度目の";
      Timestamp timestamp = new Timestamp(System.currentTimeMillis());
      logFile.println(sdf.format(timestamp) + logMsg + "処理開始");

      FileWriteExecute cl = new FileWriteExecute();
      String destFileName = destPath + sdfFname.format(timestamp) + destFileSuffix;
      Timestamp timeE = cl.StreamToFileWrite(logFile, logMsg, inFileStream, destFileName);

      try {
        Thread.sleep(SLEEP_TIME);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      File file = new File(destFileName);
      timestamp = new Timestamp(System.currentTimeMillis());
      checkTime = timestamp.getTime() - timeE.getTime();
      // ファイルの存在を確認する
      if (file.exists()) {
        logFile.println(sdf.format(timestamp) + logMsg + "処理終了(" + checkTime.toString() + "ms後ファイル有)");
      } else {
        logFile.println(sdf.format(timestamp) + logMsg + "処理終了(" + checkTime.toString() + "ms後ファイル無)");
      }
    }
  }
}

4.4.FileReadWriteManager.java

package frw;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;

public class FileReadWriteManager {

  public static void main(String[] args) {

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
    String srcFilePath1 = "C:\\temp\\test1.jpg";
    String srcFilePath2 = "C:\\temp\\test2.png";
    String srcFilePath3 = "C:\\temp\\test3.jpg";
    String srcFilePath4 = "C:\\temp\\test4.png";
    String srcFilePath5 = "C:\\temp\\test5.jpg";
    String destFileSuffix1 = "Out1.jpg";
    String destFileSuffix2 = "Out2.png";
    String destFileSuffix3 = "Out3.jpg";
    String destFileSuffix4 = "Out4.png";
    String destFileSuffix5 = "Out5.jpg";
    String rmFileSuffix11 = "Out";
    String rmFileSuffix21 = ".jpg";
    String rmFileSuffix22 = ".png";
    String destPath = "C:\\temp\\";

    // FileWriterクラスのオブジェクトを生成する
    FileWriter file = null;
    try {
      file = new FileWriter("C:\\temp\\FileReadWriteManager.log", true);
    } catch (IOException e) {
      e.printStackTrace();
    }
    // PrintWriterクラスのオブジェクトを生成する
    PrintWriter logFile = new PrintWriter(new BufferedWriter(file));

    Timestamp timestamp = new Timestamp(System.currentTimeMillis());
    logFile.println(sdf.format(timestamp) + " FileReadWriteManager 処理開始");

    FileReadWriteThread mt1 = new FileReadWriteThread(logFile, srcFilePath1, destPath, destFileSuffix1, 1);
    FileReadWriteThread mt2 = new FileReadWriteThread(logFile, srcFilePath2, destPath, destFileSuffix2, 2);
    FileReadWriteThread mt3 = new FileReadWriteThread(logFile, srcFilePath3, destPath, destFileSuffix3, 3);
    FileReadWriteThread mt4 = new FileReadWriteThread(logFile, srcFilePath4, destPath, destFileSuffix4, 4);
    FileReadWriteThread mt5 = new FileReadWriteThread(logFile, srcFilePath5, destPath, destFileSuffix5, 5);
    FileRemoveThread mtrm1 = new FileRemoveThread(logFile, 1, destPath, rmFileSuffix11, rmFileSuffix21);
    FileRemoveThread mtrm2 = new FileRemoveThread(logFile, 2, destPath, rmFileSuffix11, rmFileSuffix22);
    mt1.start();
    mt2.start();
    mt3.start();
    mt4.start();
    mt5.start();
    mtrm1.start();
    mtrm2.start();

    try {
      timestamp = new Timestamp(System.currentTimeMillis());
      logFile.println(sdf.format(timestamp) + " FileReadWriteManager 別スレッドの処理を待機します");
      mt1.join();
      mt2.join();
      mt3.join();
      mt4.join();
      mt5.join();
      mtrm1.join();
      mtrm2.join();
      timestamp = new Timestamp(System.currentTimeMillis());
      logFile.println(sdf.format(timestamp) + " FileReadWriteManager 別スレッドの処理が終わりました");
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    timestamp = new Timestamp(System.currentTimeMillis());
    logFile.println(sdf.format(timestamp) + " FileReadWriteManager 処理終了");

    //ファイルを閉じる
    logFile.close();
  }

}

5.ソースのコンパイル&jar作成

5.1.Javaクラスのコンパイル

javacコマンドでコンパイルを行います。同パッケージ内でクラス参照しているので、コンパイルの順序に気をつけてください。

javac -sourcepath src -d classes src\frw\FileReadWriteExecute.java
C:\xxxxx>javac -sourcepath src -d classes src\frw\FileRemoveThread.java
C:\xxxxx>javac -sourcepath src -d classes src\frw\FileReadWriteThread.java
C:\xxxxx>javac -sourcepath src -d classes src\frw\FileReadWriteManager.java

5.2.jar作成

jarコマンドを使ってjarファイルを作成します。

 C:\xxxxx>jar cvfm sample.jar META-INF\MANIFEST.MF -C classes . 

5.3.jarファイルの確認

jarファイルの内容を確認します。

C:\xxxxx>jar tf sample.jar
META-INF/
META-INF/MANIFEST.MF
frw/
frw/FileReadWriteManager.class
frw/FileReadWriteThread.class
frw/FileRemoveThread.class
frw/FileWriteExecute.class

6.プログラムの実行

作成したjarファイルを実行します。

 C:\xxxxx>java -jar sample.jar 

ログファイル、および新しく作成されたファイルが C:\temp 配下に出力されます。

 C:\temp\FileReadWriteManager.log 
タイトルとURLをコピーしました