JavaRush /Java Blog /Random-JA /Java ファイル、パス

Java ファイル、パス

Random-JA グループに公開済み
こんにちは!今日はファイルとディレクトリの操作について説明します。ファイルの内容を管理する方法はすでにご存知でしょう。これに特化したクラスがたくさんありました :) これらの目的に必要ないくつかのクラスは簡単に覚えられると思います。今日の講義では、ファイルの作成、名前変更などのファイル管理について具体的に説明します。Java 7 より前では、このような操作はすべてFile. 彼の作品についてはここで読むことができます。しかし、Java 7 では、この言語の作成者はファイルとディレクトリの操作方法を変更することにしました。Fileこれは、このクラスには多くの欠点があるという事実によるものでした。たとえば、copy()ある場所から別の場所にファイルをコピーできるメソッド (明らかに必要と思われる機能) がありませんでした。さらに、このクラスには、値Fileを返すメソッドが多数ありましたboolean。エラーが発生した場合、このようなメソッドは例外をスローするのではなくfalseを返すため、エラーの診断と原因の特定が非常に困難になります。単一のクラスではなく、 、、のFile3 つのクラスが出現しました。正確に言えば、これはクラスではなくインターフェイスです。それぞれがどのように異なるのか、そしてそれぞれがなぜ必要なのかを見てみましょう。最も簡単なことから始めましょう - 。 PathsPathFilesPathPaths

パス

Pathsは、単一の静的メソッドを備えた非常に単純なクラスですget()。これは、渡された string または URI から type のオブジェクトを取得するためだけに作成されましたPath。他の機能はありません。彼の作品の一例を次に示します。
import java.nio.file.Path;
import java.nio.file.Paths;

public class Main {

   public static void main(String[] args) {

       Path testFilePath = Paths.get("C:\\Users\\Username\\Desktop\\testFile.txt");
   }
}
一番難しいクラスではないですよね?:) さて、タイプのオブジェクトを取得したのでPath、それが何であるか、そしてなぜそれが必要であるかを理解しましょうPath:)

パス

Pathは概して、 の再設計された類似物ですFile。を使用するよりもはるかに簡単に作業できますFileまず、多くのユーティリティ (静的) メソッドがそこから削除され、クラスに移動されましたFiles次にPathメソッドの戻り値が順序付けされました。クラスでは、Fileメソッドは this String、 that boolean、 thatを返しましたがFile、それを理解するのは簡単ではありませんでした。たとえば、getParent()現在のファイルの親パスを文字列として返すメソッドがありました。しかし同時に、getParentFile()同じものをオブジェクトの形式で返すメソッドもありましたFile。これは明らかに冗長です。したがって、インターフェイスでは、ファイルを操作するためのPathメソッドgetParent()やその他のメソッドは単にオブジェクトを返しますPath。たくさんのオプションはありません - すべてが簡単でシンプルです。 どのような便利なメソッドがあるのでしょうかPath? 以下にその一部とその仕事の例を示します。
  • getFileName()— パスからファイル名を返します。

  • getParent()- 現在のパスに関連する「親」ディレクトリ (つまり、ディレクトリ ツリーの上位のディレクトリ) を返します。

  • getRoot()— 「ルート」ディレクトリを返します。つまり、ディレクトリツリーの最上位にあるものです。

  • startsWith(), endsWith()— パスが渡されたパスで始まる/終わるかどうかを確認します。

    import java.nio.file.Path;
    import java.nio.file.Paths;
    
    public class Main {
    
       public static void main(String[] args) {
    
           Path testFilePath = Paths.get("C:\\Users\\Username\\Desktop\\testFile.txt");
    
           Path fileName = testFilePath.getFileName();
           System.out.println(fileName);
    
           Path parent = testFilePath.getParent();
           System.out.println(parent);
    
           Path root = testFilePath.getRoot();
           System.out.println(root);
    
           boolean endWithTxt = testFilePath.endsWith("Desktop\\testFile.txt");
           System.out.println(endWithTxt);
    
           boolean startsWithLalala = testFilePath.startsWith("lalalala");
           System.out.println(startsWithLalala);
       }
    }

    コンソール出力:

    testFile.txt
    C:\Users\ユーザー名\Desktop
    C:\
    true
    false

    このメソッドがどのように機能するかに注目してくださいendsWith()。現在のパスが渡されたパスで終わるかどうかを確認します。これはパス上にあり、文字セット上にはありません

    これら 2 つの呼び出しの結果を比較してください。

    import java.nio.file.Path;
    import java.nio.file.Paths;
    
    public class Main {
    
       public static void main(String[] args) {
    
           Path testFilePath = Paths.get("C:\\Users\\Username\\Desktop\\testFile.txt");
    
           System.out.println(testFilePath.endsWith("estFile.txt"));
           System.out.println(testFilePath.endsWith("Desktop\\testFile.txt"));
       }
    }

    コンソール出力:

    真偽
    _

    単なる文字のセットではなく、メソッドへの完全なパスを渡す必要があります。 そうしないと、現在のパスが実際にはそのような文字のシーケンスで終わっている場合でも (「estFile.txt」の場合のように)、結果は常にfalseendsWith()になります。」(上の例では)。

    さらに、絶対 (完全) パスと相対パスの操作を簡素化する一連のメソッドがありますPath

