ふと、書いてみたくなりまして。だいたいスクリプト系の言語で、よく忘れてしまうのが書いた動機です…。
記載パターンは、以下の2通り
- ファイルの中身を全て読み込んで、1つの文字列として変数contentsに格納
- ファイルの中身を全て読み込んで、改行無しの1行を要素としたリストの変数linesに格納
あと、前提は以下の通り
- 読み込むファイルの名前は「input.txt」で、中身のエンコーディングは「UTF-8」とする
- ファイルを開く時に、エンコーディングは「UTF-8」と明示的に指定する
- 実行効率は求めない
- ファイルの中身がメモリに乗り切らないなんて考えない
- 言語の標準ライブラリだけで実装する
要は、簡単なスクリプト的にファイルを読み込みたい時に使うことを想定してます。
最後に、読み込んだ内容を出力します。
では、いってみましょう。
Java
いっつも面倒だと思っていたのですが、JDK 7からだいぶ楽になりましたね。
まずは雛形コード。
import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.util.List; public class ReadFile { public static void main(String[] args) { try { // code here... } catch (IOException e) { e.printStackTrace(); } } }
コメント「// code here...」の部分を埋めていきます。
まずは、ファイルの中身を1つの文字列として取得する方から。
String contents = new String(Files.readAllBytes(Paths.get("input.txt")), StandardCharsets.UTF_8); // String contents = new String(Files.readAllBytes(Paths.get("input.txt")), "UTF-8"); // <= もしくは、こちら System.out.println(contents);
java.nio.file.Files#readAllBytesで一括で読んで、その後Stringに変換。よって、効率は良くないです…。
JDK 7から、java.nio.charset.StandardCharsetsってクラスが入ったんですね。
続いて、ファイルを行単位のList形式で読む方。
List<String> lines = Files.readAllLines(Paths.get("input.txt"), StandardCharsets.UTF_8); for (String line : lines) { System.out.println(line); }
java.nio.file.Files#readAllLinesで、Listで一気に読めます。
クローズ処理も不要で、随分簡単になったなぁ〜と。
Groovy
JDK 7とか関係なく、楽。
文字列として取得。
def contents = new File('input.txt').getText('UTF-8') println(contents)
Listとして取得。
def lines = new File('input.txt').readLines('UTF-8') lines.each { println(it) }
GDK、楽。
Scala
こちらは、ちょっと何パターンか遊んでみました。複数書いた都合上、文字列、Listでの取得を続けて書きます。
まずは、JDK 7が使える環境の場合。
import scala.collection.JavaConverters._ import java.nio.charset.StandardCharsets import java.nio.file.{Files, Paths} // 文字列として取得 val contents = new String(Files.readAllBytes(Paths.get("input.txt")), StandardCharsets.UTF_8) println(contents) // Listとして取得 val lines = Files.readAllLines(Paths.get("input.txt"), StandardCharsets.UTF_8).asScala.toList lines foreach println
続いて、Iterator#continuallyで遊んでみました。
// 文字列として取得 import java.io.{BufferedReader, FileInputStream, InputStreamReader} import java.nio.charset.StandardCharsets var fis: FileInputStream = null var isr: InputStreamReader = null var reader: BufferedReader = null try { fis = new FileInputStream("input.txt") isr = new InputStreamReader(fis, StandardCharsets.UTF_8) reader = new BufferedReader(isr) val text = Iterator.continually(reader.read()).takeWhile(_ != -1).map(_.asInstanceOf[Char]).mkString println(text) } finally { if (reader != null) { reader.close() } if (isr != null) { isr.close() } if (fis != null) { fis.close() } } // Listとして取得 import java.io.{BufferedReader, FileInputStream, InputStreamReader} import java.nio.charset.StandardCharsets var fis: FileInputStream = null var isr: InputStreamReader = null var reader: BufferedReader = null try { fis = new FileInputStream("input.txt") isr = new InputStreamReader(fis, StandardCharsets.UTF_8) reader = new BufferedReader(isr) val lines = Iterator.continually(reader.readLine()).takeWhile(_ != null).toList lines foreach println } finally { if (reader != null) { reader.close() } if (isr != null) { isr.close() } if (fis != null) { fis.close() } }
最後に、評判の悪い?scala.io.Sourceで。
// 文字列として取得 import scala.io.Source val source = Source.fromFile("input.txt", "UTF-8") try { val contents = source.mkString println(contents) } finally { source.close() } // Listとして取得 import scala.io.Source val source = Source.fromFile("input.txt", "UTF-8") try { val lines = source.getLines().toList lines foreach println } finally { source.close() }
普通に読むだけなら、まあいい?でも、書き込みはできないんですよねー。
Perl
実は、今回1番ちゃんとやっておきたかった言語。One Linerばっかり使ってるんで、普通にファイル読み込みしようと思うとコロっと忘れてることが多いんですよね…。
文字列として、一気に読む場合。
#!/usr/bin/perl use strict; use warnings; use Encode 'encode'; my $input_file = 'input.txt'; open my $file, '<:encoding(utf8)', $input_file or die qq{Can't open file: "$input_file"\n}; local $/ = undef; my $contents = <$file>; print encode('utf8', $contents); close $file;
ポイントは、
local $/ = undef;
らしいです。
リスト(配列)で読む場合。
#!/usr/bin/perl use strict; use warnings; use Encode 'encode'; my $input_file = 'input.txt'; open my $file, '<:encoding(utf8)', $input_file or die qq{Can't open file: "$input_file"\n}; my @lines = split /\r?\n/, do { local $/ = undef; <$file> }; foreach my $line (@lines) { print encode('utf8', $line), "\n"; } close $file;
Perlって、きちんとエンコーディング指定して文字列作っちゃうと、printで出力する時にencode関数がいるんですねー。
ホント、この辺りは常識感がないです…。
なんとなく、普通は改行込みで
my @lines = <$fh>;
とか
while (<$fh>) { # ... }
とかすることの方が多いと思いますが…。
Python
文字列で、一気に取得する場合。
#!/usr/bin/python # -*- coding: utf-8 -*- import codecs f = codecs.open("input.txt", "r", "utf-8") try: contents = f.read() print contents finally: f.close()
リストで読む場合。
#!/usr/bin/python # coding: utf-8 import codecs f = codecs.open("input.txt", "r", "utf-8") try: lines = [line.rstrip("\r\n") for line in f] for line in lines: print line finally: f.close()
Pythonの場合、readlineとかで改行が除去されないので、自分で取ってます。