仕事やプライベートで?受け取ったcsvのデータを、自分の思うようにちょっと加工したいときってありませんか?
項目の順番を入れ替えたり、文字列に加工したりして、自分の使いやすい形に整形したいというシーンは結構あると思います。
Script系の言語を使ったり、SedやAwkを使う!という人もいるでしょうね。私はjavaが使い慣れているので、今回はJavaを使ってみたいと思います。
いくつか便利なライブラリがあるようですが、私は、opencsvが使いやすいと思いました。
opencsvでは、csvファイルの読み込みの方法をいくつか指定することができます。
どの方法を利用して読み込みを行うかはMappingStrategyクラスを切り替えることで指定できます。
HeaderColumnNameTranslateMappingStrategy
HeaderColumnNameMappingStrategy
などはヘッダ項目をもつcsvファイルを扱うのに便利なクラスのようですね。私が今回利用したのはColumnPositionMappingStrategyクラスです。
csvファイルを簡単に加工するというのが目的ですので、読み込み/書き込みの記述が比較的シンプルな方法を選択しました。
目次
準備作業
コンパイルに必要なライブラリは以下の通りです。OpenCVはもちろん必要ですが、「commons-beanutils」と「org.apache.commons」も必要なので、詳細は、ここのdependenciesを確認しましょう。
※2016/09/01に再検証した時点では、以下のjarが必要でした。
- opencsv-3.8.jar
- commons-beanutils-1.9.2.jar
- commons-lang3-3.4.jar
実際に読み書きに使用するcsvファイルを適当なディレクトリに用意します。サンプルとして、「SampleIn.csv」というファイルをUTF-8の文字コードで作成しました。
key,name,pref,job
key1,name1,pref1,job1
key2,名前2,県2,お仕事2
上記のような内容のcsvで良いと思います。1行目がヘッダで、このヘッダ名をキーに下記の「String[]{“key”, “name”, “pref”, “job”}」で対応付けて読み取ります。
csvを扱うクラスの作成
まず、読み込み対象のcsvファイルの項目に対応する単純なJavaBeansクラスを定義します。項目さえ定義すれば、SetterとGetterはEclipseなどのIDEが自動で吐いてくれますよね。
コンストラクタで空白をセットしておいてあげると、空行とかを読み込んだときにエラーで落ちることを防いでくれます。
SampleCsvBeanクラス
package jp.koji.bean;
public class SampleCsvBean {
String key;
String name;
String pref;
String job;
public SampleCsvBean() {
this.key = "";
this.name = "";
this.pref = "";
this.job = "";
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPref() {
return pref;
}
public void setPref(String pref) {
this.pref = pref;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
}
次に、作成したJavaBeansクラスを読み書きする、Mainクラスを作成します。
MainCSVUtil
package jp.koji.bean;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.OutputStreamWriter;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.Writer;
import java.util.Iterator;
import java.util.List;
import com.opencsv.CSVReader;
import com.opencsv.CSVWriter;
import com.opencsv.bean.ColumnPositionMappingStrategy;
import com.opencsv.bean.CsvToBean;
public class MainCSVUtil {
public static void main(String[] arg) throws Exception {
writeSampleCSV("D:\\SampleOut.csv",readSampleCSV("D:\\SampleIn.csv"));
}
public static List readSampleCSV(String inputFilePath){
Reader ioreader = null;
List tmpNDCsvBean = null;
try {
ioreader = new InputStreamReader(new FileInputStream(inputFilePath),"UTF-8");
ColumnPositionMappingStrategy mappingStrategy = new ColumnPositionMappingStrategy();
mappingStrategy.setType(SampleCsvBean.class);
String[] columns = new String[]{"key", "name", "pref", "job"};
mappingStrategy.setColumnMapping(columns);
CsvToBean csv = new CsvToBean();
CSVReader reader = new CSVReader(ioreader, ',', '"');
tmpNDCsvBean = csv.parse(mappingStrategy, reader);
} catch (Exception e) {
e.printStackTrace();
}finally{
try{
ioreader.close();
}catch(Exception e){
e.printStackTrace();
}
}
return tmpNDCsvBean;
}
public static void writeSampleCSV (String outputFilePath, List listCSVBean){
Writer iowriter = null;
CSVWriter writer = null;
try {
iowriter = new OutputStreamWriter(new FileOutputStream(outputFilePath),"UTF-8");
writer = new CSVWriter(iowriter, ',', CSVWriter.NO_QUOTE_CHARACTER);
Iterator<samplecsvbean> ite = listCSVBean.iterator();
while(ite.hasNext()){
SampleCsvBean tt = ite.next();
String[] entries = new String[]{tt.getKey(),
tt.getName(),
tt.getPref(),
tt.getJob().replace(",", "、")
};
writer.writeNext(entries);
}
writer.close();
}catch (Exception e) {
e.printStackTrace();
}finally{
try{
iowriter.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
}
一旦読み込むと、定義したJavaBeans型のリストとなるので、その後の加工は自由自在です。加工した結果を、csvに吐き出すコードは、上記の「writeSampleCSV」です。
一つ作っておくと、いろいろなcsvを加工するのも楽ですよ。