Java Gold 17のファイルI/O対策|Path・Filesと例題

ファイルI/Oの問題は、扱う値がバイト・文字・パスのどれかを見極めるところから始めます。実ファイルを操作する処理と、パスを組み立てるだけの処理も分けて確認しましょう。

バイトと文字、戻り値と終端を区別する

種類扱う対象確認する点
InputStream / OutputStreamバイト列文字として解釈するなら文字コードが必要
Reader / Writer文字単一文字を読むreadの戻り値はintで、終端は-1
BufferedReaderバッファを用いた文字入力readLineは行末の改行文字を含まず、読み込む文字がなく終端ならnull

Reader.read()がintを返すのは、文字の値と終端の-1を表すためです。最初からcharへ変換すると終端の判定を取り違えやすくなります。readLine()とは戻り値も終端の表し方も異なります。Reader.readの仕様とBufferedReader.readLineの仕様で確認してください。

テキストを読むときは、データを保存した文字コードを確認します。Java 17の環境依存のデフォルトを前提にせず、問題文でUTF-8などが指定されているかを確認しましょう。Files.newBufferedReaderのようにAPIごとに決められたデフォルトを持つ場合もあるため、呼び出しているオーバーロードまで読む必要があります。

Pathは場所の表現、Filesはファイル操作

Path.ofでパスを作っただけでは、その場所にファイルが作成されるわけではありません。normalize()はパス要素を整理し、ファイルシステムへアクセスしません。一方、toRealPath()は既存ファイルの実際のパスを求める操作です。存在確認やアクセス権に関わる例外を考える必要があります。

resolveでパスをつなぐ問題では、渡したパスが相対パスか絶対パスかを先に確認します。relativizeでは、相対パス同士か絶対パス同士かなど、関係を計算できる組み合わせかを確認します。OSやファイルシステムに依存する前提も読み落とさないようにします。規則はPathの公式APIで確認できます。

ファイルを開くAPIでは、リソース解放も確認します。たとえばFiles.linesが返すStreamは、必要な処理の後で閉じます。try-with-resourcesは、正常終了だけでなく例外が発生した場合の解放を考えるためにも役立ちます。

例題2問:Readerの取得とreadの戻り値

コンストラクタが受け取れる引数の型と、実行時に返る値を別々に確認してください。

例題1:BufferedReaderの取得

Path pathのテキストを行単位で読むBufferedReaderを取得できる式を2つ選んでください。

2つ選択してください

  • A. new BufferedReader(path)
  • B. new FileReader(path.toFile(), true)
  • C. Files.newBufferedReader(path, StandardCharsets.UTF_8)
  • D. new BufferedReader(new FileReader(path.toFile(), StandardCharsets.UTF_8))
例題1の正解・解説を見る

正解:C・D

行単位で読むreadLineはBufferedReaderにあり、Filesから取得する方法とReaderを包む方法があります。

行単位で読むreadLineはBufferedReaderにあり、Filesから取得する方法とReaderを包む方法があります。

  • A:BufferedReaderはPathではなくReaderを受け取ります。
  • B:FileReaderに追記モードのboolean引数はありません。
  • C:指定エンコーディングのBufferedReaderを取得できます。
  • D:ReaderをBufferedReaderで包めます。

確認するポイント:読み込み側に書き込みのappendフラグを持ち込まないでください。

仕様を確認するための公式資料:

問題ID:jg17-0185e60a9d543e · この問題の訂正を連絡する

例題2:readの戻り値と終端

次の処理が最後に表示する内容を選んでください。必要なimportは記述済みです。

try (var r = new StringReader("Q")) {
    int ch = r.read();
    System.out.print(ch + ":" + (char)ch + ":" + r.read());
}

1つ選択してください

  • A. 81:Q:0
  • B. 81:Q:-1
  • C. Q:Q:0
  • D. Q:Q:-1
例題2の正解・解説を見る

正解:B

正解は「81:Q:-1」です。

readは文字コードをintで返し、終端を-1で表します。文字として表示する場合は終端を確認してcharに変換します。

  • A:この結果にはなりません。readは文字コードをintで返し、終端を-1で表します。文字として表示する場合は終端を確認してcharに変換します。
  • B:readは文字コードをintで返し、終端を-1で表します。文字として表示する場合は終端を確認してcharに変換します。
  • C:この結果にはなりません。readは文字コードをintで返し、終端を-1で表します。文字として表示する場合は終端を確認してcharに変換します。
  • D:この結果にはなりません。readは文字コードをintで返し、終端を-1で表します。文字として表示する場合は終端を確認してcharに変換します。

確認するポイント:intをそのままprintすると文字でなく数値が表示されます。

仕様を確認するための公式資料:

問題ID:jg17-28a0b76f97ff72 · この問題の訂正を連絡する

ファイルI/Oの53問で復習する

問題演習の「出題分野」で「ファイルIO」を選びます。バイト・文字入出力、Path・Files、シリアライズなどを扱います。53問は本サイトの収録数で、公式試験の出題比率ではありません。

実行結果を問う問題は「ファイルの初期内容」「文字コード」「追記か上書きか」「存在するパス」を先にメモします。前提を固定してから出力や例外を追うと、復習時に誤答の原因を説明できます。

関連する学習

本サイトの問題は、Java SE 17を学ぶためのオリジナル練習教材です。本試験の過去問やOracle公式の教材ではありません。編集・訂正の方針をご確認ください。