JavaRush /Java Blog /Random-KO /Java 파일, 경로

Java 파일, 경로

Random-KO 그룹에 게시되었습니다
안녕하세요! 오늘은 파일 및 디렉토리 작업에 대해 이야기하겠습니다. 여러분은 이미 파일 내용을 관리하는 방법을 알고 있습니다. 이에 대한 수업이 많이 있었습니다. :) 이러한 목적에 필요한 여러 수업을 쉽게 기억하실 수 있을 것 같습니다. 오늘 강의에서는 파일 관리(생성, 이름 바꾸기 등)에 대해 구체적으로 설명하겠습니다. Java 7 이전에는 이러한 모든 작업이 File. 여기에서 그의 작업에 대해 읽을 수 있습니다 . 그러나 Java 7에서 언어 작성자는 파일 및 디렉토리 작업 방식을 변경하기로 결정했습니다. File이는 수업에 여러 가지 단점이 있다는 사실 때문이었습니다 . copy()예를 들어, 한 위치에서 다른 위치로 파일을 복사할 수 있는 방법(분명히 필요한 기능인 것처럼 보임)이 없었습니다 . 또한 클래스에는 -value를 File반환하는 메서드가 꽤 많이 있었습니다 boolean. 오류가 발생하면 이러한 메서드는 예외를 발생시키지 않고 false를 반환하므로 오류 진단과 원인 파악이 매우 어렵습니다. 단일 클래스 대신 File최대 3개의 클래스가 등장했습니다: Paths, PathFiles. 엄밀히 말하면 Path이것은 클래스가 아니라 인터페이스입니다. 서로 어떻게 다른지, 왜 각각이 필요한지 알아 봅시다. 가장 쉬운 것부터 시작해 보겠습니다 Paths.

경로

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

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\Username\Desktop
    C:\

    거짓

    방법이 어떻게 작동하는지 주의 깊게 살펴보세요 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");
    
           System.out.println(testFilePath.endsWith("estFile.txt"));
           System.out.println(testFilePath.endsWith("Desktop\\testFile.txt"));
       }
    }

    콘솔 출력:

    거짓
    사실

    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());
       }
    }

    콘솔 출력:

    진실

  • 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\예제
    C:\Users\예제

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

    콘솔 출력:

    사용자 이름\Desktop\testFile.txt

전체 메소드 목록은 Path상당히 많습니다. Oracle 설명서 에서 해당 내용을 모두 찾을 수 있습니다 . 검토를 진행하겠습니다 Files.

파일

Files- 클래스의 정적 메소드를 이동한 유틸리티 클래스입니다 File. - 이것은 or 와 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>! 즉, 파일의 행 목록을 반환합니다. 물론 이렇게 하면 콘텐츠 작업이 매우 편리해집니다. 예를 들어 전체 파일을 한 줄씩 일반 루프로 콘솔에 출력할 수 있기 때문입니다 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"라는 단어로 시작하는 모든 줄을 찾아서 대문자로 변환하고 콘솔에 출력하는 작업이 있다고 상상해 보세요. 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("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. 우리는 모든 결과 라인 Listcollect().

출구에서 우리는 동일한 결과를 얻습니다: 마치 단식하는 비전처럼, 순수한 아름다움의 천재처럼. 이 라이브러리의 기능에 대해 자세히 알아보려면 이 문서를 읽어 보시기 바랍니다 . 우리는 양, 즉 파일로 돌아갈 것입니다. :) 오늘 고려할 마지막 가능성은 파일 트리를 살펴보는 것입니다 . 최신 운영 체제의 파일 구조는 대부분 트리 형태를 취합니다. 즉, 루트가 있고 다른 가지를 분리할 수 있는 가지가 있습니다. 디렉터리는 루트와 분기의 역할을 합니다. 예를 들어, " C:// " 디렉토리는 루트 역할을 할 수 있습니다 . 여기에서 두 개의 분기가 분기됩니다: " C://Downloads " 및 " C://Users ". 각 분기에는 " C://Downloads/Pictures ", " C://Downloads/Video ", " C://Users/JohnSmith ", " C://Users/Pudge2005 " 라는 2개의 분기가 더 있습니다. . 이 가지 등에서 다른 가지가 갈라집니다. -나무가 이렇게 나옵니다. Linux에서는 거의 동일해 보입니다. 디렉토리만 루트 역할을 합니다. / 파일, 경로 - 2 이제 작업이 있다고 상상해 보십시오. 루트 디렉토리를 알고 있으면 루트 디렉토리를 살펴보고 모든 수준의 폴더를 살펴보고 그 안에서 콘텐츠가 있는 파일을 찾아야 합니다. 우리는 필요합니다. "이것이 우리에게 필요한 파일입니다!"라는 줄이 포함된 파일을 찾습니다. 루트 디렉터리는 바탕 화면에 있는 "testFolder" 폴더입니다. 그 안에는 다음과 같은 내용이 있습니다. 파일, 경로 - 3level1-a 및 level1-b 폴더 안에는 폴더도 있습니다. 파일, 경로 - 4파일, 경로 - 5이 "두 번째 수준 폴더" 안에는 더 이상 폴더가 없고 개별 파일만 있습니다. 파일, 경로 - 6파일, 경로 - 7우리는 내용이 포함된 3개의 파일을 특별히 지정합니다. 명확한 이름이 필요합니다 - FileWeNeed1.txt , FileWeNeed2.txt, FileWeNeed3.txt Java를 사용하여 콘텐츠별로 찾아야 하는 항목입니다. 어떻게 할 수 있나요? 파일 트리를 탐색하는 매우 강력한 방법이 구출됩니다 Files.walkFileTree(). 우리가 해야 할 일은 다음과 같습니다. 먼저, 가 필요합니다 FileVisitor. FileVisitor파일 트리를 탐색하는 모든 방법을 설명하는 특수 인터페이스입니다. 특히, 파일의 내용을 읽고 필요한 텍스트가 포함되어 있는지 확인하는 논리를 거기에 넣을 것입니다. 이것이 우리의 모습입니다 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, 단 하나의 메서드만 재정의하면 됩니다 visitFile(). 여기에서는 각 디렉터리의 각 파일에 대해 수행해야 할 작업을 설명합니다. 더 복잡한 순회 논리가 필요한 경우 자체 구현을 작성해야 합니다 FileVisitor. 거기에서 3가지 메소드를 더 구현해야 합니다:
  • preVisitDirectory()— 폴더에 들어가기 전에 실행되어야 하는 논리.

  • visitFileFailed()— 파일 입력이 불가능한 경우(접근 불가 또는 기타 사유) 어떻게 해야 할까요?

  • postVisitDirectory()— 폴더에 들어간 후 실행해야 하는 로직입니다.

그런 논리가 없기 때문에 우리에게는 충분합니다 SimpleFileVisitor. 메서드 내부의 논리는 visitFile()매우 간단합니다. 파일의 모든 줄을 읽고 필요한 콘텐츠가 포함되어 있는지 확인한 다음, 포함되어 있으면 절대 경로를 콘솔에 인쇄합니다. 문제를 일으킬 수 있는 유일한 줄은 다음과 같습니다.
return FileVisitResult.CONTINUE;
사실 모든 것이 간단합니다. 여기에서는 파일이 입력되고 필요한 모든 작업이 완료된 후 프로그램이 수행해야 하는 작업을 간단히 설명합니다. 우리의 경우 트리를 계속 순회해야 하므로 옵션을 선택합니다 CONTINUE. 그러나 예를 들어 우리는 "필요한 파일입니다"가 포함된 모든 파일을 찾는 것이 아니라 그러한 파일 하나만 찾는 또 다른 작업을 수행할 수 있습니다 . 이후에는 프로그램을 종료해야 합니다. 이 경우 코드는 완전히 동일해 보이지만 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\Username\Desktop\testFolder\FileWeNeed1.txt 필요한 파일을 찾았습니다! C:\Users\Username\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