これらの方法を見てみましょう。
  • boolean isAbsolute()—現在のパスが絶対パスの場合はtrueを返します。

    import java.nio.file.Path;
    import java.nio.file.Paths;
    
    public class Main {
    
       public static void main(String[] args) {
    
           Path testFilePath = Paths.get("C:\\Users\\Username\\Desktop\\testFile.txt");
    
           System.out.println(testFilePath.isAbsolute());
       }
    }

    コンソール出力:

    真実

  • Path normalize()— 現在のパスを「正規化」し、不必要な要素を削除します。一般的なオペレーティング システムでは、パスを示すときに「.」文字がよく使用されることをご存知かもしれません。(「現在のディレクトリ」) および「..」(親ディレクトリ)。例: 「./Pictures/dog.jpg」は、現在いるディレクトリに Pictures フォルダーがあり、その中にファイル「dog.jpg」があることを意味します。

    それで、ここにあります。プログラムに「.」を使用したパスがある場合。または「..」の場合、メソッドはnormalize()それらを削除し、それらを含まないパスを取得します。

    import java.nio.file.Path;
    import java.nio.file.Paths;
    
    public class Main {
    
       public static void main(String[] args) {
    
    
           Path path5 = Paths.get("C:\\Users\\Java\\.\\examples");
    
           System.out.println(path5.normalize());
    
           Path path6 = Paths.get("C:\\Users\\Java\\..\\examples");
           System.out.println(path6.normalize());
       }
    }

    コンソール出力:

    C:\Users\Java\examples
    C:\Users\examples

  • Path relativize()— 現在のパスと渡されたパスの間の相対パスを計算します。

    例えば:

    import java.nio.file.Path;
    import java.nio.file.Paths;
    
    public class Main {
    
       public static void main(String[] args) {
    
           Path testFilePath1 = Paths.get("C:\\Users\\Users\\Users\\Users");
           Path testFilePath2 = Paths.get("C:\\Users\\Users\\Users\\Users\\Username\\Desktop\\testFile.txt");
    
           System.out.println(testFilePath1.relativize(testFilePath2));
       }
    }

    コンソール出力:

    ユーザー名\デスクトップ\testFile.txt

メソッドの完全なリストはPath非常に膨大です。これらはすべてOracle のドキュメントに記載されています。レビューに進みますFiles

ファイル

Files- これは、クラスの静的メソッドが移動されたユーティリティ クラスですFile。- これはまたは とFilesほぼ同じですが、ファイルのみで動作し、配列やコレクションでは動作しません:) ファイルとディレクトリの管理に重点を置いています。静的メソッドを使用すると、ファイルやディレクトリを作成、削除、移動できます。これらの操作には、メソッド(ディレクトリの場合 - )およびが使用されます。使用方法は次のとおりです。 ArraysCollectionsFilescreateFile()createDirectory()move()delete()
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;

