대부분의 경우 프로그램은 작업 중 특정 파일에 액세스를 해야한다. 예를 들어, 사용자 데이터는 일부 외부 파일에 기록될 수 있고, 이를 읽으려면 프로그램이 데이터 열기, 읽기, 편집 및 닫기 등의 작업을 수행할 수 있어야 한다.
File클래스는 Java 1.0에서 등장한 파일과 디렉터리에 대한 정보를 관리하는 클래스다.File 클래스는 java.io 패키지에 정의되어 있으며 스트림에서 직접 작동하지 않는다. import java.io.File;
import java.io.IOException;
import java.util.Date;
public class FileMain {
public static void main(String[] args) throws IOException {
File file = new File("temp/example.txt");
File directory = new File("temp/exampleDir");
// exists(): 파일이나 디렉터리의 존재 여부를 확인
System.out.println("File exist: " + file.exists());
// createNewFile() 새 파일을 생성
boolean create = file.createNewFile();
System.out.println("File create: " + create);
// mkdir(): 새 디렉터리를 생성
boolean dirCreated = directory.mkdir();
System.out.println("Directory created: " + dirCreated);
// delete(): 파일이나 디렉터리를 삭제
boolean deleted = file.delete();
System.out.println("File deleted = " + deleted);
// isFile(): 파일인지 확인
System.out.println("Is file: " + file.isFile());
// isDirectory(): 디렉터리인지 확인
System.out.println("Is directory : " + directory.isDirectory());
// getName(): 파일이나 디렉터리의 이름을 반환
System.out.println("File Name: " + file.getName());
// length(): 파일의 크기를 바이트 단위로 반환
System.out.println("File size: " + file.length() + "byte");
// renameTo(): 파일의 이름을 변경하거나 이동
File newFile = new File("temp/newExample.txt");
boolean renamed = file.renameTo(newFile);
System.out.println("File renamed: " + renamed);
// lastModified(): 마지막 수정 시간을 반환
long lastModified = newFile.lastModified();
System.out.println("Last modifed: " + new Date(lastModified));
}
}
참고 : Java에서 다루는 파일과 디렉토리는 운영 체제 수준에서 다루는 것과 서로 다른 객체다.
File보다 성능과 편의성이 모두 개선되었다.FileInputStream, FileWriter)의 사용을 고민하기 전에 Files에 있는 기능을 먼저 찾아보자.import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
public class FilesMain {
public static void main(String[] args) throws IOException {
Path file = Path.of("temp/example.txt");
Path directory = Path.of("temp/exampleDor");
// exists(): 파일이나 디렉터리의 존재 여부를 확인
System.out.println("File exists: " + Files.exists(file));
// createFile() 새 파일을 생성
try {
Files.createFile(file);
System.out.println("File created");
} catch (FileAlreadyExistsException e) {
System.out.println(file + "File already exists");
}
// createDirectories(): 새 디렉터리를 생성
try {
Files.createDirectories(directory);
} catch (FileAlreadyExistsException e) {
System.out.println(directory + "Directory already exists");
}
// delete(): 파일이나 디렉터리를 삭제
Files.delete(file);
System.out.println("File deleted");
// isRegularFile(): 일반 파일인지 확인
System.out.println("Is regular file: " + Files.isRegularFile(file));
// isDirectory(): 디렉토리인지 확인
System.out.println("Is directory: " + Files.isDirectory(directory));
// getFileName(): 파일이나 디렉토리의 이름을 반환
System.out.println("File name: " + file.getFileName());
// size(): 파일의 크기를 바이트 단위로 반환
System.out.println("File size: " + Files.size(file));
// move(): 파일의 이름을 변경하거나 이동
Path newFile = Path.of("temp/newExample.txt");
Files.move(file, newFile, StandardCopyOption.REPLACE_EXISTING);
System.out.println("File moved/renamed");
// getLastModifiedTime(): 마지막으로 수정된 시간을 반환
System.out.println("Last modify: " + Files.getLastModifiedTime(newFile));
// readAttributes() : 파일의 기본 속성들을 한 번에 읽기
BasicFileAttributes attrs = Files.readAttributes(newFile, BasicFileAttributes.class);
System.out.println("==== Attributes ====");
System.out.println("Creation time: " + attrs.creationTime());
System.out.println("Is directory: " + attrs.isDirectory());
System.out.println("Is regular file: " + attrs.isRegularFile());
System.out.println("is symbolic link: " + attrs.isSymbolicLink());
System.out.println("Size: " + attrs.size());
}
}
/Users/IdeaProjects/java-basic/src/../../Users//IdeaProjects../../java.dmgimport java.io.*;
public class FilePath{
public static void main(String[] args) throws IOException {
File file = new File("temp/..");
// 상대 경로
System.out.println("path = " + file.getPath());
// 절대 경로
System.out.println("Absolute path = " + file.getAbsolutePath());
// 정규 경로
System.out.println("Canonical path = " + file.getCanonicalPath());
File[] files = file.listFiles();
for(File f : files){
System.out.println((f.isFile() ? "F":"D") + " | " + f.getName());
}
}
}
public class FilesPath{
public static void main(String[] args) throws IOException {
Path path = Path.of("temp/..");
// 상대 경로
System.out.println("path = " + path);
// 절대 경로
System.out.println("Absolute path = " + path.toAbsolutePath());
// 정규 경로
System.out.println("Canonical path = " + path.toRealPath());
Stream<Path> pathStream = Files.list(path);
List<Path> list = pathStream.toList();
pathStream.close();
for(Path p : list) {
System.out.println((Files.isRegularFile(p) ? "F": "D") + " | " + p.getFileName());
}
}
}
FileReader, FileWriter 등 스트림 클래스를 사용해서 문자 파일을 읽고 썼다.BufferedReader와 같은 스트림 클래스를 추가해야 했다.import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import static java.nio.charset.StandardCharsets.*;
public class WriteAndReadString {
private static final String PATH= "temp/hello2.txt";
public static void main(String[] args) throws IOException {
String writeString = "abc\n가나다";
System.out.println("== Write String ==");
System.out.println(writeString);
Path path = Path.of(PATH);
// 파일에 쓰기
Files.writeString(path, writeString, UTF_8);
// 파일에서 읽기
String readString = Files.readString(path, UTF_8);
System.out.println("== Read String ==");
System.out.println(readString);
}
}
Files.writeString() : 파일에 쓰기Files.readStirng() : 파일에서 모든 문자 읽기Files를 사용하면 아주 쉽게 파일에 문자를 스고 읽을 수 있다.
import java.io.IOException;
import java.nio.file.*;
import java.util.List;
import java.util.stream.Stream;
import static java.nio.charset.StandardCharsets.*;
public class LineReadString {
private static final String PATH= "temp/hello2.txt";
public static void main(String[] args) throws IOException {
String writeString = "abc\n가나다";
System.out.println("== Write String ==");
System.out.println(writeString);
Path path = Path.of(PATH);
// 파일에 쓰기
Files.writeString(path, writeString, UTF_8);
// 파일에서 읽기
System.out.println("== Read String ==");
List<String> lines = Files.readAllLines(path, UTF_8);
for (int i = 0; i < lines.size(); i++) {
System.out.println((i+1) + ": " + lines.get(i));
}
Stream<String> lineStream = Files.lines(path, UTF_8);
lineStream.forEach(line -> System.out.println(line));
lineStream.close();
/**
try(Sream<String> lineStream = Files.lines(path, UTF_8)){
lineStream.forEach(line -> System.out.println(line));
}
*/
}
}
Files.readAllLines(path)Files.lines(path)BufferedReader를 통해서도 한 줄 단위로 나누어 처리가 가능하다.temp/copy.dat미리 만들어 둔다.import java.io.*;
public class FileByteCopy {
private static final int FILE_SIZE = 200 * 1024 * 1024; // 200MB
public static void main(String[] args) throws IOException {
long startTime = System.currentTimeMillis();
FileInputStream fis = new FileInputStream("temp/copy.dat");
FileOutputStream fos = new FileOutputStream("temp/copy_new.dat");
byte[] bytes = fis.readAllBytes();
fos.write(bytes);
fis.close();
fos.close();
long endTime = System.currentTimeMillis();
System.out.println("File taken: " + (endTime-startTime) + "ms");
}
}
FileInputStream에서 readAllBytes를 통해 한 번에 모든 데이터를 읽고 write(bytes)를 통해 한 번에 모든 데이터를 저장한다.copy.dat) -> 자바(byte) -> 파일(copy_new.dat)의 과정을 거친다.copy.dat파일의 데이터를 자바 프로세스가 사용하는 메모리에 부른다. 이후 메모리에 있는 데이터를 copy_new.dat에 전달한다.import java.io.*;
public class FileCopyMainV2 {
private static final int FILE_SIZE = 200 * 1024 * 1024; // 200MB
public static void main(String[] args) throws IOException {
long startTime = System.currentTimeMillis();
FileInputStream fis = new FileInputStream("temp/copy.dat");
FileOutputStream fos = new FileOutputStream("temp/copy_new.dat");
fis.transferTo(fos);
fis.close();
fos.close();
long endTime = System.currentTimeMillis();
System.out.println("File taken: " + (endTime-startTime) + "ms");
}
}
InputStream에는 transferTo()라는 메서드가 있다.(자바 9부터 지원)InputStream에서 읽은 데이터를 바로 OutputStream으로 출력한다.transferTo()는 성능 최적화가 되어 있기 때문에 바이트 변환 복사 보다 조금 더 빠르다. byte[] bytes = fis.readAllBytes();
fos.write(bytes);
// 위 코드가 아래 한줄 코드로 압축
fis.transferTo(fos);
import java.io.*;
import java.nio.file.*;
public class FilesCopy{
private static final int FILE_SIZE = 200 * 1024 * 1024; // 200MB
public static void main(String[] args) throws IOException {
long startTime = System.currentTimeMillis();
Path source = Path.of("temp/copy.dat");
Path target = Path.of("temp/copy_new.dat");
Files.copy(source,target, StandardCopyOption.REPLACE_EXISTING);
long endTime = System.currentTimeMillis();
System.out.println("File taken: " + (endTime-startTime) + "ms");
}
}
Files.copy()copy.dat) -> 파일(copy_new.dat)의 과정을 거친다.