이것이 자바다 - Part 18

mj·2023년 2월 2일
0
post-thumbnail

Part 18 데이터 입출력

입출력 스트림

자바는 입력 스트림과 출력 스트림을 통해 데이터를 입출력한다.
스트림은 단방향으로 데이터가 흐르는 것을 말하는데, 데이터는 출발지에서 나와 도착지로 흘러들어간다.

프로그램을 기준으로 데이터가 들어오면 입력 스트림, 데이터가 나가면 출력 스트림이 도니다.

스트림의 구분

  • 바이트 스트림 : 그림, 멀티미디어, 문자 등 모든 종류의 데이터를 입출력할 때 사용
  • 문자 스트림 : 문자만 입출력할 때 사용

자바는 데이터 입출력과 관련된 라이브러리를 Java.io 패키지에서 제공하고 있다.
java.io 패키지는 바이트 스트림과 문자 스트림을 다음과 같이 이름으로 구분해서 제공한다.

구분바이트 입력 스트림바이트 출력 스트림문자 입력 스트림문자 출력 스트림
최상위 클래스InputStreamOutputStreamReaderWriter
하위 클래스FileInputStreamFileOutputStreamFileReaderFileWriter

바이트 입출력 스트림의 최상위 클래스는 InputStream과 OutputStream 이다.
이 클래스를 상속 받는 자식 클래스에는 접미사로 InputStream 또는 OutputStream이 붙는다.

문자 입출력 스트림의 최상위 클래스는 Reader와 Writer이다.
이 클래스를 상속받는 하위 클래스에는 접미사로 Reader 또는 Writer가 붙는다.

바이트 출력 스트림

outputStream은 바이트 출력 스트림의 최상위 클래스로 추상 클래스이다.
모든 바이트 출력 스트림 클래스는 이 OutputStream 클래스를 상속받아서 만들어진다.

OutputStream 클래스의 주요 메소드는 다음과 같다.

리턴 타입메소드설명
voidwrite(int b)1byte 를 출력
voidwrite(byte[] b)매개값으로 주어진 배열 b의 모든 바이트를 출력
voidwrite(byte[] b, int off, int len)매개값으로 주어진 배열 b[off]부터 len개의 바이트를 출력
voidflush()flush()
voidclose()출력 스트림을 닫고 사용 메모리 해제

1바이트 출력

write(int b) 메소드는 매개값 int(4byte)에서 끝 1byte만 출력한다.
매개변수가 int 타입이므로 4byte 모두를 보내는 것은 아니다.

FileOutputStream 생성자는 주어진 파일을 생성할 수 없으면 IOException을 발생시킨다.
write(), flush(), close() 메소드도 IOException이 발생할 수 있으므로 예외 처리를 해야 한다.

OutputStream은 내부에 작은 버퍼를 가지고 있다. write() 메소드가 호출되면 버퍼에 바이트를 우선 저장하고, 버퍼가 차면 순서대로 바이트를 출력한다.
flush() 메소드는 내부 버퍼에 잔류하는 모든 바이트를 출력하고 버퍼를 비우는 역할을 한다.

출력 스트림을 더 이상 사용하지 않을 때에는 close() 메소드를 호출해서 출력 스트림이 사용했던 메모리를 해제하는 것이 좋다.

바이트 배열 출력

write(byte[] b) 메소드는 매개값으로 주어진 배열의 모든 바이트를 출력한다.

만약 배열의 일부분을 출력하고 싶다면 write(byte[] b, int off, int len) 메소드를 사용하면 된다.
이 메소드는 b[off] 부터 len개의 바이트를 출력한다.

바이트 입력 스트림

InputStream은 바이트 입력 스트림의 최상위 클래스로, 추상 클래스이다. 모든 바이트 입력 스트림은 InputStream 클래스를 상속받아 만들어진다.

다음은 InputStream 클래스의 주요 메소드이다.

리턴 타입메소드설명
intread()1byte를 읽은 후 읽은 바이트를 리턴
intread(byte[] b)읽은 바이트를 매개값으로 주어진 배열에 저장 후 읽은 바이트 수를 리턴
voidclose()입력 스트림을 닫고 사용 메모리 해제

1 바이트 읽기

read() 메소드는 입력 스트림으로부터 1byte를 읽고 int(4byte) 타입으로 리턴한다.
더 이상 입력 스트림으로부터 바이트를 읽을 수 없다면 read() 메소드는 -1을 리턴하는데, 이것을 이용하면 읽을 수 있는 마지막 바이트까지 반복해서 한 바이트씩 읽을 수 있다.

