1. 概要

Javaでは、PathおよびFileはファイルI/O操作を担当するクラスです。 それらは同じ機能を実行しますが、異なるパッケージに属しています。

このチュートリアルでは、これら2つのクラスの違いについて説明します。 簡単なクラスの要約から始めましょう。 次に、いくつかのレガシーの欠点について説明します。 最後に、両方のAPI間で機能を移行する方法を学習します。

2.  java.io.Fileクラス

最初のバージョン以来、Javaは独自の java.io パッケージを提供してきました。このパッケージには、入出力操作を実行するために必要になる可能性のあるほぼすべてのクラスが含まれています。 ファイルクラスファイルとディレクトリのパス名の抽象表現です。

File file = new File("baeldung/tutorial.txt");

ファイルクラスのインスタンスは不変です。一度作成されると、このオブジェクトによって表される抽象パス名は変更されません。

3. java.nio.file.Pathクラス

Pathクラスは、バージョン7でJavaに導入されたNIO2アップデートの一部を形成します。 I /Oと連携するまったく新しいAPIを提供します。 さらに、従来の File クラスと同様に、Pathファイルシステム内のファイルを見つけるために使用できるオブジェクトを作成します。

同様に、Fileクラスで実行できるすべての操作を実行できます。

Path path = Paths.get("baeldung/tutorial.txt");

File APIのようにコンストラクターを使用する代わりに、静的 java.nio.file.Paths.get()を使用してPathインスタンスを作成します。方法。

4. ファイルクラスの欠点

2つのクラスのこの短い要約の後、両方のAPIについて説明し、質問に答えましょう。同じ機能を提供する場合、 Oracleが新しいAPIを導入することを決定した理由と、どちらを使用する必要がありますか?

ご存知のとおり、 java .ioパッケージはJavaJDKの最初のリリースで提供され、I/Oアクションを実行できるようになりました。 それ以来、多くの開発者が多くの欠点、機能の欠如、およびその機能の一部に関する問題を報告しています。

4.1. エラー処理

最も一般的な問題は、不十分なエラー処理です。 多くのメソッドは、発生した問題の詳細を教えてくれないか、例外をスローすることさえありません。

ファイルを削除する簡単なプログラムがあるとしましょう。

File file = new File("baeldung/tutorial.txt");
boolean result = file.delete();

このコードはコンパイルされ、エラーなしで正常に実行されます。 もちろん、false値を含むresultフラグがありますが、この失敗の理由はわかりません。 ファイルが存在しないか、プログラムにファイルを削除する権限がない可能性があります。

これで、新しいNIO2APIを使用して同じ機能を書き直すことができます。

Path path = Paths.get("baeldung/tutorial.txt");
Files.delete(path);

ここで、コンパイラーはIOExceptionを処理する必要があります。 さらに、スローされた例外には、その失敗に関する詳細が含まれており、たとえば、ファイルが存在しないかどうかがわかります。

4.2. メタデータのサポート

java.ioパッケージのFileクラスはメタデータのサポートが不十分であるため、ファイルに関するメタ情報を必要とするI/O操作でさまざまなプラットフォーム間で問題が発生します。

メタデータには、アクセス許可、ファイル所有者、およびセキュリティ属性も含まれる場合があります。 このため、ファイルクラスはシンボリックリンクをまったくサポートしておらず、 rename()メソッドは異なるプラットフォーム間で一貫して機能しません

4.3. メソッドのスケーリングとパフォーマンス

File クラスのメソッドはスケーリングされないため、パフォーマンスの問題もあります。 多数のファイルがある一部のディレクトリで問題が発生します。 ディレクトリの内容を一覧表示すると、ハングが発生し、メモリリソースの問題が発生する可能性があります。 最後に、サービス拒否につながる可能性があります。

これらの欠点のいくつかのために、Oracleは改良されたNIO2APIを開発しました。 開発者は、可能であれば、レガシークラスの代わりにこの新しいjava.nioパッケージを使用して新しいプロジェクトを開始する必要があります。

5. マッピング機能

java.io パッケージのいくつかのギャップを修正するために、Oracleは独自の欠点の要約を用意し、開発者がAPI間で移行できるようにしました。

NIO2 パッケージは、前述の欠点の改善を含む、すべてのレガシー機能を提供します。 このレガシーAPIを引き続き使用する可能性のあるアプリケーションが多数あるため、Oracleは現在、将来のリリースで古いAPIを廃止または削除する予定はありません。

新しいAPIでは、インスタンスメソッドの代わりにjava.nio.file.Filesクラスの静的メソッドを使用します。 これらのAPIを簡単に比較してみましょう。

5.1. ファイルおよびパスインスタンス

もちろん、主な違いはパッケージとクラス名です。

java.io.File file = new java.io.File("baeldung/tutorial.txt");
java.nio.file.Path path = java.nio.file.Paths.get("baeldung/tutorial.txt");

