0
0

csvを読む

Posted at

簡単にcsvを読むというだけのことをします。

使用するライブラリ

簡単になので、既存のライブラリを使用します。今回試してみたのは以下の2つです。

使用するデータ

あまりオススメされてないようですが、有名な郵便番号のCSVを使用します。

ビルド用の設定

今回はmavenで用意しました。JREは17想定です。8でもちょっと修正すれば動くかも。

pox.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example-hoge</groupId>
  <artifactId>csv-reader-test</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>csv-reader-test</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>com.opencsv</groupId>
      <artifactId>opencsv</artifactId>
      <version>5.9</version>
    </dependency>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-csv</artifactId>
      <version>1.11.0</version>
    </dependency>

  </dependencies>
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
          <archive>
            <manifest>
              <addClasspath>true</addClasspath>
              <classpathPrefix>lib/</classpathPrefix>
              <mainClass>example_hoge.csv_reader_test.App</mainClass>
            </manifest>
          </archive>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-jar-plugin</artifactId>
        <version>3.4.2</version>
        <configuration>
          <archive>
            <manifest>
              <addClasspath>true</addClasspath>
              <classpathPrefix>lib/</classpathPrefix>
              <mainClass>example_hoge.csv_reader_test.App</mainClass>
            </manifest>
          </archive>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

コード

src/main/java/example_hoge/csv_reader_test/App.java
package example_hoge.csv_reader_test;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVRecord;

import com.opencsv.bean.CsvBindByPosition;
import com.opencsv.bean.CsvToBeanBuilder;

public class App {
	public static class PostalCode {
		// 全国地方公共団体コード
		@CsvBindByPosition(position = 0)
		private String nationalLocalGovernmentCode;
		// (旧)郵便番号
		@CsvBindByPosition(position = 1)
		private String oldPostalCode;
		// 郵便番号
		@CsvBindByPosition(position = 2)
		private String postalCode;
		// 都道府県名(全角カタカナ)
		@CsvBindByPosition(position = 3)
		private String prefectureNameKana;
		// 市区町村名(全角カタカナ)
		@CsvBindByPosition(position = 4)
		private String cityNameKana;
		// 町域名(全角カタカナ)
		@CsvBindByPosition(position = 5)
		private String townAreaNameKana;
		// 都道府県名
		@CsvBindByPosition(position = 6)
		private String prefectureName;
		// 市区町村名
		@CsvBindByPosition(position = 7)
		private String cityName;
		// 町域名
		@CsvBindByPosition(position = 8)
		private String townAreaName;
		// 一町域が二以上の郵便番号で表される場合の表示
		@CsvBindByPosition(position = 9)
		private boolean multiPostalCodesInTownArea;
		// 小字毎に番地が起番されている町域の表示
		@CsvBindByPosition(position = 10)
		private boolean numberedForEachKoaza;
		// 丁目を有する町域の場合の表示
		@CsvBindByPosition(position = 11)
		private boolean townAreaWithChome;
		// 一つの郵便番号で二以上の町域を表す場合の表示
		@CsvBindByPosition(position = 12)
		private boolean multiTownAreasWithPostalCode;
		// 更新の表示
		@CsvBindByPosition(position = 13)
		private boolean updated;
		// 変更理由
		@CsvBindByPosition(position = 14)
		private int reasonForUpdate;
	}

	public static enum Headers {
		// 全国地方公共団体コード
		NationalLocalGovernmentCode,
		// (旧)郵便番号
		OldPostalCode,
		// 郵便番号
		PostalCode,
		// 都道府県名(全角カタカナ)
		PrefectureNameKana,
		// 市区町村名(全角カタカナ)
		CityNameKana,
		// 町域名(全角カタカナ)
		TownAreaNameKana,
		// 都道府県名
		PrefectureName,
		// 市区町村名
		CityName,
		// 町域名
		TownAreaName,
		// 一町域が二以上の郵便番号で表される場合の表示
		MultiPostalCodesInTownArea,
		// 小字毎に番地が起番されている町域の表示
		NumberedForEachKoaza,
		// 丁目を有する町域の場合の表示
		TownAreaWithChome,
		// 一つの郵便番号で二以上の町域を表す場合の表示
		MultiTownAreasWithPostalCode,
		// 更新の表示
		Updated,
		// 変更理由
		ReasonForUpdate
	}

	private static void test_commonscsv(Reader in, Writer out) {
		try {
			Iterable<CSVRecord> records = CSVFormat.RFC4180.builder().setHeader(Headers.class).build().parse(in);
			for (CSVRecord record : records) {
				out.write(record.get(Headers.PostalCode));
				out.write(":");
				out.write(record.get(Headers.PrefectureName));
				out.write(" ");
				out.write(record.get(Headers.CityName));
				out.write(" ");
				out.write(record.get(Headers.TownAreaName));
				out.write("\n");
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private static void test_opencsv(Reader in, Writer out) {
		try {
			var parser = new CsvToBeanBuilder<PostalCode>(in).withType(PostalCode.class).build();
			var postalCodes = parser.parse();
			for (var postalcode: postalCodes) {
				out.write(postalcode.postalCode);
				out.write(':');
				out.write(postalcode.prefectureName);
				out.write(' ');
				out.write(postalcode.cityName);
				out.write(' ');
				out.write(postalcode.townAreaName);
				out.write('\n');
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		Reader in = new InputStreamReader(System.in); // wont close for standard input
		Writer out = new OutputStreamWriter(System.out); // wont close for standard output
		boolean use_commonscsv = true;
		if (args.length > 0) {
			use_commonscsv = ! "opencsv".equals(args[0]);
		}
		if (use_commonscsv) {
			test_commonscsv(in, out);
		} else {
			test_opencsv(in, out);
		}
		try {
			out.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

動かし方

$ mvn package # ビルド
$ java -jar target/csv-reader-test-0.0.1-SNAPSHOT-jar-with-dependencies.jar <utf_ken_all.csv
...
9071544:沖縄県 八重山郡竹富町 鳩間
9071800:沖縄県 八重山郡与那国町 以下に掲載がない場合
9071801:沖縄県 八重山郡与那国町 与那国
$ 

普通に動かすとcommons csvを使います。opencsvを使う場合は引数にopencsvを入れて下さい。

$ java -jar target/csv-reader-test-0.0.1-SNAPSHOT-jar-with-dependencies.jar opencsv <utf_ken_all.csv
...
9071544:沖縄県 八重山郡竹富町 鳩間
9071800:沖縄県 八重山郡与那国町 以下に掲載がない場合
9071801:沖縄県 八重山郡与那国町 与那国
$ 

補足

opencsvではbeansを使用する方式にしてるので、割と遅いかもしれません。とはいえ、18MBのテキストを読むのに起動処理込み3.2秒かかっていました。

ヘッダの設定はどちらも本来不要ですが、やはり読みやすさが違うので、今回は定義しています。

まとめ

beanを使った読み込みに興味があり、少し動かしてみただけです。ちゃんと調べてないので結論はなし。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0