CSVファイルの差分を出力するツールをつくってみた
ファイルの差分を比較するツールは沢山出回っているものの
自分が欲しいと思えるものがなかったので
2つのCSVファイルの差分を出力するツールをつくってみた。
引数でキーとなる行番号を指定して、
キーの値が異なれば別行に出力するシンプルなツールです。
CSVDiff.java
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* CSV差分出力
*/
public class CSVDiff {
private String split = null;
/**
* 区切り文字
*/
private String delimiter = null ;
/**
* キー項目のインデックス
* ※0始まり
*/
private List<Integer> keyIndex = null;
/**
* 取込ファイル配置フォルダ
*/
private String inputDir = null ;
/**
* 取込ファイル1
*/
private String inputFile1 = null ;
/**
* 取込ファイル2
*/
private String inputFile2 = null ;
/**
* 差分ファイル出力フォルダ
*/
private String outputDir = null ;
/**
* */
private List<String[]> recordList1 = null;
/**
* */
private List<String[]> recordList2 = null;
private List <String> outputList = null ;
/**
* コンストラクタ
* @param delimiterType 区切り文字種別(1:カンマ 1以外:タブ)
* @param args キー項目のインデックス
* @param inputDir 取込ファイル配置フォルダ
* @param inputFile1 取込ファイル1
* @param inputFile2 取込ファイル2
* @param outputDir 差分ファイル出力フォルダ
*/
public CSVDiff(String delimiterType, String args, String inputDir, String inputFile1, String inputFile2,String outputDir) {
//================================================================================
// 1.区切り文字種別判定
//================================================================================
if ("1".equals(delimiterType)) {
this.delimiter = ",";
} else {
this.delimiter = "\t";
}
this.split = "*" + this.delimiter + "*" + this.delimiter + "*";
//================================================================================
// 2.レコード比較時のキー項目インデックスを配列に変換する
//================================================================================
this.keyIndex = new ArrayList<Integer> ();
String arr[] = args.split(",");
for (String item : arr) {
int index = Integer.parseInt(item);
if (! this.keyIndex.contains(index) ) {
this.keyIndex.add(index);
}
}
//================================================================================
// 3.各種フォルダ名、ファイル名を設定
//================================================================================
this.inputDir = inputDir;
this.outputDir = outputDir;
this.inputFile1 = inputFile1;
this.inputFile2 = inputFile2;
}
/**
*
* @param outputType
* @param array1
* @param array2
* @return
*/
private String makeRecord (int outputType,String[] array1 ,String[] array2) {
StringBuilder outputRecord = new StringBuilder() ;
if (outputType == 0) {
//================================================================================
// レコード1=レコード2
// → レコード1、レコード2を出力
//================================================================================
//--------------------------------------------------------------------------------
// レコード1出力
//--------------------------------------------------------------------------------
for ( int i=0;i<array1.length;i++) {
if (i == 0) {
outputRecord.append(array1[i]);
} else {
outputRecord.append(this.delimiter + array1[i]);
}
}
//--------------------------------------------------------------------------------
// 区切り文字出力
//--------------------------------------------------------------------------------
outputRecord.append(this.delimiter);
outputRecord.append(split);
//--------------------------------------------------------------------------------
// レコード2出力
//--------------------------------------------------------------------------------
for ( int i=0;i<array2.length;i++) {
outputRecord.append(this.delimiter + array2[i]);
}
} else if (outputType == 1) {
//================================================================================
// レコード1<レコード2
// → レコード1のみ出力
//================================================================================
//--------------------------------------------------------------------------------
// レコード1出力
//--------------------------------------------------------------------------------
for ( int i=0;i<array1.length;i++) {
if (i == 0) {
outputRecord.append(array1[i]);
} else {
outputRecord.append(this.delimiter + array1[i]);
}
}
//--------------------------------------------------------------------------------
// 区切り文字出力
//--------------------------------------------------------------------------------
outputRecord.append(this.delimiter);
outputRecord.append(split);
//--------------------------------------------------------------------------------
// レコード2出力(カンマorタブのみ)
//--------------------------------------------------------------------------------
for ( int i=0;i<array1.length;i++) {
outputRecord.append(this.delimiter);
}
} else if (outputType == 2) {
//================================================================================
// レコード1>レコード2
// → レコード2のみ出力
//================================================================================
//--------------------------------------------------------------------------------
// レコード1出力(カンマorタブのみ)
//--------------------------------------------------------------------------------
for ( int i=0;i<array2.length;i++) {
outputRecord.append(this.delimiter);
}
//--------------------------------------------------------------------------------
// 区切り文字出力
//--------------------------------------------------------------------------------
// outputRecord.append(this.delimiter);
outputRecord.append(split);
//--------------------------------------------------------------------------------
// レコード2出力
//--------------------------------------------------------------------------------
for ( int i=0;i<array2.length;i++) {
outputRecord.append(this.delimiter + array2[i]);
}
}
return outputRecord.toString();
}
/**
* CSV差分リスト出力
* @return 0:正常終了 1:異常終了
*/
protected int outputCSVDiff () {
boolean isError = false ;
// --------------------------------------------------------------------------------
// (1)取込・出力ファイル、フォルダ存在チェック
// --------------------------------------------------------------------------------
if (this.checkFileExists() != 0) {
System.err.println("取込・出力用のファイルまたはフォルダが存在しません");
return 1;
}
// --------------------------------------------------------------------------------
// (1)ファイル読込
// --------------------------------------------------------------------------------
if (this.readFile() != 0) {
System.err.println("ファイル読込エラー");
return 1;
}
// --------------------------------------------------------------------------------
// (2)出力用リスト生成
// --------------------------------------------------------------------------------
this.outputList = new ArrayList<String> () ;
int i_file1 = 0 ;
int i_file2 = 0 ;
while (i_file1 < this.recordList1.size() && i_file2 < this.recordList2.size()) {
String[] record1 = this.recordList1.get(i_file1);
String[] record2 = this.recordList2.get(i_file2);
String outputRecord = null ;
if (record1.length != record2.length) {
System.err.println("ファイル1とファイル2でレコード数に相違があります");
isError = true ;
break ;
}
//========================================================================
// キー項目一致判定
//========================================================================
int diffType = 0 ;
for (int keyIndex :this.keyIndex) {
if (record1[keyIndex].compareTo(record2[keyIndex]) < 0 ) {
// ファイル1レコード < ファイル2レコード
diffType = 1;
break;
} else if (record1[keyIndex].compareTo(record2[keyIndex]) > 0 ) {
// ファイル1レコード > ファイル2レコード
diffType = 2;
break;
}
}
if (diffType == 0) {
// ファイル1レコード=ファイル2レコード
outputRecord = this.makeRecord(diffType, record1, record2) ;
System.out.println(outputRecord);
this.outputList.add(outputRecord);
i_file1 ++;
i_file2 ++;
} else if (diffType == 1) {
// ファイル1レコード<ファイル2レコード
outputRecord = this.makeRecord(diffType, record1, null);
System.out.println(outputRecord);
this.outputList.add(outputRecord);
i_file1 ++;
} else {
// ファイル1レコード>ファイル2レコード
outputRecord = this.makeRecord(diffType, null, record2);
System.out.println(outputRecord);
this.outputList.add(outputRecord);
i_file2 ++;
}
} // end-of-while
if (isError) { return 1; }
while (i_file1 < this.recordList1.size() ) {
String[] record1 = this.recordList1.get(i_file1);
String outputRecord = this.makeRecord(1, record1, null);
System.out.println(outputRecord);
this.outputList.add(outputRecord);
i_file1 ++;
}
while (i_file2 < this.recordList2.size()) {
String[] record2 = this.recordList2.get(i_file2);
String outputRecord = this.makeRecord(2, null, record2) ;
System.out.println(outputRecord);
this.outputList.add(outputRecord);
i_file2 ++;
}
// --------------------------------------------------------------------------------
// (3)ファイル出力
// --------------------------------------------------------------------------------
this.writeFile();
return 0 ;
}
private void writeFile () {
FileOutputStream fos = null;
OutputStreamWriter osw = null;
// --------------------------------------------------------------------------------
// (1)出力ファイルタイムスタンプ生成
// --------------------------------------------------------------------------------
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
String fileName = "csvdiff_"+sdf.format(timestamp)+".txt" ;
try {
fos = new FileOutputStream(this.outputDir+"/"+fileName);
osw = new OutputStreamWriter(fos,"Shift_JIS");
for (String record : this.outputList) {
osw.write(record + "\r\n") ;
}
osw.close();
fos.close();
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (osw != null ) {
try {
osw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null ) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 取込・出力ファイル、フォルダの存在チェック
* @return 0: 取込・出力ファイル、フォルダあり 1: 取込・出力ファイル、フォルダのいずれか存在しない
*/
private int checkFileExists () {
// --------------------------------------------------------------------------------
// (1)取込ファイル1存在チェック
// --------------------------------------------------------------------------------
File file1 = new File(this.inputDir+"/"+this.inputFile1) ;
if (!file1.exists()) {
System.err.println("エラー -> 取込ファイル1『"+this.inputDir+"/"+this.inputFile1+"』が存在しません!!");
return 1;
}
// --------------------------------------------------------------------------------
// (2)取込ファイル2存在チェック
// --------------------------------------------------------------------------------
File file2 = new File(this.inputDir+"/"+this.inputFile2) ;
if (!file2.exists()) {
System.err.println("エラー -> 取込ファイル2『"+this.inputDir+"/"+this.inputFile2+"』が存在しません!!");
return 1;
}
// --------------------------------------------------------------------------------
// (3)出力ファイル配置フォルダチェック
// --------------------------------------------------------------------------------
File outputDir = new File(this.outputDir) ;
if (!outputDir.exists()) {
System.err.println("エラー -> 出力フォルダ『"+this.outputDir+"』が存在しません!!");
return 1;
}
return 0 ;
}
/**
* ファイルを読み込んで配列リストに設定する
* @return 0:読込OK 1:読込NG
*/
private int readFile() {
int retVal = 0 ;
File file1 = new File(this.inputDir+"/"+this.inputFile1) ;
File file2 = new File(this.inputDir+"/"+this.inputFile2) ;
try {
this.recordList1 = this.makeRecordList(file1);
this.recordList2 = this.makeRecordList(file2);
} catch (Exception e) {
e.printStackTrace();
retVal = 1;
}
return retVal;
}
/**
* CSVファイル内容を配列リストに詰め替える
* @param file
* @return
* @throws Exception
*/
private List<String[]> makeRecordList (File file) throws Exception {
boolean isError = false;
List<String[]> recordList = new ArrayList<String[]>() ;
FileInputStream fis = null;
InputStreamReader isr = null ;
BufferedReader br = null ;
try {
fis = new FileInputStream(file);
isr = new InputStreamReader(fis, Charset.forName("MS932"));
br = new BufferedReader(isr);
int i = 1 ;
String record = null ;
while((record = br.readLine()) != null) {
String[] recordArray = record.split(this.delimiter);
System.out.println("["+i+"]行目:"+Arrays.toString(recordArray));
recordList.add(recordArray);
// System.out.println("["+i_file1+"]行目:"+record);
i ++ ;
}
} catch(FileNotFoundException e ) {
e.printStackTrace();
isError = true;
} catch(IOException e ) {
e.printStackTrace();
isError = true;
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
isError = true;
}
}
if (isr != null) {
try {
isr.close();
} catch (IOException e) {
e.printStackTrace();
isError = true;
}
}
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
isError = true;
}
}
}
if (isError) { throw new Exception(); }
return recordList ;
}
以下は実行クラス
CSVDiffExecute.java
/**
* CSV差分出力実行クラス
*
*/
public class CSVDiffExecute {
/**
* メインメソッド
* @param args [0] 区切り文字種別 (1:カンマ 1以外:タブ)
* [1] キー項目のインデックス(半角カンマ区切りで複数指定可能)
* [2] 取込ファイル配置フォルダ
* [3] 取込ファイル1
* [4] 取込ファイル2
* [5] 差分ファイル出力フォルダ
*/
public static void main(String[] args) {
//================================================================================
// 引数チェック
//================================================================================
if (args.length != 6) {
System.err.println("エラー->引数の数が不足しています。");
System.exit(1);
}
//================================================================================
// CSV差分出力実行
//================================================================================
CSVDiff csvDiff = new CSVDiff(args[0], args[1], args[2], args[3], args[4], args[5]);
csvDiff.outputCSVDiff();
}
}
Author And Source
この問題について(CSVファイルの差分を出力するツールをつくってみた), 我々は、より多くの情報をここで見つけました https://qiita.com/amnavi/items/e11219730234e5c7a223著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .