ファイルを行単位で読む
1 行ずつ読むだけなのに、while と null 判定が要る
ログを 1 行ずつ確かめたい、設定ファイルを上から順に処理したい。やりたいことは「行の並びが欲しい」だけなのに、昔ながらの書き方だと BufferedReader を用意して、readLine() の戻り値を変数に代入しながら null と比べる while を回し、読み終えたら閉じる、という手続きが要りました。本題に入る前の準備がやたらと長いのです。
Files.readAllLines は、その全部を 1 行にまとめてくれます。渡した Path のファイルを開いて最後まで読み、閉じたうえで List<String> を返します。
Java
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
public class Demo {
public static void main(String[] args) throws Exception {
List<String> lines = Files.readAllLines(Path.of("access.log"));
System.out.println(lines.size());
for (String line : lines) {
System.out.println(line);
}
}
}各要素に入るのは行の中身だけで、末尾の \n や \r\n は取り除かれています。返ってくるのは見慣れた List なので、size() で行数を数えるのも、for で回すのも、stream() につなぐのも思いのままです。ファイルは戻ってきた時点ですでに閉じられているので、自分で閉じる必要はありません。
末尾の改行は 1 行として数えない
行数を数えると、多くの人が「1 行多いはず」「1 行足りない」で止まります。数え方には決まりがあり、最後の改行のうしろは行として数えません。
"a\nb\nc"は["a", "b", "c"]で3行"a\nb\n"は["a", "b"]で2行"hello"は["hello"]で1行"\n"は[""]で1行
"a\nb\n" が 2 行なのは、改行を「行の終わりを示す印」として読んでいるからです。最後の \n は 2 行目を閉じただけで、そのうしろに 3 行目が始まっているわけではありません。テキストファイルの末尾に改行を置く習慣は Unix から続くもので、多くのツールがこの数え方で一致しています。
空のファイルの場合、返るのは null ではなく要素 0 個の List です。if (lines == null) のような身構えは要らず、lines.isEmpty() で判定します。
Java
List<String> empty = Files.readAllLines(Path.of("empty.txt"));
System.out.println(empty.size()); // 0
System.out.println(empty.isEmpty()); // true文字化けしたときは、まずファイル側の文字コードを疑ってください。引数 1 つの
readAllLinesは UTF-8 として読むので、Shift_JIS で保存されたファイルを渡すと化けるか、MalformedInputExceptionで落ちます。第 2 引数にCharsetを渡せば読み分けられます。
やってみよう
Solution.countLines(String content) を完成させます。
- 一時ファイルを作り、受け取った
contentを書き込む - そのファイルを
Files.readAllLinesで読み返す - 返ってきた
List<String>の行数をintとしてreturnする - 後始末として一時ファイルを削除する
一時ファイルの作り方と書き込みは前回のとおりです。countLines("a\nb\n") は 3 ではなく 2、countLines("") は 0 を返します。上の数え方の表と突き合わせながら確かめてください。
要件
java.nio.file.Files.createTempFileで一時ファイルを作成し、そのPathを使うことFiles.writeString(path, content)で引数の文字列を書き込み、Files.readAllLines(path)で読み返すこと- 読み返した
List<String>のsize()をintとしてreturnすること (Files.lines(p).count()を使う場合は(int)でキャストする)
入出力例
countLines("a
b
c") → 3
countLines("") → 0
countLines("hello") → 1
countLines("a
b
") → 2
countLines("
") → 1