InputStream is = ...;
while(true) {
	int data = is.read();
    if (date == -1) break;
}

FileInputStream 생성자는 주어진 파일이 존재하지 않을 경우 FileNotFoundException 을 발생시킨다. 그리고 read(), close() 메소드에서 IOException 이 발생할 수 있으므로 두 가지 예외를 모두 처리해야 한다.

바이트 배열로 읽기

read(byte[] b) 메소드는 입력 스트림으로부터 주어진 배열의 길이만큼 바이트를 읽고 배열에 저장한 다음 읽은 바이트 수를 리턴한다.

read(byte[] b) 역시 입력 스트림으로부터 바이트를 더 이상 읽을 수 없다면 -1을 리턴하는데, 이 것을 이용하면 읽을 수 있는 마지막 바이트까지 반복해서 읽을 수 있다.

InputStream is = ...;
byte[] data = new byte[100];
while (true) {
	int num = is.read(data);
    if(num == -1) break;
}

스트림을 이용하여 파일 복사를 할 수 있다.
파일 복사의 원리는 FileInputStream 에서 읽은 바이트를 바로 FileOutputStream 으로 출력하는 것이다.

Java9 부터는 좀 더 편리하게 입력 스트림에서 출력 스트림으로 바이트를 복사하는 transferTo() 메소드가 InputStream에 추가되었다.

is.transferTo(os);

문자 입출력 스트림

바이트 입출력 스트림인 InputStream과 OutputStream에 대응하는 문자 입출력 스트림으로 Reader와 Writer 가 있다.
입출력되는 단위가 문자인 것을 제외하고는 바이트 입출력 스트림과 사용 방법은 동일하다.

문자 출력

Writer는 문자 출력 스트림의 최상위 클래스로, 추상 클래스이다.
모든 문자 출력 스트림 클래스는 Writer 클래스를 상속받아서 만들어진다.

Writer 클래스의 주요 메소드는 다음과 같다.

리턴 타입메소드설명
voidwrite(int c)매개값으로 주어진 한 문자를 출력
voidwrite(char[] cbuf)매개값으로 주어진 배열의 모든 문자를 출력
voidwrtie(char[] cbuf, int off, int len)매개값으로 주어진 배열에서 cbuf[off] 부터 len개 까지의 문자를 출력
voidwrite(String str)매개값으로 주어진 문자열을 출력
voidwrite(String str, int off, int len)매개값으로 주어진 문자열에서 off 순번부터 len개까지의 문자를 출력
voidflush()버퍼에 잔류하는 모든 문자를 출력
voidclose()출력 스트림을 닫고 사용 메모리를 해제

Writer는 OutputStream과 사용 방법은 동일하지만, 출력 단위가 문자(char)이다.
그리고 문자열을 출력하는 메소드를 추가로 제공한다.

문자 읽기

Reader 는 문자 입력 스트림의 최상위 클래스로, 추상 클래스이다.
모든 문자 입력 스트림 클래스는 Reader 클래스를 상속받아서 만들어진다.

Reader 클래스의 주요 메소드는 다음과 같다.

리턴 타입메소드설명
intread()1개의 문자를 읽고 리턴
intread(char[] cbuf)읽은 문자들을 매개값으로 주어진 배열에 저장 후 읽은 문자 수를 리턴
voidclose()입력 스트림을 닫고 사용 메모리 해제

Reader는 InputStream과 사용 방법은 동일하지만, 출력 단위가 문자(char)이다.

보조 스트림

보조 스트림이란 다른 스트림과 연결되어 여러 가지 편리한 기능을 제공해주는 스트림을 말한다.
보조 스트림은 자체적으로 입출력을 수행할 수 없기 때문에 입출력 소스로부터 직접 생성된 입출력 스트림에 연결해서 사용해야 한다.

입출력 스트림에 보조 스트림을 연결하려면 보조 스트림을 생성할 때 생성자 매개값으로 입출력 스트림을 제공하면 된다.

보조스트림 변수 = new 보조스트림(입출력스트림);
InputStream is = new FileInputStream("...");
InputStreamReader reader = new InputStreamReader(is);

보조 스트림은 또 다른 보조 스트림과 연결되어 스트림 체인으로 구성할 수 있다.

