최원종의 개발 블로그

파일 복사 기능 만들기 본문

Java/JAVA 유용한 클래스

파일 복사 기능 만들기

chl6698 2026. 3. 25. 17:35

파일 복사의 원리

 

읽기와 쓰기를 동시에 열어두고, 읽은 데이터를 바로 다른 파일에 쓰는 방법

[원본 파일] ──읽기──► [프로그램 메모리] ──쓰기──► [복사본 파일]
          InputStream               OutputStream

-코드

package io.ch18;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileCopy {

    public static void main(String[] args) {

        //파일 경로 지정
        String sourceFilePath = "employees.zip";
        String destinationFilePath = "employees_copy.zip";

        //소요 시간 측정 시작
        //현재 시각을 나노초(10억분의 1초) 단위로 변환 1970 ~
        long startTime = System.nanoTime();

        // 파일 복사 기능
        try (FileInputStream fis = new FileInputStream(sourceFilePath);
             FileOutputStream fos = new FileOutputStream(destinationFilePath)) {
            // employees.zip 에서 1바이트씩 읽어서
            //employees_copy.zip 에서 1바이트 씩 쓰기
            int data;
            while ((data = fis.read()) != -1) {
                fos.write(data);
                fos.flush();

            }
            System.out.println("파일 복사 완료");
            
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        
        long endTime = System.nanoTime();
        // 소요 시간 계산
        long duration = endTime - startTime;
        double seconds = duration / 1_000_000_000.0; // 나노 초 --> 초 변환
        System.out.println("나노 초 값 : " + duration);
        System.out.println("초 값 : " + seconds);

    }
}

-버퍼를 이용한 복사 코드

package io.ch18;

import java.io.*;

public class FileCopyBuffered {

    public static void main(String[] args) {

        //파일 경로 지정
        String sourceFilePath = "employees.zip";
        String destinationFilePath = "employees_copy.zip";

        //소요 시간 측정 시작
        //현재 시각을 나노초(10억분의 1초) 단위로 변환 1970 ~
        long startTime = System.nanoTime();

        // 파일 복사 기능 - 빠른 버전 (버퍼 활용)

        try (FileInputStream fis = new FileInputStream(sourceFilePath);
             FileOutputStream fos = new FileOutputStream(destinationFilePath);
             BufferedInputStream bfis = new BufferedInputStream(fis);
             BufferedOutputStream bfos = new BufferedOutputStream(fos)) {

            //버퍼에 크기를 직접 지정해주자.
            //1 바이트가 1000개 있으면 1KB  정확한 크기-1024
            byte[] bytes = new byte[1024]; //1KB 씩 읽을 버퍼 계열

            int data;
            while ((data = bfis.read(bytes)) != -1) {
                bfos.write(bytes, 0, data); //읽은 만큼 씀!!

            }
            System.out.println("파일 복사 완료");


        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }


        long endTime = System.nanoTime();
        // 소요 시간 계산
        long duration = endTime - startTime;
        double seconds = duration / 1_000_000_000.0; // 나노 초 --> 초 변환
        System.out.println("나노 초 값 : " + duration);
        System.out.println("초 값 : " + seconds);

    }
}

write(bytes, 0, data) vs write(bytes)

// 잘못된 코드 - 버퍼 배열 전체를 씀
bfos.write(bytes);

// 올바른 코드 - 실제로 읽은 만큼만 씀
bfos.write(bytes, 0, data);

 

-다른 이유

파일 크기: 2500바이트, 버퍼 크기: 1024바이트

1회차: bfis.read(bytes) → 1024바이트 읽음,  data = 1024
2회차: bfis.read(bytes) → 1024바이트 읽음,  data = 1024
3회차: bfis.read(bytes) →  452바이트만 읽음, data = 452
       bytes 배열에는 앞쪽 452바이트만 새 데이터로 채워짐
       나머지 572바이트는 2회차에 읽었던 데이터가 그대로 남아있음

write(bytes)          → 1024바이트 전부 씀 → 쓰레기값 572바이트가 파일에 포함됨!
write(bytes, 0, data) →  452바이트만 씀   → 정확하게 복사

 

 

- write(bytes, 0, data)에서 세 인자의 의미

bytes  : 쓸 데이터가 담긴 배열
0      : 배열의 몇 번째 인덱스부터 쓸지 (0 = 처음부터)
data   : 몇 바이트를 쓸지 (실제로 읽은 만큼)

 


I/O단원 최종 정리

                [Java I/O 핵심 클래스 총정리]

바이트 기반                          문자 기반
InputStream                          Reader
  FileInputStream                      FileReader
  BufferedInputStream                  BufferedReader   ← readLine()
OutputStream                         Writer
  FileOutputStream                     FileWriter
  BufferedOutputStream                 BufferedWriter   ← newLine()

[브릿지 클래스]
InputStreamReader  : 바이트 스트림 → 문자 스트림  (System.in 을 문자로 읽을 때)
OutputStreamWriter : 문자 스트림  → 바이트 스트림

 

스트림 선택 방법

내가 다루는 파일이 텍스트 파일인가?

  YES → FileReader / FileWriter
        성능이 필요하면 → BufferedReader / BufferedWriter 로 감싸기

  NO  (이미지, 동영상, zip 등 바이너리 파일)
      → FileInputStream / FileOutputStream
        성능이 필요하면 → BufferedInputStream / BufferedOutputStream 으로 감싸기

키보드에서 입력받기
  간단할 때       → Scanner
  입력이 많을 때  → new BufferedReader(new InputStreamReader(System.in))