Post

입출력

입출력이란

컴퓨터 내부 또는 외부의 장치와 프로그램간의 데이터를 주고받는 것을 말한다.

자바에서 입출력은 스트림을 통해 수행한다.

스트림은 데이터를 운반하는데 사용되는 연결통로를 뜻한다.

스트림은 단방향통신만 가능하기 때문에 입력과 출력을 동시에 수행하려면 입력 스트림과 출력 스트림이 필요하다.

바이트기반 스트림

바이트단위로 데이터를 전송하여 단위가 1 byte인 스트림

입력스트림출력스트림입출력 대상의 종류
FileInputStreamFileOutputStream파일
ByteArrayInputStreamByteArrayOutputStream메모리 (byte 배열)
PipedInputStreamPipedOutputStream쓰레드 간에 데이터를 주고받을 때 사용
AudioInputStreamAudioOutputStream오디오장치

보조 스트림

실제 데이터를 주고받는 스트림이 아니지만 스트림의 기능을 향상시키거나 새로운 기능을 추가할 수 있도록 하는 스트림이다.

예를 들어 test.txt 파일을 읽기위해 FileInputStream을 사용할 때 입력 성능을 향상시키기 위해 버퍼를 사용하는 보조스트림 BufferedInputStream을 사용하는 것

입력스트림출력스트림설명
FilterInputStreamFilterOutputStream필터를 이용한 입출력 처리. 모든 보조 스트림의 조상이다.
BufferedInputStreamBufferedOutputStream버퍼를 이용한 입출력 성능 향상
DataInputStreamDataOutputStreamint, float과 같은 기본형으로 데이터를 처리하는 기능 제공
SequenceInputStream 두 개의 스트림을 하나로 연결
LineNumberInputStream 읽어 온 데이터의 라인 번호를 카운트
ObjectInputStreamObjectOutputStream데이터를 객체단위로 읽고 쓰는데 사용 (직렬화)
 PrintStream버퍼를 이용하며, 추가적인 print관련 기능 제공
PushbackInputStream 버퍼를 이용해서 읽어 온 데이터를 다시 되돌리는 기능 제공

문자기반 스트림

java는 문자가 2 byte이기 때문에 바이트기반 스트림으로 문자를 처리하기 어려운 점을 보완한 스트림

입력스트림출력스트림
FileReaderFileWriter
CharArrayReaderCharArrayWriter
PipedReaderPipedWriter
StringReaderStringWriter

보조스트림

입력스트림출력스트림
FilterReaderFilterWriter
BufferedReaderBufferedWriter
LineNumberReader 
 PrintWriter
PushbackReader 
  • DataInputStream / DataOutputStream 사용 시 출력한 데이터의 타입과 읽어올 데이터의 타입을 맞춰줘야 한다.
  • InputStreamReader / OutputStreamWriter 는 바이트기반 스트림의 데이터에 인코딩을 지정하여 문자기반 스트림으로 변환하는 역할을 한다.

RandomAccessFile

하나의 클래스 파일에 대한 입력과 출력을 모두 할 수 있는 특수한 클래스

DataInputStream / DataOutputStream 과 같이 기본자료형 단위로 데이터를 읽고 쓴다.

순차 읽기/쓰기를 하는 다른 입출력 클래스와 달리 내부적으로 파일포인터를 이용해 파일의 어느 위치에나 읽기/쓰기가 가능하다.

1
2
3
4
5
6
7
8
// 생성자
RandomAccessFile(File file, String mode)
RandomAccessFile(String fileName, String mode)
// 파일포인터 위치 변경
void seek(long pos)
int skipBytes(int n)
// 파일포인터 위치 조회
long getFilePointer()

생성자 사용 시 mode의 값은 다음 항목을 지정할 수 있다.

r
읽기
rw
읽기/쓰기
rws
기본적으로 rw와 같지만 쓰기 시 바로 파일에 쓰이도록 한다. 또한, 파일의 메타정보를 포함한다.
rwd
기본적으로 rw와 같지만 쓰기 시 바로 파일에 쓰이도록 한다. 파일의 내용만 포함한다.

직렬화

객체를 연속적인(serial) 데이터로 변환하는 것

직렬화가 가능한 클래스

직렬화를 가능하게 하려면 Serializable 인터페이스를 구현해야 한다.

Serializable 인터페이스는 아무런 내용도 없는 빈 인터페이스지만 직렬화를 고려한 클래스인지를 판단하기 위해 사용한다.

또한, 부모 클래스가 Serializable 인터페이스를 구현했다면 자식은 기본적으로 직렬화가 가능하다.

만약 부모 클래스가 Serializable 인터페이스를 구현하지 않고 자식 클래스만 Serializable 인터페이스를 구현했다면 부모 클래스의 인스턴스 변수는 직렬화되지 않는다. (단, 자식 클래스에서 부모 클래스의 인스턴스 변수도 직렬화할 수 있도록 처리하는 코드를 구현하면 가능하다.)

직렬화 가능한 클래스의 인스턴스 변수 중 직렬화 대상에서 제외하고 싶은 인스턴스 변수가 있다면 trasient 키워드를 붙여주면 된다. transient 키워드가 붙은 인스턴스 변수의 경우 직렬화 시 타입의 기본값으로 직렬화된다.

serialVersionUID

클래스의 버전을 나타내는 값

객체가 직렬화될 때 클래스에 정의된 멤버들의 정보를 이용해서 serialVersionUID라는 클래스의 버전을 자동생성해서 직렬화 내용에 포함한다.

직렬화된 객체를 역직렬화 할 때는 직렬화 할 때와 같은 클래스를 사용해야 하며 클래스의 버전이 다르면 예외가 발생한다.

static 변수, 상수, transient 키워드가 붙은 인스턴스 변수를 추가하는 것은 클래스의 버전에 영향을 미치지 않는다.

이미 정의된 serialVersionUID가 존재한다면 클래스의 버전을 자동으로 생성하지 않는다.

자동으로 생성하는 serialVersionUID를 사용하면 클래스를 조금만 수정하여도 값이 변경되기 때문에 프로그램의 관리를 어렵게 한다. 그래서 수동으로 관리하는 것이 좋다.

serialVersionUID는 정수값이면 어떠한 값으로도 지정할 수 있지만 고유한 값을 가지기 위해 serialver.exe 프로그램을 이용해서 생성하는 것이 보편적이다.

This post is licensed under CC BY 4.0 by the author.