[JAVA] ByteStream : InputStream / OutputStream

2019. 8. 6. 18:21 JAVA/Java IO

ByteStream : InputStream / OutputStream




초기의 자바는 바이트 단위로 입출력을 지원하였다. 이것은 가장 원시적인 형태의 입출력이며 아무런 변환 작업을 수행하지 않는다. 그러므로 바이너리 형태의 자원을 다루기 적합하며 InputStream과 OutputStream의 두 클래스가 최상위 클래스이다.


InputStream과 OutputStream 클래스는 둘 다 abstract 지정자를 가지고 있는 추상 클래스이다. 따라서 InputStream과 OutputStream은 객체를 직접 만들지 못하는 클래스로 대부분 추상 메소드를 정의하여 모든 후손 클래스가 이를 강제로 구현하게 만드는 통일의 의미로 사용된다.


1. InputStream 클래스


InputStream 클래스는 바이트 단위 입력 스트림의 최상위 클래스이다. 따라서 이 클래스에 존재하는 모든 메소드는 후손들에게 상속되므로 후손 객체를 통하여 원하는 메소드를 호출할 수 있다.


* InputStream에 정의된 메소드


InputStream에 정의된 메소드 

설명 

int available() throws IOException

- 현재 읽을 수 있는 바이트 수를 얻는다.

void close() throws IOException 

- InputStream을 닫는다

void mark(int readlimit)

- InputStream에서 현재 위치를 표시한다.

boolean markSupported() 

- 해당 InputStream에서 mark()로 지정된 지점이 있는지 여부를 체크한다.

abstract int read() throws IOException

- InputStream에서 한 바이트를 읽어서 int 값으로 반환한다. 

int read(byte[] b) throws IOException

- byte[] b 만큼의 데이터를 읽어서 b에 저장하고읽은 바이트 수를 반환한다

int read(byte[] b, int off, int len)

thrwos IOException 

- len 만큼을 읽어 byte[] b의 off위치에 저장하고 읽은 바이트 수를 반환한다

void reset() 

- mark() 를 마지막으로 호출한 위치로 이동한다.

long skip(long n) throws IOException

- InputStream에서 n 바이트 만큼 데이터를 스킴하고 바이트 수를 반환한다.


InputStream의 하위 클래스들은 위의 메소드를 사용할 수 있다.


InputStream 클래스에서 중요한 메소드는 입력을 위한 read() 메소드가 있다. read() 메소드는 입력 스트림에서 하나의 바이트를 읽어 들이기 위한 메소드인데 EoF(End of File)을 만나면 -1 을 반환하여 읽기 작업이 끝났다는 것을 알 수 있다.


read() 메소드가 한 바이트만 읽어들인다면 read(byte[] b) 메소드는 사용자가 지정한 byte[] 을 이용하여 한꺼번에 원하는 양을 읽어들일 수 있다.


일반적으로 available() 메소드를 사용하여 스트림에서 읽을 수 있는 바이트 수를 얻은 후 이를 기준으로 byte[]를 생성하여 한꺼번에 읽을 수 있다.


- read() 메소드의 리턴형이 byte가 아니라 int이다. 파일의 끝을 나타내는 EoF는 윈도우에서는 "Ctrl-Z"를 사용하고 리눅스나 유닉스에서는 "Ctrl-D"를 사용하는데 이 값을 -1 로 표현하였다. 자바는 숫자 체계는 바이트를 기준으로 -128에서 127까지 표현할 수 있다. 하지만 read() 메소드를 통해서 읽는 값은 양수를 기준으로 표현하는데 이 경우에는 0에서 127까지 밖에 사용할 수 없다. 이를 해결하기 위한 방법으로 더 큰 자료형을 리턴하도록 사용하여 0에서 255까지 사용할 수 있게 하고 -1을 특수한 입력 값으로 처리하도록 구성하기 위하여 정수형(int)를 사용하는 것이다.


JAVA API DOC : InputStream



2. OutputStream 클래스


OutputStream 클래스는 바이트 단위의 출력을 대표하는 최상위 클래스이다.

InputStream 클래스와 마찬가지로 이 클래스에 정의되어 있는 메소드는 후손 클래스가 상속받아서 그대로 사용하거나 재정의하여 사용한다.


* OutputStream에 정의된 메소드


 OutputStream에 정의된 메소드

설명 

void close() throws IOException 

- OutputStream을 닫는다 

void flush() throws IOException

- 버퍼에 남은 출력 스트림을 출력한다.

abstract void write(int i) 

throws IOException 

- 정수 i의 하위 8비트를 출력한다. 

void write(byte buf[]) throws IOException

- buf의 내용을 출력한다. 

void write(byte buf[], int index, int size) throws IOException 

- buf의 index 위치부터 size만큼의 바이트를 출력한다. 


가장 중요한 메소드는 write(int i) 메소드로 한 바이트를 출력하는 메소드인데 이 메소드의 인자도 바이트가 아닌 정수형을 사용하고 있다.


write() 메소드의 형태는 3가지가 있는데 인자로 byte[]를 사용하는 것과 배열과 함께 시작 위치 및 크기를 지정하는 메소드가 있다. 이 메소드를 사용하면 출력하고자 하는 배열의 지정된 위치에서 정해진 크기만큼 출력이 가능하다.

입력과 달리 출력은 출력이 끝났음을 알려 주기 위한 메소드를 1개 더 가지고 있다. 이 메소드가 바로 flush() 메소드이다.


flush() 메소드를 제대로 사용하려면 버퍼를 알아야 한다.


버퍼는 일종의 완충지대로 입출력을 조금 더 빨리 할 수 있게 도와준다. 모든 출력은 도착 지점으로 바로 나가지 않고 먼저 버퍼에 쌓인다.

버퍼에 데이터가 충분히 쌓인 후 flush() 명령을 받으면 현재 버퍼에 있던 모든 내용을 도착 지점으로 내보내고 버퍼를 비워 버린다.


즉, flush() 메소드를 호출하지 않으면 버퍼로만 출력되기 때문에 실제로 도착 지점에서는 아무런 데이터를 받지 못하는 경우가 발생할 수 있다. 


이런 이유로 일반적인 OutputStream에서는 데이터를 출력하고 나면 자동적으로 flush() 메솓를 호출하게 만들 수 있는 기능을 제공하는 경우가 많다.


JAVA API DOC : OutputStream



출처: https://hyeonstorage.tistory.com/234?category=578560 [개발이 하고 싶어요]