public class Main {

   public static void main(String[] args) throws IOException {

       //file creation
       Path testFile1 = Files.createFile(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt"));
       System.out.println("Was the file created successfully?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt")));

       // create directory
       Path testDirectory = Files.createDirectory(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory"));
       System.out.println("Was the directory successfully created?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory")));

       //move file from desktop to testDirectory. You need to move with the name of the file in the folder!
       testFile1 = Files.move(testFile1, Paths.get("C:\\Users\\Username\\Desktop\\testDirectory\\testFile111.txt"), REPLACE_EXISTING);

       System.out.println("Is our file left on the desktop?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt")));

       System.out.println("Has our file been moved to testDirectory?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory\\testFile111.txt")));

       //remove file
       Files.delete(testFile1);
       System.out.println("Does the file still exist?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory\\testFile111.txt")));
   }
}
Files.createFile()ここでは、まずデスクトップに ファイルを作成し (メソッド)、​​次にそこにフォルダーを作成します (メソッドFiles.createDirectory())。その後、ファイル (メソッドFiles.move()) をデスクトップからこの新しいフォルダーに移動し、最後にファイルを削除します (メソッドFiles.delete())。 コンソール出力: ファイルは正常に作成されましたか? true ディレクトリは正常に作成されましたか? true ファイルはまだデスクトップ上にありますか? false ファイルは testDirectory に移動されましたか? true ファイルはまだ存在しますか? 間違い 注意してください:インターフェイス メソッドと同様にPath多くのメソッドはFilesオブジェクトを返しますPath。ほとんどのクラス メソッドはFilesも受け入れますPath。ここではメソッドがあなたの忠実なアシスタントになりますPaths.get()- 積極的に使用してください。他に何が面白いですかFiles?古いクラスに実際に欠けていたのは、!Fileメソッドでした。copy()講義の冒頭で彼のことについて話しましたが、今度は彼にお会いするときです!
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;

public class Main {

   public static void main(String[] args) throws IOException {

       //file creation
       Path testFile1 = Files.createFile(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt"));
       System.out.println("Was the file created successfully?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt")));

       // create directory
       Path testDirectory2 = Files.createDirectory(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2"));
       System.out.println("Was the directory successfully created?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2")));

       //copy the file from the desktop to the directory testDirectory2.
       testFile1 = Files.copy(testFile1, Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2\\testFile111.txt"), REPLACE_EXISTING);

       System.out.println("Is our file left on the desktop?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt")));

       System.out.println("Has our file been copied to testDirectory?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2\\testFile111.txt")));
   }
}
コンソール出力: ファイルは正常に作成されましたか? true ディレクトリは正常に作成されましたか? true ファイルはまだデスクトップ上にありますか? true ファイルは testDirectory にコピーされましたか? true プログラムでファイルをコピーできるようになりました。:) しかし、このクラスを使用すると、Filesファイル自体を管理するだけでなく、その内容を操作することもできます。データをファイルに書き込むには 、write()読み取りには 3 つのメソッドがありますread()。 後者については詳しく説明しますreadAllBytes()readAllLines()なぜその上にあるのでしょうか?それは非常に興味深い戻り値の型を持っているからです - List<String>! つまり、ファイル内の行のリストが返されます。もちろん、ファイル全体を 1 行ずつ通常のループでコンソールに出力できるため、コンテンツの操作が非常に便利になりますfor
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;

import static java.nio.charset.StandardCharsets.UTF_8;

public class Main {

   public static void main(String[] args) throws IOException {

       List<String> lines = Files.readAllLines(Paths.get("C:\\Users\\Username\\Desktop\\pushkin.txt"), UTF_8);

       for (String s: lines) {
           System.out.println(s);
       }
   }
}
コンソール出力: 素晴らしい瞬間を覚えています: あなたは私の前に現れました、つかの間のビジョンのように、純粋な美しさの天才のように。 とっても快適!:) この機能は Java 7 で登場しました。Java 8 では、関数型プログラミングのいくつかの要素を Java に追加したStream APIが登場しました。ファイルを操作するためのより豊富な機能が含まれています。ファイル内の「How」という単語で始まるすべての行を検索し、それらを大文字に変換してコンソールに出力するというタスクがあると想像してください。Java 7 のクラスを使用したソリューションはどのFilesようなものになるでしょうか? このようなもの:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

