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