InputStream is = new FileInputStream("...");
InputStreamReader reader = new InputStreamReader(is);
BufferedReader br = new BufferedReader(reader);
보조 스트림기능
InputStreamReader바이트 스트림을 문자 스트림으로 변환
BufferedInputStream, BufferedOutputStream, BufferedReader, BufferedWriter입출력 성능 향상
DataInputStream, DataOutputStream기본 타입 데이터 입출력
PrintStream, PrintWriter줄바꿈 처리 및 형식화된 문자열 출력
ObjectInputStream, ObjectOutputStream객체 입출력

문자 변환 스트림

바이트 스트림에서 입출력할 데이터가 문자라면 문자 스트림으로 변환해서 사용하는 것이 좋다.

InputStream 을 Reader로 변환

InputStreamReader 사용

InputStream is = new FileInputStream("C:/Temp/test.txt");
Reader reader = new InputStreamReader(is);

FileReader의 원리
FileInputStream 에 InputStreamReader 를 연결하지 않고 FileReader를 직접 생성할 수 있다.
FileReader 는 InputStreamReader의 자식 클래스이다. 이것은 FileReader가 내부적으로 FileInputStream에 InputStreamReader 보조 스트림을 연결한 것이라고 볼 수 있다.

OutputStream 을 Writer로 변환

OutputStreamWriter 사용

OutputStream os = new FileOutputStream("C:/Temp/test.txt");
Writer writer = new OutputStreamWriter(os);

FileWriter의 원리
FileOutputStream 에 OutputStreamWriter를 연결하지 않고 FileWriter를 직접 생성할 수 있다.
FileWriter 는 OutputStreamWriter의 자식 클래스이다. 이것은 FileWriter가 내부적으로 FileOutputStream에 OutputStreamWriter 보조 스트림을 연결한 것이라고 볼 수 있다.

성능 향상 스트림

CPU와 메모리가 아무리 뛰어나도 하드 디스크의 입출력이 늦어지면 프로그램의 실행 성능은 하드디스크의 처리 속도에 맞춰진다.
이는 중간에 메모리 버퍼와 작업함으로써 실행 성능을 향상시킬 수 있다.

출력 스트림의 경우 직접 하드 디스크에 데이터를 보내지 않고 메모리 버퍼에 데이터를 보냄으로써 출력 속도를 향상시킬 수 있다.
버퍼는 데이터가 쌓이기를 기다렸다가 꽉 차게 되면 데이터를 한꺼번에 하드 디스크로 보냄으로써 출력 횟수를 줄여준다.

입력 스트림에서도 버퍼를 사용하면 읽기 성능이 좋아진다. 하드 디스크로부터 직접 읽는 것보다는 메모리 버퍼로부터 읽는 것이 빠르다.

이렇게 성능을 향상시키는 보조 스트림으로 BufferedInputStream, BufferedOutputStream, BufferedReader, BufferedWriter 가 있다.

BufferedInputStream bis = new BufferedInputStream(바이트 입력 스트림);
BufferedOutputStream bos = new BufferedOutputStream(바이트 출력 스트림);
BufferedReader br = new BufferedReader(문자 입력 스트림);
BufferedWriter bw = new BufferedWriter(문자 출력 스트림);

BufferedReader는 이 외에 행 단위로 문자열을 읽는 매우 편리한 readLine() 메소드를 제공한다.

BufferedReader br = new BufferedReader(new FileReader("..."));
while(true) {
	String str = br.readLine();
    if(str == null) break;
}

기본 타입 스트림

바이트 스트림에 DataInputStream과 DataOutputStream 보조 스트림을 연결하면 기본 타입인 boolean, char, short, int, lont, float. double 값을 입출력할 수 있다.

DataInputStream dis = new DataInputStream(바이트 입력 스트림);
DataOutputStream dos = new DataOutputStream(바이트 출력 스트림);
DataInputStreamDataOutputStream
booleanreadBoolean()voidwriteBoolean(boolean v)
bytereadByte()voidwriteByte(int v)
charreadChar()voidwriteChar(int v)
doublereadDouble()voidwriteDouble(double v)
floatreadFloat()voidwriteFloat(float v)
intreadInt()voidwriteInt(int v)
longreadLong()voidwriteLong(long v)
shortreadShort()voidwriteShort(int v)
StringreadUTF()voidwriteUTF(String str)

데이터 타입의 크기가 모두 다르므로 DataOutputStream으로 출력한 데이터를 다시 DataInputStream 으로 읽어 올 때에는 출력한 순서와 동일한 순서로 읽어야 한다.

프린트 스트림