ここでは、コンストラクターを介して File オブジェクトを作成し、静的メソッドを使用してPathを取得します。 複数の引数を使用して複雑なパスを解決することもできます。

File file = new File("baeldung", "tutorial.txt");
Path path = Paths.get("baeldung", "tutorial.txt");

また、 resolve()メソッドをチェーンすることで同じ結果を得ることができます。

Path path2 = Paths.get("baeldung").resolve("tutorial.txt");

さらに、 toPath()メソッドと toFile()メソッドを使用して、API間でオブジェクトを変換できます。

Path pathFromFile = file.toPath();
File fileFromPath = path.toFile();

5.2. ファイルとディレクトリの管理

どちらのAPIも、ファイルとディレクトリを管理するためのメソッドを提供します。 以前に作成したインスタンスオブジェクトを使用してこれを示します。

ファイルを作成するには、 createNewFile()および Files.createFile()メソッドを使用できます。

boolean result = file.createNewFile();
Path newPath = Files.createFile(path);

ディレクトリを作成するには、 mkdir()または Files.createDirectory()を使用する必要があります。

boolean result = file.mkdir();
File newPath = Files.createDirectory(path);

mkdirs()および Files.createDirectories()メソッドを介して、存在しないすべてのサブディレクトリを含めるために、これらのメソッドの追加のバリアントがあります。

boolean result = file.mkdirs();
File newPath = Files.createDirectories(path);

でファイルの名前を変更または移動する場合は、別のインスタンスオブジェクトを作成し、 renameTo()または Files.move()を使用する必要があります。

boolean result = file.renameTo(new File("baeldung/tutorial2.txt"));
Path newPath = Files.move(path, Paths.get("baeldung/tutorial2.txt"));

削除操作を実行するには、 delete()または Files.delete()を使用します。

boolean result = file.delete();
Files.delete(Paths.get(path));

エラーが発生した場合、レガシーメソッドは結果がfalseに設定されたフラグを返すことに注意してください。 NIO2メソッドは、エラーが発生したときに IOException をスローする削除操作を除いて、新しいPathインスタンスを返します。

5.3. メタデータの読み取り

また、権限やタイプなど、ファイルに関するいくつかの基本情報を取得することもできます。 前と同じように、インスタンスオブジェクトが必要です。

// java.io API
boolean fileExists = file.exists();
boolean fileIsFile = file.isFile();
boolean fileIsDir = file.isDirectory();
boolean fileReadable = file.canRead();
boolean fileWritable = file.canWrite();
boolean fileExecutable = file.canExecute();
boolean fileHidden = file.isHidden();

// java.nio API
boolean pathExists = Files.exists(path);
boolean pathIsFile = Files.isRegularFile(path);
boolean pathIsDir = Files.isDirectory(path);
boolean pathReadable = Files.isReadable(path);
boolean pathWritable = Files.isWritable(path);
boolean pathExecutable = Files.isExecutable(path);
boolean pathHidden = Files.isHidden(path);

5.4. パス名メソッド

最後に、ファイルシステムパスを取得するためのFileクラスのメソッドを簡単に見てみましょう。 前の例とは異なり、それらのほとんどはオブジェクトインスタンスで直接実行されることに注意してください。

絶対パスまたは正規パスを取得するには、次を使用できます。

// java.io API
String absolutePathStr = file.getAbsolutePath();
String canonicalPathStr = file.getCanonicalPath();

// java.nio API
Path absolutePath = path.toAbsolutePath();
Path canonicalPath = path.toRealPath().normalize();

Path オブジェクトは不変ですが、新しいインスタンスを返します。 さらに、NIO2 APIには、冗長性を削除するために使用できる toRealPath()および normalize()メソッドがあります。

URI への変換は、 toUri()メソッドを使用して実行できます。

URI fileUri = file.toURI();
URI pathUri = path.toUri();

また、ディレクトリコンテンツを一覧表示することもできます。

// java.io API
String[] list = file.list();
File[] files = file.listFiles();

// java.nio API
DirectoryStream<Path> paths = Files.newDirectoryStream(path);

NIO2 APIは、Iterableインターフェイスを実装する独自のDirectoryStreamオブジェクトを返します。

6. 結論

Java 7以降、開発者は2つのAPIから選択してファイルを操作できるようになりました。 この記事では、java.io.Fileクラスに関連するいくつかのさまざまな欠点と問題について説明しました。

それらを修正するために、オラクルは NIOパッケージを提供することを決定しました。これにより、同じ機能が大幅に改善されます

次に、両方のAPIを確認しました。 例を通して、それらの間で移行する方法を学びました。 また、 java.io.Fileはレガシーと見なされ、新しいプロジェクトには推奨されないこともわかりました。 ただし、廃止して削除する予定はありません。

いつものように、この記事のすべてのコードスニペットは、GitHubから入手できます。