import static java.nio.charset.StandardCharsets.UTF_8;

public class Main {

   public static void main(String[] args) throws IOException {

       List<String> lines = Files.readAllLines(Paths.get("C:\\Users\\Username\\Desktop\\pushkin.txt"), UTF_8);

       List<String> result = new ArrayList<>();

       for (String s: lines) {
           if (s.startsWith("How")) {
               String upper = s.toUpperCase();
               result.add(upper);
           }
       }

       for (String s: result) {
           System.out.println(s);
       }
   }
}
コンソール出力: 断食のビジョンのように、純粋な美しさの天才のように。 それはできたようですが、このような単純なタスクの割に、コードが少し...冗長になってしまったとは思いませんか? Java 8 Stream API を使用すると、ソリューションはより洗練されたものになります。
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Main {

   public static void main(String[] args) throws IOException {

       Stream<String> stream = Files.lines(Paths.get("C:\\Users\\Username\\Desktop\\pushkin.txt"));

       List<String> result  = stream
               .filter(line -> line.startsWith("How"))
               .map(String::toUpperCase)
               .collect(Collectors.toList());
       result.forEach(System.out::println);
   }
}
同じ結果が得られましたが、コードは大幅に減りました。また、「読みやすさ」においても負けているとは言えません。Stream API に詳しくなくても、このコードの動作については簡単にコメントできると思います。しかし、要するに、ストリームはさまざまな機能を実行できる一連の要素です。メソッドから Stream オブジェクトを取得しFiles.lines()、それに 3 つの関数を適用します。
  1. このメソッドを使用して、filter()ファイルから「How」で始まる行のみを選択します。

  2. このメソッドを使用して選択されたすべての行を調べmap()、それぞれを大文字に変換します。

  3. 結果の行をすべて結合して、Listを使用しますcollect()

出口でも同じ結果が得られます。 断食中のビジョンのような、純粋な美しさの天才のようなものです。 このライブラリの機能について詳しく知りたい場合は、この記事を読むことをお勧めします。私たちの羊、つまりファイルに戻ります :) 今日検討する最後の可能性は、ファイル ツリーをたどることです。最新のオペレーティング システムのファイル構造は、ほとんどの場合ツリーの形式をとります。ツリーにはルートがあり、そこから他のブランチを分離できるブランチもあります。ディレクトリはルートとブランチの役割を果たします。たとえば、ディレクトリ「 C:// 」はルートとして機能します。そこから「C://Downloads」と「C://Users」という 2 つのブランチが分岐します。これらの各ブランチからさらに 2 つのブランチがあります: 「C://Downloads/Pictures」、「C://Downloads/Video」、「C://Users/JohnSmith」、「C://Users/Pudge2005」 。これらの支店から他の支店が分岐するなど。- これが木がどのようになるかです。Linux では、これはほぼ同じに見えますが、そこではディレクトリがルートとして機能するだけです/ ファイル、パス - 2次に、タスクがあると想像してください。ルート ディレクトリを知っているので、それを通過し、すべてのレベルのフォルダを調べて、その中にあるコンテンツを含むファイルを見つける必要があります。私たちには必要です。「これは必要なファイルです!」という行を含むファイルを探します。ルート ディレクトリは、デスクトップにある「testFolder」フォルダになります。その中には次の内容があります: ファイル、パス - 3フォルダー level1-a と level1-b 内にもフォルダーがあります: ファイル、パス - 4ファイル、パス - 5これらの「第 2 レベルのフォルダー」内にはそれ以上のフォルダーはなく、個々のファイルのみがあります: ファイル、パス - 6ファイル、パス - 7コンテンツを含む 3 つのファイルを特別に指定します。明確な名前が必要 - FileWeNeed1.txt 、 FileWeNeed2.txt 、 FileWeNeed3.txt これらは、Java を使用してコンテンツによって検索する必要があるものです。どうすればこれができるでしょうか?ファイル ツリーを横断するための非常に強力な方法が役に立ちますFiles.walkFileTree()。やるべきことは次のとおりです。まず、 が必要ですFileVisitorFileVisitorは、ファイル ツリーを移動するためのすべてのメソッドを説明する特別なインターフェイスです。具体的には、ファイルの内容を読み取り、必要なテキストが含まれているかどうかを確認するロジックをそこに配置します。これは私たちのものは次のようになりますFileVisitor:
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.List;

