File
. 여기에서 그의 작업에 대해 읽을 수 있습니다 . 그러나 Java 7에서 언어 작성자는 파일 및 디렉토리 작업 방식을 변경하기로 결정했습니다. File
이는 수업에 여러 가지 단점이 있다는 사실 때문이었습니다 . copy()
예를 들어, 한 위치에서 다른 위치로 파일을 복사할 수 있는 방법(분명히 필요한 기능인 것처럼 보임)이 없었습니다 . 또한 클래스에는 -value를 File
반환하는 메서드가 꽤 많이 있었습니다 boolean
. 오류가 발생하면 이러한 메서드는 예외를 발생시키지 않고 false를 반환하므로 오류 진단과 원인 파악이 매우 어렵습니다. 단일 클래스 대신 File
최대 3개의 클래스가 등장했습니다: Paths
, Path
및 Files
. 엄밀히 말하면 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
거의 동일하며 파일에서만 작동하고 배열 및 컬렉션에서는 작동하지 않습니다. :) 파일 및 디렉터리 관리에 중점을 둡니다. 정적 메소드를 사용하면 파일과 디렉토리를 생성, 삭제 및 이동할 수 있습니다. 이러한 작업에는 메소드 (디렉토리 - ) 및 가 사용됩니다 . 사용 방법은 다음과 같습니다. Arrays
Collections
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 {
//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"라는 단어로 시작하는 모든 줄을 찾아서 대문자로 변환하고 콘솔에 출력하는 작업이 있다고 상상해 보세요. Files
Java 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가지 함수를 적용합니다.
-
이 방법을 사용하여
filter()
파일에서 "How"로 시작하는 줄만 선택합니다. -
메소드를 사용하여 선택된 모든 행을 살펴보고
map()
각 행을 대문자로 줄입니다. -
우리는 모든 결과 라인
List
을collect()
.
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가지 방법을 모두 구현하고 이 프로그램의 목적을 생각해 보세요. 예를 들어, 모든 작업을 기록하는 프로그램을 작성할 수 있습니다. 파일이나 폴더 이름을 입력하기 전/후에 콘솔에 표시합니다. 그게 다야 - 나중에 보자! :) SimpleFileVisitor
FileVisitor
GO TO FULL VERSION