PrintStream과 PrintWriter는 프린터와 유사하게 출력하는 print(), println(), printf() 메소드를 가지고 있는 보조 스트림이다.

System.out.println()에서 out 도 PrintStream 타입니다.

PrintStream 은 바이트 출력 스트림과 연결되고, PrintWriter는 문자 출력 스트림과 연결된다.

리턴타입메소드(매개변수)리턴타입메소드(매개변수)
voidprint(boolean v)voidprintln(boolean v)
voidprint(char v)voidprintln(char v)
voidprint(double v)voidprintln(double v)
voidprint(float v)voidprintln(float v)
voidprint(int v)voidprintln(int v)
voidprint(long v)voidprintln(long v)
voidprint(Object v)voidprintln(Object v)
voidprint(String v)voidprintln(String v)
voidprintln()

객체 스트림

자바는 메모리에 생성된 객체를 파일 또는 네트워크로 출력할 수 있다.
객체를 출력하려면 필드값을 일렬로 늘어선 바이트로 변경해야 하는데, 이것을 직렬화라고 한다.
반대로 직렬화된 바이트를 객체의 필드값으로 복원하는 것을 역직렬화라고 한다.

ObjectOutputStream 은 바이트 출력 스트림과 연결되어 객체를 직렬화하고, ObjectInputStream은 바이트 입력 스트림과 연결되어 객체로 복원하는 역직렬화를 한다.

ObjectInputStream ois = new ObjectInputStream(바이트 입력 스트림);
ObjectOutputStream oos = new ObjectOutputStream(바이트 출력 스트림);

객체를 직렬화하기 위해서는 writeObject() 메소드를 사용

oos.writeObject(객체);

객체를 역직렬화하기 위해서는 readObject() 메소드를 사용. 이때 리턴 타입은 Object 이므로 구체적인 타입으로 강제 타입 변환해야 한다.

객체타입 변수 = (객체타압) ois.readObject();

Serializable 인터페이스

자바는 Serializable 인터페이스를 구현한 클래스만 직렬화할 수 있도록 제한한다.
Serializable 인터페이스는 멤버가 없는 빈 인터페이스이지만, 객체를 직렬화할 수 있다고 표시하는 역할을 한다.

객체가 직렬화될 때 인스턴스 필드값은 직렬화 대상이지만 정적 필드값과 transient로 선언된 필드값은 직렬화에서 제외되므로 출력되지 않는다.

public class XXX implements Serializable {
	public int field1;
    protected int field2;
    int field3;
    private int field4;
    public static int field5;
    transient int field6;
}

serialVersionUID 필드

직렬화할 때 사용된 클래스와 역직렬화할 때 사용된 클래스는 기본적으로 동일한 클래스여야 한다.
만약 클래스의 이름이 같더라도 클래스의 내용이 다르면 역직렬화에 실패한다.

클래스의 내용이 다르다 할지라도 직렬화된 필드를 공통으로 포함하고 있으면 역직렬화할 수 있는 방법이 있다.
두 클래스가 동일한 serialVersionUID 상수값을 가지고 있으면 된다.

File과 Files 클래스

java.io 패키지와 java.nio.file 패키지는 파일과 디렉토리 정보를 가지고 있는 File과 Files 클래스를 제공한다. Files는 File을 개선한 클래스로, 좀 더 많은 기능을 가지고 있다.

File 클래스

File file = new File("경로");

File 객체를 생성했다고 해서 파일이나 디렉토리가 생성되는 것은 아니다. 그리고 경로에 실제 파일이나 디렉터리가 없더라도 예외가 발생하지 않는다.

파일이나 디렉토리가 실제 있는지 확인하고 싶다면 exist() 메소드를 호출하면 된다.

boolean isExist = file.exist();

exist() 메소드가 false를 리턴할 경우, 다음 메소드로 파일 또는 폴더를 생성할 수 있다.

리턴 타입메소드설명
booleancreateNewFile()새로운 파일을 생성
booleanmkdir()새로운 디렉토리 생성
booleanmkdirs()경로상에 없는 모든 디렉토리 생성

exist() 메소드가 true를 리턴할 경우 다음 메소드를 사용할 수 있다.
|리턴 타입|메소드|설명|
|---|---|---|
|boolean|delete()|파일 또는 디렉토리 삭제|
|boolean|canExecute()|실행할 수 있는지 여부|
|boolean|canRead()|읽을 수 있는지 여부|
|boolean|CanWrite()|수정 및 저장할 수 있는 파일인지 여부|
|String|getName()|파일의 이름을 리턴|
|String|getParent()|부모 디렉토리를 리턴|
|File|getParentFile()|부모 디렉토리를 File 객체로 생성 후 리턴|
|String|getPath()|전체 경로를 리턴|
|boolean|isDirectory()|디렉토리인지 여부|
|boolean|isFile()|파일인지 여부|
|boolean|isHidden()|숨김 파일인지 여부|
|long|lastModified()|마지막 수정 날짜 및 시간을 리턴|
|long|length()|파일의 크기 리턴|
|String[]|list()|디렉토리에 포함된 파일이나 서브 디렉터리 목록 전부를 String 배열로 러턴|
|String[]|list(FilenameFilter filter)|디렉토리에 포함된 파일이나 서브 디렉터리 목록 중에 FilenameFilter 에 맞는 것만 String 배열로 리턴|
|File[]|listFiles()|디렉토리에 포함된 파일이나 서브 디렉터리 목록 전부를 File 배열로 리턴|
|File[]|listFiles(FilenameFilter filter)|디렉토리에 포함된 파일이나 서브 디렉터리 목록 중에 FilenameFilter 에 맞는 것만 File 배열로 리턴|

Files 클래스

Fils 클래스는 정적 메소드로 구성되어 있기 때문에 File 클래스처럼 객체로 만들 필요가 없다.
Files 의 정적 메소드는 운영체제의 파일 시스템에게 파일 작업을 수행하도록 위임한다.

기능관련 메소드
복사copy
생성createDirectories, createDirectory, createFile, createLink, createSymbolickLink, createTempDirectory, createTempFile
이동move
삭제delete, deleteIfExists
존재, 검색, 비교exists, notExists, find, mismatch
속성getLastModifiedTime, getOwner, getPosixFilePermissions, isDirectory, isExecutable, isHidden, idReadable, isSymbolicLink, isWritable, size, setAttribute, setLastModifiedTime, setOwner, setPosixFilePermissions, probeContentType
디렉토리 탐색list, newDirectoryStream, walk
데이터 입출력newInputStream, newOutputStream, newBufferedReader, newBufferedWriter, readAllBytes, lines, readAllLines, readString, readSymbolicLink, write, writeString

이 메소드들은 매개값으로 Path 객체를 받는다. Path 객체는 파일이나 디렉토리를 찾기 위한 경올 정보를 가지는데, 정적 메소드인 get() 메소드로 다음과 같이 얻을 수 있다.

Path path = Paths.get(String fisrt, String ... more)

get() 메소드의 매개값은 파일 경로인데, 전체 경로를 한꺼번에 저정해도 좋고 상위 디렉토리와 하위 디렉토리를 나열해서 지정해도 좋다.

절대경로, 상대경로 모두 사용 가능하다.

문제

  1. 입출력 스트림에 대한 설명 중 틀린 것은 무엇입니까?
    ➊ 하나의 스트림으로 입력과 출력이 동시에 가능하다.
    ➋ 프로그램을 기준으로 데이터가 들어오면 입력 스트림이다.
    ➌ 프로그램을 기준으로 데이터가 나가면 출력 스트림이다.
    ➍ 콘솔에 출력하거나 파일에 저장하려면 출력 스트림을 사용해야 한다.
  • 답 : ➊
  1. InputStream과 Reader에 대한 설명으로 틀린 것은 무엇입니까?
    ➊ 이미지 데이터는 InputStream 또는 Reader로 모두 읽을 수 있다.
    ➋ Reader의 read() 메소드는 1문자를 읽는다.
    ➌ InputStream의 read() 메소드는 1바이트를 읽는다.
    ➍ InputStreamReader를 이용하면 InputStream을 Reader로 변환시킬 수 있다.
  • 답 : ➊
  1. InputStream의 read(byte[ ] b) 메소드에 대한 설명으로 틀린 것은 무엇입니까?
    ➊ 메소드의 리턴값은 읽은 바이트 수이다.
    ➋ 매개값 b에는 읽은 데이터가 저장된다.
    ➌ 읽을 수 있는 바이트 수는 제한이 없다.
    ➍ 매개값 b에는 이전에 읽은 바이트가 남아 있을 수 있다.
  • 답 : ➌
  1. 출력 스트림에서 데이터를 출력 후 flush() 메소드를 호출하는 이유는 무엇입니까?
    ➊ 출력 스트림의 버퍼에 있는 데이터를 모두 출력시키고 버퍼를 비운다.
    ➋ 출력 스트림을 메모리에서 제거한다.
    ➌ 출력 스트림의 버퍼에 있는 데이터를 모두 삭제한다.
    ➍ 출력 스트림을 닫는 역할을 한다.
  • 답 : ➊
  1. 보조 스트림에 대한 설명으로 틀린 것은 무엇입니까?
    ➊ InputStreamReader는 InputStream을 Reader로 변환시키는 보조 스트림이다.
    ➋ BufferedInputStream은 데이터 읽기 성능을 향상시키는 보조 스트림이다.
    ➌ DataInputStream은 객체를 입출력하는 보조 스트림이다.
    ➍ PrintStream은 print(), println() 메소드를 제공하는 보조 스트림이다.
  • 답 : ➌
  1. ObjectInputStream, ObjectOutputStream에 대한 설명으로 틀린 것은 무엇입니까?
    ➊ 객체를 직렬화해서 출력하고 역직렬화해서 복원시킨다.
    ➋ Serializable 인터페이스를 구현한 객체만 입출력할 수 있다.
    ➌ 클래스의 serialVersionUID는 입출력할 때 달라도 상관없다.
    ➍ transient 필드는 출력에서 제외된다.
  • 답 : ➌
  1. 소스 파일을 읽고 실행 결과와 같이 행의 라인 번호를 추가시켜 출력하도록 밑줄과 빈 곳에 코드
    를 작성해보세요.
//실행 결과
 1: package ch02.sec01;
 2:
 3: public class VariableUseExample {
 4: 	public static void main(String[] args) { 
 5: 		int hour = 3;10: 		System.out.println("총" + totalMinute + "분");
11: 	}
12: }
  • 답 :
new FileReader(filePath);
new BufferedReader(fr);
rowData= br.readLine();
if(rowData = = null) {
	break;
}
System.out.println(++rowNumber + ": " + rowData);
  1. PrintStream에 대한 설명으로 틀린 것은 무엇입니까?
    ➊ out 필드는 콘솔로 출력하는 PrintStream 타입이다.
    ➋ print(), println(), printf() 메소드를 제공한다.
    ➌ println() 메소드는 매개값의 타입에 따라 오버로딩되어 있다.
    ➍ PrintStream은 문자 기반 출력 스트림에 연결된다.
  • 답 : ➍
  1. File과 Files 클래스에 대한 설명으로 틀린 것은 무엇입니까?
    ➊ File 객체는 파일이 실제로 존재하지 않아도 생성할 수 있다.
    ➋ File 객체는 파일 정보만 제공하고, 디렉토리 정보는 제공하지 않는다.
    ➌ Files 클래스는 정적 메소드로 구성되어 있기 때문에 객체를 만들 필요가 없다.
    ➍ File 객체는 파일의 크기를 제공하는 length() 메소드를 제공한다.
  • 답 : ➋
  1. 실행하면 다음과 같이 원본 파일 경로와 복사 파일 경로를 입력받고 원본 파일을 복사하는 프로
    그램을 만들어보세요. (바이트 기반 스트림과 성능 향상 보조 스트림을 반드시 사용)
  • 답 :
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Scanner;

public class Example {
	public static void main(String[] args) {
 		try {
 			Scanner scanner = new Scanner(System.in);

 			System.out.print("원본 파일 경로: ");
 			String originalFilePath = scanner.nextLine();

 			System.out.print("복사 파일 경로: ");
 			String targetFilePath = scanner.nextLine();정답

 			File originalFile = new File(originalFilePath);
 			if(!originalFile.exists()) {
 				System.out.println("원본 파일이 존재하지 않습니다.");
 				System.exit(0);
 			}

 			File targetFile = new File(targetFilePath);
 			File parentFile = targetFile.getParentFile();
 			if(!parentFile.exists()) {
 				parentFile.mkdirs();
 			}

 			BufferedInputStream bis = new BufferedInputStream(
			new FileInputStream(originalFilePath));
 			BufferedOutputStream bos = new BufferedOutputStream(
 			new FileOutputStream(targetFilePath));

 			byte[] data = new byte[1024];
 			int num = -1;
 			while(true) {
 				num = bis.read(data);
 				if(num = = -1) break;
 					bos.write(data, 0, num);
 				}
 				System.out.println("복사가 성공되었습니다.");
 				bis.close();
 				bos.close();
 		} catch(Exception e) {
 			e.printStackTrace();
 		}
	}
}
profile
사는게 쉽지가 않네요

0개의 댓글