CodeGym /Java Blog /ランダム /Java ファイル、パス
John Squirrels
レベル 41
San Francisco

Java ファイル、パス

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

パス

Paths は、単一の静的メソッドget()を備えた非常に単純なクラスです。これは、渡された文字列または URI から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 は、概して、Fileクラスの再設計された類似物です。Fileよりもはるかに簡単に操作できます。 まず、多くのユーティリティ (静的) メソッドが取り出され、Filesクラスに移動されました。 次に、 Pathインターフェースのメソッドの戻り値に順序が課されました。Fileクラスでは、メソッドはStringboolean、または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\Username\Desktop
    C:\
    true
    false
    

    opensWith()メソッドがどのように動作するかに注意してください。現在のパスが渡されたパスで終わるかどうかを確認します。具体的には、渡された文字列内ではなくパス内にあるかどうかです。

    これら 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"));
       }
    }
    

    コンソール出力:

    
    false
    true
    

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

    さらに、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());
       }
    }
    

    コンソール出力:

    
    true
    
  • 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));
       }
    }
    

    コンソール出力:

    
    Username\Desktop\testFile.txt
    

Pathメソッドの完全なリストは非常に長くなります。これらはすべてOracle のドキュメントに記載されています。次に、 Files の検討に移ります。

ファイル

Files は、 Fileクラスから取得された静的メソッドを保持するユーティリティ クラスです。ファイルは配列またはコレクションに相当します。違いは、配列やコレクションではなく、ファイルを操作することです :) ファイルとディレクトリの管理に重点を置いています。Filesクラスの静的メソッドを使用すると、ファイルとディレクトリを作成、削除、移動できます。これらの操作は、 createFile() (ディレクトリの場合は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 {

       // Create a file
       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 a directory
       Path testDirectory = Files.createDirectory(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory"));
       System.out.println("Was the directory created successfully?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory")));

       // Move the file from the desktop to the testDirectory directory. When you move a folder, you need to indicate its name in the folder!
       testFile1 = Files.move(testFile1, Paths.get("C:\\Users\\Username\\Desktop\\testDirectory\\testFile111.txt"), REPLACE_EXISTING);

       System.out.println("Did our file remain 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")));

       // Delete a 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()メソッド)。 コンソール出力:

Was the file created successfully? 
true 
Was the directory created successfully? 
true
Did our file remain on the desktop? 
false 
Has our file been moved to testDirectory? 
true 
Does the file still exist? 
false
ノート:インターフェイスのメソッドと同様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 {

       // Create a file
       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 a directory
       Path testDirectory2 = Files.createDirectory(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2"));
       System.out.println("Was the directory created successfully?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2")));

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

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

       System.out.println("Was our file copied to testDirectory?");
       System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2\\testFile111.txt")));
   }
}
コンソール出力:

Was the file created successfully? 
true 
Was the directory created successfully? 
true 
Did our file remain on the desktop? 
true 
Was our file copied to testDirectory? 
true
これで、プログラムでファイルをコピーする方法がわかりました。:) もちろん、このFilesクラスを使用すると、ファイル自体を管理できるだけでなく、そのコンテンツを操作することもできます。これには、write()データをファイルに書き込むためのメソッドと、データを読み取るための 3 つのメソッドすべてがあります: read()readAllBytes()、およびreadAllLines() 最後のメソッドについては後で詳しく説明します。なぜそれが?非常に興味深い戻り値の型があるためですList<String>。つまり、ファイル内のすべての行のリストが返されます。forもちろん、これにより、たとえば通常のループ を使用してファイル全体を 1 行ずつコンソールに表示できるため、ファイルの内容を操作するのが非常に便利になります。

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);
       }
   }
}
コンソール出力:

I still recall the wondrous moment: 
When you appeared before my sight, 
As though a brief and fleeting omen, 
Pure phantom in enchanting light.
超便利!:) この機能は Java 7 で登場しました。Stream API はJava 8 で登場しました。関数型プログラミングのいくつかの要素を Java に追加します。より豊富なファイル処理機能が含まれます。次のタスクがあると想像してください。「As」という単語で始まるすべての行を検索し、それらを大文字に変換して、コンソールに表示します。このクラスを使用したソリューションはFilesJava 7 ではどのようなものになるでしょうか? このようなもの:

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("As")) {
               String upper = s.toUpperCase();
               result.add(upper);
           }
       }

       for (String s: result) {
           System.out.println(s);
       }
   }
}
コンソール出力:

AS THOUGH A BRIEF AND FLEETING OMEN, 
PURE PHANTOM IN ENCHANTING LIGHT.
使命は達成されましたが、このような単純なタスクの割に、コードが少し...冗長になってしまったとは思いませんか? 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("As"))
               .map(String::toUpperCase)
               .collect(Collectors.toList());
       result.forEach(System.out::println);
   }
}
同じ結果が得られましたが、コードは大幅に減りました。さらに言えば、「読みやすさ」が失われているとは誰も言えません。Stream API に詳しくなくても、このコードの動作について簡単にコメントできると思います。つまり、ストリームは一連の要素であり、それに対してさまざまな操作を実行できます。メソッドから Stream オブジェクトを取得しFiles.lines()、それに 3 つの関数を適用します。
  1. filter()ファイルから「As」で始まる行のみを選択する方法を使用します。

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

  3. メソッドを使用して、collect()受信したすべての行を .html ファイルに収集しますList

同じ出力が得られます。

AS THOUGH A BRIEF AND FLEETING OMEN, 
PURE PHANTOM IN ENCHANTING LIGHT.
ここで、基本であるファイルに戻りましょう :) 今日検討する最後の機能は、ファイル ツリーをたどることです。最新のオペレーティング システムでは、ファイル構造はほとんどの場合ツリーのように見えます。ルートとブランチがあり、ブランチには他のブランチが存在することもあります。ルートとブランチはディレクトリです。たとえば、ディレクトリ「С://」がルートになる可能性があります。これには、「C://Downloads」と「C://Users」という 2 つのブランチが含まれています。これらのブランチにはそれぞれ、「C://Downloads/Pictures」、「C://Downloads/Video」、「C://Users/JohnSmith」、「C://Users/Pudge2005 」という 2 つのブランチがあります。「そして、これらのブランチには他のブランチなどがあり、これがツリーと呼ばれる理由です。Linux では、構造は似ていますが、/ ディレクトリがルートです。次に、ルート ディレクトリから開始する必要があると想像しください ファイル、パス - 2。 , そのすべてのフォルダーとサブフォルダーを調べて、特定の内容を持つファイルを見つけます。「これは必要なファイルです!」という行を含むファイルを検索します。ここでは、「testFolder」フォルダーを選択します。ルート ディレクトリとしてのデスクトップ。その内容は次のとおりです: ファイル、パス - 3level1-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("We found a file we need!");
               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());
   }
}
コンソール出力:

We found a file we need! 
C:\Users\Username\Desktop\testFolder\FileWeNeed1.txt 
We found a file we need! 
C:\Users\Username\Desktop\testFolder\level1-a\level2-a-a\FileWeNeed2.txt 
We found a file we need! 
C:\Users\Username\Desktop\testFolder\level1-b\level2-b-b\FileWeNeed3.txt
素晴らしい!出来た!:) この小さな挑戦を受け入れることもできます。SimpleFileVisitor通常の に置き換えFileVisitor、4 つのメソッドすべてをオーバーライドし、プログラムの独自の目的を考え出します。たとえば、すべてのアクションを記録するプログラムを作成できます。ファイルまたはフォルダーの名前を入力する前または後に表示します。それは今のところすべてです。また近いうちにお会いしましょう!:)
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION