Java - File, Files Class

INHEES·2025년 4월 20일

Java

목록 보기
13/13

금일은 File, Files 클래스에 대해 알아보는 시간입니다.

목차

  • File, Files
  • 경로 표시
  • Files 문자 파일 읽기
  • 파일 복사 최적화

File, Files, Path

파일 또는 디렉토리를다룰 때는 File, Files, Path 클래스를 활용하면 됩니다.

        File file = new File("temp/example.txt");
        File directory = new File("temp/exampleDir");

        // 1. exists(): 파일이나 디렉토리의 존재 여부를 확인
        System.out.println("File exists: " + file.exists());

        // 2. createNewFile(): 새 파일을 생성
        boolean created = file.createNewFile();
        System.out.println("File created: " + created);

        // 3. mkdir(): 새 디렉토리를 생성
        boolean dirCreated = directory.mkdir();
        System.out.println("Directory created: " + dirCreated);

        ...

다음과 같이 메서드를 사용하면 되지만 오래된 방법입니다.


자바 1.0에서 File 클래스가 등장했다. 이후에 자바 1.7에서 File 클래스를 대체할 Files 와 Path 가 등장했다.

FileInputStream , FileWriter의 사용을 고민하기 전에 Files 에 있는 기능을 알아보고 필요한 함수는 찾아보면서 적용하는게 맞다.

Files 를 사용할 때 파일이나, 디렉토리의 경로는 Path 클래스를 사용해야 한다.

        Path file = Path.of("temp/example.txt");
        Path directory = Path.of("temp/exampleDir");

        // 1. exists(): 파일이나 디렉토리의 존재 여부를 확인
        System.out.println("File exists: " + Files.exists(file));

        // 2. createFile(): 새 파일을 생성
        try {
            Files.createFile(file);
            System.out.println("File created");
        } catch (FileAlreadyExistsException e) {
            System.out.println(file + " File already exists");
        }

        // 3. createDirectory(): 새 디렉토리를 생성
        try {
            Files.createDirectory(directory);
            System.out.println("Directory created");
        } catch (FileAlreadyExistsException e) {
            System.out.println(directory + " Directory already exists");
        }

        // 4. delete(): 파일이나 디렉토리를 삭제
        //Files.delete(file);
        //System.out.println("File deleted");

        // 5. isRegularFile(): 일반 파일인지 확인
        System.out.println("Is regular file: " + Files.isRegularFile(file));

        // 6. isDirectory(): 디렉토리인지 확인
        System.out.println("Is directory: " + Files.isDirectory(directory));

        // 7. getFileName(): 파일이나 디렉토리의 이름을 반환
        System.out.println("File name: " + file.getFileName());

        // 8. size(): 파일의 크기를 바이트 단위로 반환
        System.out.println("File size: " + Files.size(file) + " bytes");

        // 9. move(): 파일의 이름을 변경하거나 이동
        Path newFile = Paths.get("temp/newExample.txt");
        Files.move(file, newFile, StandardCopyOption.REPLACE_EXISTING);
        System.out.println("File moved/renamed");

        // 10. getLastModifiedTime(): 마지막으로 수정된 시간을 반환
        System.out.println("Last modified: " + 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());

경로 표시 ( 절대 경로, 정규 경로)

File 의 경로 표시 관련 메서드 입니다.


        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());
        }
    path = temp/..
    Absolute path = /Users/yh/study/inflearn/java/java-adv2/temp/..
    Canonical path = /Users/yh/study/inflearn/java/java-adv2
    D | temp
    F | java-adv2-v1.iml
    D | out
    F | .gitignore
    D | .idea
    D | src
  • 절대 경로(Absolute path): 절대 경로는 경로의 처음부터 내가 입력한 모든 경로를 다 표현한다.

  • 정규 경로(Canonical path): 경로의 계산이 모두 끝난 경로이다. 정규 경로는 하나만 존재한다.

    	- .. 는 상위 디렉토리를 듯한다. 

다음은 Files, Path 의 경로 표시이다.


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

Files 문자 파일 읽기

문자로된 파일을 읽고 쓸 때 과거에는 FileReader , FileWriter 같은 복잡한 스트림 클래스를 사용해야 하며 한 줄 단위로 파일
을 읽으려면 BufferedReader 와 같은 스트림 클래스를 추가해야 했다. 이러한 문제를 Files 클래스가 해결해준다.

모든 문자 읽기


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

파일을 스트림 단위로 나누어 조회 하면 용량이 큰 파일의 경우 outOfMemoryException 에러를 피할수 있다.
메모리 사용량을 줄인 람다와 스트림 코드이다.


Stream<String> lineStream = Files.lines(path, UTF_8);
try(Stream<String> lineStream = Files.lines(path, UTF_8)){
   lineStream.forEach(line -> System.out.println(line));
}

파일 복사 최적화

예시로 200mb 임시 파일을 하나 만들어보겠습니다.

    public static void main(String[] args) throws IOException {
        String fileName = "temp/copy.dat";
        long startTime = System.currentTimeMillis();

        FileOutputStream fos = new FileOutputStream(fileName);
        byte[] buffer = new byte[FILE_SIZE];
        fos.write(buffer);
        fos.close();

        long endTime = System.currentTimeMillis();
        System.out.println("File created: " + fileName);
        System.out.println("File size: " + FILE_SIZE / 1024 / 1024 + "MB");
        System.out.println("Time taken: " + (endTime - startTime) + "ms");
    }
    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("Time taken: " + (endTime - startTime) + "ms");
    }

Files.copy() 는 자바에 파일 데이터를 불러오지 않고, 운영체제의 파일 복사 기능을 사용한다. 파일에서의 byte 코드 즉 자바 메모리의 불러오는 과정이 불필요하다 .

  • 파일(copy.dat) -> 파일(copy_new.dat)

물론 이 기능은 파일에서 파일을 복사할 때만 유용하다. 만약 파일의 정보를 읽어서 처리해야 하거나, 스트림을 통해 네
트워크에 전달해야 한다면 앞서 설명한 스트림을 직접 사용해야 한다.

profile
이유를 찾아보자

0개의 댓글