벌써 자바 기초 수업이 끝났다.
이제부터는 응용할 수 있도록 연습해야겠다.
- 입출력 (IO)
- File 클래스
- 스트림 클래스
- InputStream
- OutputStream
- Reader
- Writer
- 보조 스트림
- 직렬화와 역직렬화
Input 과 Output 의 약자로 컴퓨터 내부 또는 외부 장치와 프로그램 간의 데이터를 주고 받는 것이다.
장치와 입출력을 위해서는 하드웨어 장치에 직접 접근이 필요한데 다양한 매체에 존재하는 데이터들을 사용하기 위해 입출력 데이터를 처리할 공통적인 방법으로 스트림을 이용한다.
스트림은 데이터가 이동하는 통로라고 생각하면 된다. 양방향인 파이프 스트림을 제외하고 단방향으로만 흘러갈 수 있다.
파일 시스템의 파일을 표현하는 클래스이다. 파일 크기와 속성 및 이름 등의 정보와 파일 생성 및 삭제 기능을 제공한다. 본 수업에서는 다루지 않고 넘어갔다.
File file = new File("파일 경로");
File file = new File("C:/dev/test.txt");
입출력 장치에서 데이터를 읽고 쓰기 위한 클래스로 모든 스트림은 단방향이며 각각의 장치마다 연결할 수 있는 스트림이 존재한다. 하나의 스트림으로 입출력을 동시에 수행할 수 없으므로 동시에 수행하려면 두 개의 스트림이 필요하다.
숫자와 문자는 1 byte 씩 출력하고 한글은 2 byte 씩 출력한다.
스트림 클래스는 모두 다 외우지는 말고 필요할 때 사용하도록 한다.
다음은 스트림 클래스의 종류이다. 색이 있는 것은 기반 스트림이고 색이 없는 것은 보조 스트림이다.
얇은 빨대라고 생각하면 된다. 데이터를 잘라서 전송하기 때문에 데이터가 깨질 수 있다. 따라서 이미지나 영상 및 파일 등 문자가 아닌 데이터나 파일 또는 1 byte 문자로 이루어진 텍스트를 전송할 때 사용하는 것이 좋다.
두꺼운 빨대라고 생각하면 된다. 문자로 이루어진 텍스트나 채팅 및 코드를 전송할 때 사용하는 것이 좋다.
private String content = "Hello World\n" + "987654321\n" + "오늘은 금요일\n" + "!@#$%^&*():";
public void byteOutPut() { // 바이트 기반 출력
// 스트림 참조 변수 선언을 try 전에 한 이유 : finally 에서도 해당 참조 변수를 사용하기 위해
FileOutputStream fos = null;
try {
// 프로그램에서 지정된 경로로 파일 내보냄 (출력)
// 만약 경로 제일 마지막에 작성한 파일이 존재하지 않는다면 출력 구문 수행 시 자동으로 생성됨
// 파일이나 폴더가 없을 수 있으므로 FileNotFoundException 발생 가능성 존재
fos = new FileOutputStream("byte/byteTest.txt"); // 이어쓰기 하고 싶으면 true
// content에 작성된 문자를 하나씩 쪼개기
for (int i=0; i<content.length(); i++) {
char ch = content.charAt(i);
fos.write(ch); // 프로그램이 txt 파일에 작성 (출력)
}
System.out.println("출력 완료");
} catch (FileNotFoundException e) { // 파일 없는 경우
e.printStackTrace();
} catch (IOException e) { // 문제 있는 경우
e.printStackTrace();
} finally { // 예외 발생 여부와 관계없이 무조건 수행
try {
// close() : 스트림 내부 내용을 모두 밀어낸 후 객체가 있을 때만 닫음 (메모리 반환)
if(fos != null) fos.close(); // NullPointerException 방지
} catch (IOException e) {
e.printStackTrace();
}
}
}
절대 경로 : 절대적인 기준점을 기준으로 작성 c:\tools\eclipse\
상대 경로 : 현재 위치를 기준으로 작성 byte/byteTest.txt
바이트 기반 입력 스트림의 최상위 클래스로 추상 클래스이다.
파일을 바이트 단위로 읽을 때 사용한다. 그림 및 오디오와 비디오 및 텍스트 파일 등 모든 종류의 파일 읽기가 가능하다.
InputStream 의 하위 클래스로 InputStream 과 사용 방법이 동일하다.
FileInputStream 객체가 생성될 때 파일과 직접 연결됨
만약 파일 존재하지 않으면 FileNotFoundException 발생하므로 예외처리 필수
FileInputStream fis = new FileInputStream("C:/dev/text.txt");
바이트 기반 출력 스트림의 최상위 클래스로 추상 클래스이다.
파일을 바이트 단위로 저장할 때 사용한다. 그림 및 오디오와 비디오 및 텍스트 파일 등 모든 종류의 데이터를 파일로 저장할 수 있다.
FileOutputStream 객체가 생성될 때 파일과 직접 연결됨
만약 파일 존재하지 않으면 자동으로 생성하지만
이미 파일이 존재할 경우 파일을 덮어씀
// 파일 존재하지 않는 경우
FileOutputStream fos = new FileOutputStream("C:/dev/text.txt");
// 기존 파일에 이어서 작성하고 싶을 경우
FileOutputStream fos = new FileOutputStream("C:/dev/text.txt"), true;
문자 기반 입력 스트림의 최상위 클래스로 추상 클래스이다.
문자 단위로 텍스트 기반 파일을 읽을 때 사용한다.
텍스트가 아닌 그림 및 오디오와 비디오 등의 파일을 읽기가 불가능하다.
Reader 의 하위 클래스로 Reader 와 사용 방법이 동일하다.
FileReader 객체가 생성될 때 파일과 직접 연결됨
만약 파일 존재하지 않으면 FileNotFoundException 발생하므로 예외처리 필수
FileReader fr = new FileReader("C:/dev/text.txt");
FileReader fr = new FileReader(new File("C:/dev/text.txt"));
문자 기반 출력 스트림의 최상위 클래스로 추상 클래스이다.
문자 단위로 텍스트 기반 파일을 쓸 때 사용한다.
텍스트가 아닌 그림 및 오디오와 비디오 등의 파일은 저장이 불가능하다.
Writer 의 하위 클래스로 Writer 와 사용 방법이 동일하다.
FileWriter 객체가 생성될 때 파일과 직접 연결됨
만약 파일 존재하지 않으면 자동으로 생성하지만
이미 파일이 존재할 경우 파일을 덮어씀
// 파일 존재하지 않는 경우
FileWriter fw = new FileWriter("C:/dev/text.txt");
// 기존 파일에 이어서 작성하고 싶을 경우
FileWriter fw = new FileWriter("C:/dev/text.txt"), true;
스트림의 기능을 향상시키거나 새로운 기능을 추가하기 위해 사용한다.
보조 스트림은 실제 데이터를 주고 받는 스트림이 아니기 때문에 입출력 처리가 불가능하다. 기반 스트림을 먼저 생성한 후 이를 이용해 보조 스트림을 생성해야 한다.
문자 변환 보조 스트림과 성능 향상 보조 스트림 및 기본 타입 입출력 보조 스트림과 객체 입출력 보조 스트림이 있다.
// 기반 스트림 생성
FileInputStream fis = new FileInputStream("sample.txt");
// 보조 스트림 생성
BufferedInputStream bis = new BufferedInputStream(fis);
// 보조 스트림으로부터 데이터 읽어옴
bis.read();
보조 스트림 사용 시 기반 스트림과 기반이 맞아야 오류가 발생하지 않는다.
소스 스트림이 바이트 기반 스트림이지만 데이터가 문자일 경우에 사용한다. Reader 와 Writer 는 문자 단위로 입출력을 하므로 데이터가 문자인 경우 바이트 기반 스트림보다 편리하게 사용 가능하다.
InputStreamReader
OutputStreamWriter
느린 속도로 인해 입출력 성능에 영향을 미치는 입출력 소스를 이용하는 경우에 사용한다.
입출력 소스와 직접 작업하지 않고 데이터를 모아 한꺼번에 작업 하여 실행 성능을 향상시킨다. 즉 입출력 횟수를 줄일 수 있다.
BufferedInputStream
BufferedOutputStream
기본 자료형 별 데이터 읽고 쓰기가 가능하도록 기능을 제공한다.
단 입력된 자료형의 순서와 출력될 자료형의 순서는 일치해야 한다.
DataInputStream
DataOutputStream
객체를 파일 또는 네트워크로 입출력 할 수 있는 기능을 제공한다.
단 객체는 문자가 아니므로 바이트 기반 스트림으로 데이터를 변경해주는 직렬화가 필수이다.
ObjectInputStream
ObjectOutputStream
Serializable 인터페이스는 직렬화가 될 수 있는 객체가 상속 받는 인터페이스이다. ObjectOutputStream 이 객체를 내보낼 때 해당 인터페이스를 상속 받은 객체인 경우에만 직렬화를 진행한다. 컬렉션의 경우 모두 직렬화가 가능하도록 Serializable 인터페이스 구현이 되어있다. 단 컬렉션에 저장하는 객체가 직렬화가 가능하지 않다면 NotSerializableException 이 발생한다.
Serializable 를 상속했지만 구현할 메서드가 없다는 것은 그저 표시 용도의 인터페이스인 마커 인터페이스라는 의미이다.
직렬화 시 private 필드를 포함해 모든 필드를 바이트로 구현하지만 transient 키워드를 사용한 필드는 직렬화에서 제외한다.
직렬화 했을 때와 같은 클래스를 사용한다. 단 클래스 이름이 같더라도 클래스 내용이 변경된 경우 역직렬화를 할 수 없다.
직렬화한 클래스와 같은 클래스임을 알려주는 식별자 역할로 컴파일 시 JVM 이 자동으로 serialVersionUID 정적 필드를 추가해주기 때문에 별도 작성 하지 않아도 오류는 나지 않지만 자동 생성 시 역직렬화에서 예상치 못한 InvalidClassException 이 발생할 수 있어 명시를 권장한다.
private static final long serialVersionUID = -6423919775137290062L;