바이트 단위로 기본적으로 지원한다. 이것은 가장 원시적인 형태의 입출력이며 아무런 변환 작업을 수행하지 않는다. 그러므로 바이너리 형태의 자원을 다루기 적합하며 InputStream/OutputStream의 두 클래스가 최상위 클래스이다.
두개의 클래스는 추상 클래스로 정의 되어있어 BufferedOutputStream, FileOuputStream등과 같이 내보내고자하는 타입에 맞게구현할 수 있다.
출력스트림
outputStream은 write라는 메소드를 제공하는데 0~255사이의 값만을 입력 받을 수 있다. 입력된 값의 하위 8비트를 출력한다.
하나씩 outputStream으로 전송하는 방식은 통신을 하는 서버에 굉장히 부담이다.
Byte[]에 저장 후 한번에 write(byte)처럼 한번에 보내는 방식을 사용해야 한다.
그러니 기본적으로 bufferedOutputStream이나 BufferedWriter등의 스트림을 제공하여 버퍼링을 사용 할 수 있다.
입력이나 출력이 끝났을 경우에는 flush()메소드를 사용하여 끝났음을 알린다. 만약 버퍼 사이즈가 1024여서 다 채워지지 않아 전송을 하고 있지 않으면 자원을 하염없이 기다리는 데드락 상태가 유발 될 수 있다. 그 문제를 동작이 완료되면 flush()를 통해 완료됬음을 StreamOutput 클래스에 알려줄 필요가 있다.
스트림을 닫기 전에는 항상 플러시를 해야 한다.
Close()메소드는 파일 핸들 또는 포트 같은 해당 스트림과 관련된 리소스를 해제한다.
Java 6 이전에는 try에서 선언하고 final에서 해제하는 방식이였으나
Java 7 이후 부터는 try(OutputStream out = FileOutputStream("/tmp/data.txt")) {
//ffff
} catch (Exception ex) {
}
Try블록 인자 목록에 있는 autoCloable 객체의 close()를 자동으로 호출하므로 finally 구문은 더 이상 필요로 하지 않는다.
입력 스트림
InputStream의 서브클래서는 특정 매체로부터 데이터를 읽기 위해 이 메소드를 사용한다.
기본 로직
Read(byte[] b) > b크기만큼 읽은 후 b에 저장하고 저장하고 읽은 바이트 수를 반환한다.
Read(byte[] b, int offset, int len) byte b에 offset 위치에 len 만큼의 값을 입력한다.
Ex)
Int bytesRead =0;
Byte bucker = new bucket[1024];
While(bytesRead = in.read(buffer) != -1 ) {
Out.write(bucket, offset, bytesRead);
//in.read할 경우에 읽음에 성공한 byte의 수를 반환하기 때문에 입력할 때 읽기의 성공한 길이 값으로 사용하면 된다.
}
Read()메소드는 단일 바이트를 읽고 0~255 사이의 값을 정수 타입으로 반환한다.
Read()메소드는 비록 바이트 값만 읽을 수 있지만 int 타입을 반환한다.
한번에 한바이트씩 읽는건 비효율적이다.
그래서 오버로드된 read메소드를 사용하여 파일을 여러 크기만큼 읽을 수 있다.
Byte[] input = new byte[1024];
Int bytesRead = in.read(input);
-- 이 코드는 in에서 1024만큼 읽어 input 배열에 저장하려고 한다.
만약 1024만큼 다 채워진 다음 읽어서 저장해야 하는 경우에는
Int byteRead = 0;
Int bytesToRead = 1024;
Byte[] input = new byte[bytesToRead];
While(bytesRead < bytesToRead) {
Int result = in.read(input, bytesRead, bytesToRead-bytesRead);
-> len만큼 읽어 byte[](input)의 bytesRead위치에 저장하고 읽은 바이트 수를 반환한다.
If (result == -1) break; //1024이하의 스트림을 읽고 끝났을 때의 상황을 고려해야 한다.
bytesRead += read;
}
필요한 데이터를 모두 읽을 수 있을 때 까지 실행이 대기되는 상황을 원치 않는 경우에는, 대기없이 즉시 읽을 수 있는 바이트 수를반환하는 available()를 사용하여 읽을 바이트 수를 미리 정할 수 있다.
Ex) l
Int bytesAvailable = in.available();
Byte[] input = new byte[bytesAvailabel]'
Int bytesRead = in.read(input, 0, bytesAVailable);
중간에 읽기 싫은 바이트가 있어서 건너뛰고 싶은 경우 skip() 메소드를 사용한다.
하지만 네트워크에서는 데이터를 전송받는 순서가 순차적이기에 유용하지 못하다.
차라리 원하는 데이터의 인덱스 값을 이용해서 읽는 것이 더욱 바람직하다.
추가적으로 input, outputStream에서 mark(), reset()메소드를 제공한다.
Mark()는 이미 읽은 데이터중 다시 읽을 필요가 있는 것을 표시하기 위해서 사용되고,
Reset()은 필요한 시점에서 mark()로 출력된 위치로 이동하여 스트림을 재설정 한다.
필터 스트림
자바의 raw바이트(가공하지 않은 데이터)를 데이터 형식으로 변환하기 위해 저수준 스트림에 연결할 수 있는 많은 필터 클래스를 제공한다.
필터는 필터 스트림 , reader, writer로 나뉜다.
- 필터 스트림은 기본적으로 raw바이트를 대상으로 동작한다.(데이터를 압축하거나 이이진수로 변환하는 일들이 포함된다.)
- Reader, writer는 UTF-9, iso 같은 형식으로 인코딩된 특수한 텍스트를 처리하는데 사용된다.
네트워크 상에서 필터 사용의 예)
필터는 네트워크 인터페이스에서 데이터를 전달 받을 때 저수준의 압축 암호화 데이터가 TelnetinputStream에 도착한 후 bufferedInputStream에 저장하고, CipherInputStream에 데이터가 들어가 데이터를 해독하고 GZIPInputStream에서 해독된 데이터의 압축을 해제한다.
대부분의 경우에는 실제 읽고 쓰는 일을 하는 필터는 맨 마지막의 필터만을 사용해야한다.
-> 섞어서 호출할 경우 필터 스트림의 몇 가지 암묵적인 규칙을 위반할 수 있다.
BufferedInputStream과 BufferedOutPutStream은 두 개의 생성자가 존재한다.
첫 번쨰 인자는 버퍼링 되지 않은 데이터를 읽게 될 하위 스트림이고, 두번째 인자는 버퍼에 저장할 수 있는 바이트의 양을 설정한다.
->만약 설정 하지 않을 경우에는 입력 버퍼는 2048바이트, 출력버퍼는 512바이트가 설정된다.
printStream
printStream은 기본적으로 가장 먼저 사용하는 스트림이다.
그러나 해당스트림에는 세가지의 단점이 존재한다.'
- 플랫폼의 캐리지 리턴 방식의 의존적이여서 리눅스와 윈도우 방식의 차이일 경우 큰 오류를 양산할 수 있다.
- PrintStream의 두번째 문제는 프로그램이 실행중인 플랫폼의 인코딩을 기본 인코딩으로 가정해서 문게가 발생할 수 있다. 기본인코딩을 변경할 수 있는 어떠한 방법도 제공되지 않아 더 문제다.
- 세번째 문제는 PrintStream이 모든 예외를 무시한다.
=> PrintStream에서 기본적으로 제공하는 메소드들은 ThrowsIOException이 선언되어 있지 않다. 그리서 별도의 에러 플래그를 사용하는데 매번 체크를 위해서 checkError() 메소드를 호
출해야한다.
-> 해당 문제로 인해 PrintStream을 사용하지 않고 PrintWriter를 사용하기를 권고한다.
Reader와 Writer
- InputStreamReader는 raw바이트를 읽을 수 있는 하위 입력 스트림을 퐇함하고 있고, 이 하위 입력 스트림을 통해 읽은 raw바이트를 지정된 인코딩에 따라 유니코드로 변환한다.
- OutPutStreamWriter는 실행중인 프로그램으로부터 유니코드 문자를 전달받고, 지정된 인코딩을 사용하여 바이트로 변환한다. 그리고 바이트를 내장된 하위 출력스트림에 쓴다.
- OutPutStreamWriter클래스는 writer의 가장 중요한 클래스다. 해당 클래스는 자바 프로그램으로부터 문자를 전달받고 지정된 인코딩에 따라 바이트로 변환된다.
그리고 변환된 바이트를 내장된 하위 출력 스트림에 쓴다.
Public OutputStreamWriter(OutputStream out, String encoding)
'JAVA > Input & output' 카테고리의 다른 글
Java File클래스를 이용한 파일입출력 사용 (0) | 2018.05.27 |
---|---|
스트림(Stream)_입출력 스트림 (0) | 2016.12.21 |