public class MyFileVisitor extends SimpleFileVisitor<Path> {

   @Override
   public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {

       List<String> lines = Files.readAllLines(file);
       for (String s: lines) {
           if (s.contains("This is the file we need")) {
               System.out.println("Required file found!");
               System.out.println(file.toAbsolutePath());
               break;
           }
       }

       return FileVisitResult.CONTINUE;
   }
}
この場合、クラスは から継承しますSimpleFileVisitor。これは を実装するクラスでありFileVisitor、オーバーライドする必要があるメソッドは 1 つだけですvisitFile()。ここでは、各ディレクトリ内の各ファイルに対して何を行う必要があるかを説明します。より複雑なトラバーサル ロジックが必要な場合は、独自の実装を作成する必要がありますFileVisitor。そこでさらに 3 つのメソッドを実装する必要があります。
  • preVisitDirectory()— フォルダーに入る前に実行する必要があるロジック。

  • visitFileFailed()— ファイルの入力が不可能な場合(アクセスできない、またはその他の理由)、どうすればよいですか。

  • postVisitDirectory()— フォルダーに入った後に実行する必要があるロジック。

そんなロジックはないので、それで十分ですSimpleFileVisitor。メソッド内のロジックはvisitFile()非常に単純です。ファイルからすべての行を読み取り、必要なコンテンツが含まれているかどうかを確認し、含まれている場合はコンソールへの絶対パスを出力します。問題を引き起こす可能性がある唯一の行は次の行です。
return FileVisitResult.CONTINUE;
実際、すべてがシンプルです。ここでは、ファイルが入力され、必要な操作がすべて完了した後にプログラムが何をすべきかを簡単に説明します。この場合、ツリーのトラバースを続ける必要があるため、オプションを選択しますCONTINUE。しかし、たとえば、「これは必要なファイルです」を含むすべてのファイルを見つけるのではなく、そのようなファイルを 1 つだけ見つけるという別のタスクを行うこともできます。この後、プログラムを終了する必要があります。この場合、コードはまったく同じに見えますが、break ではありません。こうなるでしょう:
return FileVisitResult.TERMINATE;
それでは、コードを実行して、機能するかどうかを確認してみましょう。
import java.io.IOException;
import java.nio.file.*;

public class Main {

   public static void main(String[] args) throws IOException {

       Files.walkFileTree(Paths.get("C:\\Users\\Username\\Desktop\\testFolder"), new MyFileVisitor());
   }
}
コンソール出力: 必要なファイルが見つかりました。C:\Users\ユーザー名\Desktop\testFolder\FileWeNeed1.txt 必要なファイルが見つかりました。C:\Users\ユーザー名\Desktop\testFolder\level1-a\level2-aa\FileWeNeed2.txt 必要なファイルが見つかりました。C:\Users\Username\Desktop\testFolder\level1-b\level2-bb\FileWeNeed3.txt 見事、できました。:) について詳しく知りたい場合は、この記事walkFileTree()をお勧めします。また、小さなタスクを完了することもできます。それを通常のタスクに置き換え、4 つのメソッドをすべて実装し、このプログラムの目的を考え出します。たとえば、すべてのアクションを記録するプログラムを作成できます。ファイルまたはフォルダーの名前を入力する前/後にコンソールに表示されます。以上です - それではまた! :) SimpleFileVisitorFileVisitor
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION