Java IO 는 크게 Byte 단위 입출력과 문자(Character) 단위 입출력 클래스로 나윕니다.
Byte 단위 입출력 클래스는 InputStream과 OutputStream 이라는 추상 클래스를 상속받아 만들어집니다.
문자단위 입출력 클래스는 Reader 와 Writer 라는 추상 클래스를 상속받아 만들어집니다.
다양한 Byte 형을 입력받고 출력하는 클래스
다양한 문자 단위의 한줄을 입력받고 출력하는 클래스
DataInputStream 생성자
public DataInputStream(InputStream in) {
super(in);
}
File로 부터 입력받고 쓰기 위한 클래스
배열로 부터 입력받고 쓰기 위한 클래스
IO 패키지는 데코레이터 패턴이 적용되어 있다.
데코레이터 패턴 : 하나의 클래스를 장식 하는 것 처럼
생성자에서 감싸서 새로운 기능을 계속 추가 할 수 있도록 클래스를 만드는 방식
Byte 단위 입출력 실습
package javaIO.exam
public class ByteExam1 {
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
// 생성자의 파라미터로 읽어들일 파일의 경로를 넣어준다.
fis = new FileInputStream("src/javaIO/exam/ByteExam1.java");
// 생성자의 파라미터로 작성하고자 하는 파일의 경로를 넣어준다.
// 상대 경로 : 프로젝트 하위에 생성이 됩니다.
fos = new FileOutputStream("byte.txt");
int readData = -1;
// .read() 메서드는 정수 4바이트 중 마지막 바이트에 읽어들인 1바이트를 저장한다.
// .read() 메서드는 더이상 읽어들일 것이 없을때 -1 을 리턴한다.
while((readData = fis.read()) != -1){
fos.write(readData);
}
} catch (Exception e) {
// FileNotFoundException 을 throw 하므로 해당 예외를 처리해주는 부분
e.printStackTrance();
} finally {
// finally 부분에서 이전에 생성해둔 객체를 더이상 사용할 필요가 없으므로
// .close() 메서드를 이용하여 해당 객체가 보유하고 있는 리소스를 반환하도록 해준다.
try {
fos.close();
} catch (IOException e) {
e.printStackTrance();
}
try {
fis.close();
} catch (IOException e) {
e.printStackTrance();
}
}
}
}
위에서 작성한 Byte 단위 입출력 코드를 512 Byte씩 읽어들여 파일에 512 Byte씩 작성한느 프로그램 을 작성해보도록 하겠습니다.
512 Byte 만큼 읽어들이기 위해 byte 배열을 사용합니다.
byte[] buffer = new byte[512];
package javaIO.exam
public class ByteExam2 {
public static void main(String[] args) {
// 메서드가 시작된 시간을 구하기 위함
long startTime = System.currentTimeMillis();
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream("src/javaIO/exam/ByteExam2.java");
fos = new FileOutputStream("byte.txt");
int readCount = -1;
byte[] buffer = new byte[512]; // 512 byte 씩 읽어들이기 위해 byte 배열을 사용함.
// read() 메서드에 byte 배열을 파라미터로 넣어줍니다. - 최대 512 byte 를 읽어들입니다.
// 읽어온 byte 를 파라미터 byte 배열인 buffer 에 저장하고, 읽어온 개수를 정수로 리턴합니다.
// 더 이상 읽어들일 내용이 없다면 -1 을 반환합니다.
while((readCount = fis.read(buffer)) != -1){
// buffer 에서 buffer[0] 부터 readCount 길이 만큼의 byte 를 읽어들여 fos 에 작성한다.
fos.write(buffer, 0, readCount);
}
} catch (Exception e) {
e.printStackTrance();
} finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrance();
}
try {
fis.close();
} catch (IOException e) {
e.printStackTrance();
}
}
//메소드가 끝났을때 시간을 구하기 위함.
long endTime = System.currentTimeMillis();
//메소드를 수행하는데 걸린 시간을 구할 수 있음. - 이전 방법보다 수행시간이 감소한 것을 확인
System.out.println(endTime-startTime);
}
}
try-with-resources 블럭
- java 7버전에 도입된 문법입니다.
- Closeable 을 구현한 객체의 인스턴스를 생성하여 사용할 경우, 개발자가 직접 finally 문에서 close()를 사용하여 할당된 자원을 해제 시켜줘야 했습니다.
- 만약 개발자가 사용한 자원을 해제시켜주지 않았다면 자원이 해제되지 않은 채로 프로그램이 오작동하게 되고, finally 문에서 자원을 해제 시켜주더라도 자원 해제를 위한 중복 코드가 발생하기 때문에 소스 코드의 가독성을 해치는 단점이 있었습니다.
- 이를 해결하기 위해 try() 안에 사용할 리소스 객체를 명시적으로 선언하면, try 블록 내부 로직의 정상 완료 여부와 관계 없이 JVM에서 자동으로 자원을 반납해주는 기능을 하도록 도입하였습니다.
try ( // IO 객체 선언 ) { // IO 객체 사용 } catch(Exception e){ e.printStackTrace(); }
package javaIO.exam;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
public class ByteExam3 {
public static void main(String[] args) {
try(
DataOutputStream out = new DataOutputStream(new FileOutputStream("data.txt"));
){
// 다양한 타입의
out.writeInt(100);
out.writeBoolean(true);
out.writeDouble(50.5);
}catch (Exception e) {
e.printStackTrace();
}
}
}
다양한 타입의 값을 읽어들일 수 있는 DataInputStream
package javaIO.exam;
import java.io.DataInputStream;
import java.io.FileInputStream;
public class ByteIOExam4 {
public static void main(String[] args) {
try(
DataInputStream out = new DataInputStream(new FileInputStream("data.txt"));
){
int i = out.readInt();
boolean b = out.readBoolean();
double d = out.readDouble();
System.out.println(i);
System.out.println(b);
System.out.println(d);
}catch(Exception ex){
ex.printStackTrace();
}
}
}
Char 단위 입출력 클래스는 클래스의 이름이 Reader 나 Writer 로 끝납니다.
Char 단위 입출력 클래스를 이용해서 키보드로 부터 한줄 을 입력 받아서 콘솔에 출력하는 프로그램을 작성해보도록 하겠습니다.
System.in - 키보드로 입력받기 위해 사용
BufferedReader - 한줄씩 입력 받기위한 클래스
package javaIO.exam;
import java.io.BufferedReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
public class CharIOExam01 {
public static void main(String[] args) {
// BufferedReader 클래스의 생성자는 InputStream을 입력받는 생성자가 없다.
// System.in은 InputStream 타입이므로 BufferedReader의 생성자에 바로 들어갈 수 없으므로
// InputStreamReader 클래스를 이용해야함.
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// 키보드로 입력받은 문자열을 저장하기 위해 line변수를 선언
String line = null;
try {
line = br.readLine()
} catch (IOException e) {
e.printStackTrace();
}
// 콘솔에 출력
System.out.println(line);
}
}
package javaIO.exam
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class CharIOExam02 {
public static void main(String[] args) {
BufferedReader br = null;
PrintWriter pw = null;
try{
br = new BufferedReader(new FileReader("src/javaIO/exam/CharIOExam02.java"));
// 생성자 파라미터로 Writer 클래스를 입력하여 PrintWriter 인스턴스를 생성한다.
pw = new PrintWriter(new FileWriter("test.txt"));
String line = null;
while((line = br.readLine())!= null){
pw.println(line);
}
}catch(Exception e){
e.printStackTrace();
}finally {
// 꼭 Closeable 객체는 close() 메서드를 이용하여 할당된 자원을 해제시켜준다.
pw.close();
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}