[JAVA] inputStream, InputStreamReader, bufferReader/Writer 총정리
좋은 글 있어서 퍼와서 정리 하였습니다.
자바 입출력 스트림
# inputStream
InputStream의 정의
JDK 11 기준 InputStream의 설명을 읽어보면
This abstract class is the superclass of all classes representing an input stream of bytes
라고 되어 있다. 중요한 부분은 "representing an input stream of bytes"이다. 하나씩 살펴보자.
Stream
먼저 Stream을 위키백과에 검색하면 이렇게 나온다.
개별 바이트나 문자열인 데이터의 원천
파일을 읽거나 쓸 때, 네트워크 소켓을 거쳐 통신할 때 쓰이는 추상적인 개념
백과에 정의된 내용을 쉽게 표현하면, '데이터가 전송되는 통로'라고 표현할 수 있다.
데이터가 네트워크를 거치건, 파일에서 넘어오건, 키보드로부터 오건, 데이터가 오고가는 통로가 스트림인 것이다.
byte
바이트란 이해하기 쉽다. 다 알고 계시겠지만 모든 데이터는 결국 0과 1로 귀결되고 0이나 1이 8개 모이면 그것을 'byte'라고 부른다. 따라서 우선은 그냥 '데이터'라고 생각해도 된다.
종합하면 InputStream 추상 클래스는 데이터가 들어오는 통로의 역할에 관해 규정하고 있는 추상 클래스이다.
아 역시 뭔가 또 막상 생각을 하면 어려울게 없다.
InputStream 주요 메소드
그럼 이제 데이터가 들어오는 통로는 어떤 역할을 수행해야 하는지 주요 메소드를 알아보자!
InputStream은 데이터를 읽어야 한다
파일에서 오건, 메모리에서 오건, 네트워크에서 오건 통로로 데이터를 빨아들이는 기능이 필요하다!
데이터를 읽는 기능과 관련된 메소드는 3개가 있다.
/**
* 1byte를 읽어 그 값을 int로 바꿔 반환하거나 (1byte = -128 ~ 127 또는 0 ~ 255이다)
* 더 이상 읽을 수 없는 경우는 -1을 반환한다
*/
public abstract int read() throws IOException;
// Main method
byte[] data = new byte[]{1, 2};
ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
System.out.println(inputStream.read()); // 바이트 하나를 읽었으니, 1을 읽었고 1이 출력된다
System.out.println(inputStream.read()); // 바이트 하나를 추가로 읽었으니, 2를 읽었고 2가 출력된다
System.out.println(inputStream.read()); // 더 이상 읽을 바이트가 없으니 -1이 출력된다
/**
* 1byte씩 읽는게 아니라 파라미터로 주어진 byte 배열 크기만큼 데이터를 읽고 총 몇 byte를 읽었는지 반환한다.
* 데이터를 읽다가 모두 읽으면, 그 만큼의 크기를 반환하고
* 시작부터 읽을게 없으면 -1을 반환한다
*/
public int read(byte b[]) throws IOException { }
// Main method
byte[] data = new byte[]{10, 20, 30, 40, 50};
ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
byte[] buffer = new byte[3];
System.out.println(inputStream.read(buffer)); // 바이트 3개(10, 20, 30)을 읽어 buffer에 넘겨주고 3을 출력한다
System.out.println(inputStream.read(buffer)); // 바이트 2개(40, 50)을 읽어 buffer에 넘겨주고 2를 출력한다
System.out.println(inputStream.read(buffer)); // 시작부터 읽을게 없으니 -1을 출력한다
/**
* len개의 byte를 읽어서 주어진 byte[] b의 b[off]부터 저장한다
* 저장한 개수를 반환하고, 읽을게 더 이상 없다면 -1을 반환한다
*
* 만약 bytep[] 크기가 부족하다면 IndexOutOfBoundsException을 낸다
*/
public int read(byte[] b, int off, int len) throws IOException { }
여기까지 읽었다면 InputStream에 대해 한 가지 알아낼 수 있다.
- InputStream은 말 그대로 통로이기 때문에, (read만 사용해서는) 한 번 읽었던 것을 다시 되돌아가 읽을 수 없다.
InputStream은 데이터를 스킵할 수 있다
/**
* n byte의 데이터를 스킵하고 실제로 스킵한 byte 개수가 출력된다
* 지원하지 않을 경우 IOException이 나오게 된다
*/
public long skip(long n) throws IOException { }
// Main method
byte[] data = new byte[]{10, 20, 30, 40, 50};
ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
System.out.println(inputStream.skip(3)); // 3개 skip 성공, 3을 출력
System.out.println(inputStream.read()); // 위에서 10, 20, 30을 skip했으므로 40을 출력
InputStream은 데이터가 얼마나 남았는지 알려준다
public int available() throws IOException;
InputStream은 닫을 수 있다
통로를 부실 수 있는 것이다
public void close() throws IOException;
InputStream은 읽었던 데이터를 특정 시점부터 다시 읽을 수 있다
/**
* 특정 시점을 기록하는 메소드 : mark
* readlimit은 마킹할 위치를 기록하는 것이 아니라,
* 현재 위치를 마킹하고나서 최대 몇개의 byte를 더 읽을 수 있는지를 의미한다
*
* 예를 들어, readlimit을 100으로 설정했다면,
* 지금 mark를 호출하고 read()를 101번 호출 할 수 없는 것이다.
*/
public synchronized void mark(int readlimit) { }
/**
* mark되어 있는 지점으로 돌아간다
* 이 이후에 read를 하면 아까 mark 해두었던 시점부터 데이터를 읽어들이는 것이다.
*/
public syncrhonized void reset() throws IOException { }
/**
* 이 InputStream 구현체가 mark / reset을 지원하는지, 지원하지 않는지를 표기한다.
*/
public boolean markSupported()
정리하면
아 드디어 모든 것(?)을 깨달았다.
InputStream은 데이터를 byte 단위로 읽어들이는 통로이며 (읽어들인 데이터를 byte로 돌려줌)
InputStream이 갖춰야 할 덕목으로는
- 데이터 읽기
- 특정 시점으로 되돌아가기
- 얼마나 데이터가 남았는지 보여주기
- 통로 끊기
# InputStreamReader
InputStreamReader : 문자 단위로 읽어 들인다.
InputStreamReader는 바이트 단위로 읽어 들이는 InputStream을 통해 입력을 받은 뒤,
문자 단위로 데이터를 변환시키는 중개자 역할을 하는 클래스로,
InputStream의 단점을 보완해 우리가 입력한 문자 값을 그대로 출력해주는 역할을 한다.
예) 입력 : abc, 출력 : abc
import java.io.InputStream;
import java.io.InputStreamReader;
public class StreamTest {
public static void main(String[] args) throws Exception {
InputStream in = System.in;
InputStreamReader reader = new InputStreamReader(in); // ①
char[] a = new char[3]; // 배열의 크기가 3인 배열 a 선언
reader.read(a); // ②
System.out.println(a);
}
}
① : 주어진 입력 바이트 스트림 in에 대해 기본 인코딩을 사용하는 객체를 생성한다.
- InputStreamReader reader = new InputStreamReader(in); -
InputStreamReader은 위에서 말했듯이,
InputStream을 통해 바이트 단위로 입력받은 값을 지정된 문자 인코딩에 따라 문자로 변환하는 클래스로,
Charset이라는 클래스에서 기본 인코딩인 UTF-16 방식으로 문자를 변환해준다.
② : byte 배열대신에 char 배열로 데이터를 받을 수 있다.
-
Char[] a = new char[3];
reader.read(a);
-
여기까지가 InputStreamReader를 이용하여 입력받는 방법이었다.
이 방법은 InputStream에서 많이 개선되었지만,
고정된 길이로만 읽어야 한다는 불편한 점이 있다.
(위 예제에서는 항상 3 byte만 읽도록 고정)
사용자가 엔터키를 입력할 때까지 사용자의 입력을 전부 받아들일 수는 없을까 ??
-> BufferReader라는 클래스 이용.
# bufferReader
buffer : 완충제, 완충 장치, 완화하다
완충제 : 일반적으로 급격한 외부 변화를 완화시키는 작용을 하는 물질
버퍼는 데이터를 한 곳에서 다른 한 곳으로 전송하는 동안 일시적으로 그 데이터를 보관하는 메모리의 영역이다.
버퍼링(Buffering)이란 버퍼를 활용하는 방식 또는 버퍼를 채우는 동작을 말한다. 다른 말로 큐(Queue)라고도 표현한다.
버퍼는 컴퓨터 안의 프로세스 사이에서 데이터를 이동시킬 때 사용된다. 보통 데이터는 키보드와 같은 입력 장치로부터
받거나 프린터와 같은 출력 장치로 내보낼 때 버퍼 안에 저장된다. 이는 전자 통신의 버퍼와 비유할 수 있다.
버퍼는 하드웨어나 소프트웨어에 추가될 수 있지만 버퍼는 상당수가 소프트웨어에 추가된다.
버퍼는 보통 속도가 계속 바뀔 수 있으므로 데이터 수신, 처리 속도에 차이가 있다.
롤러코스터 줄은 많은 유사점을 공유한다.
롤러코스터를 타는 사람들은 알려지지 않고
종종 가변적인 속도로 들어오지만 롤러코스터는 사람들을 순식간에 태울 수 잇다.
대기줄 영역은 승차를 원하는 사람들이 승차가 가능할 때까지 기다리는 임시 공간인 완충제 역할을 한다
데이터를 담아서 한 번에 전달하는 놈이란 건 알겠다. 그런데 버퍼를 왜 써야 할까?
버퍼 I/O가 없으면 각 읽기 또는 쓰기 요청이 기본 OS에서 직접 처리됨을 의미한다.
이건 각각의 그러한 요청이 종종 디스크 액세스, 네트워크 활동 또는 상대적으로 비용이 많이 드는
기타 작업을 트리거하기 때문에 프로그램을 훨씬 덜 효율적으로 만들 수 있다.
이런 종류의 오버헤드를 줄이기 위해 자바 플랫폼은 버퍼링된 I/O 스트림을 구현한다.
버퍼링된 입력 스트림은 버퍼로 알려진 메모리 영역에서 데이터를 읽는다.
버퍼는 다른 속도로 또는 다른 우선순위 세트로 작동하는 하드웨어 장치 또는 프로그램 프로세스가 공유하는 데이터 영역이다.
버퍼를 쓰면 각 장치 또는 프로세스가 다른 장치에 의해 유지되지 않고 작동할 수 있다.
버퍼가 효과적이려면 버퍼 크기와 버퍼 안팎으로 데이터를 이동하는 알고리즘을 버퍼 설계자가 고려해야 한다.
캐시와 마찬가지로 버퍼는 "중간 지점 유지 장소"지만 개별 활동의 조정을 지원하기보다 활동의 속도를 가속화하기 위해 존재한다.
이 용어는 프로그래밍과 하드웨어 모두에서 사용된다
버퍼의 장점 2개
1. 문자를 묶어서 한 번에 전달하므로 전송시간이 적게 걸려 성능이 향상된다
2. 사용자가 문자를 잘못 입력했을 경우 수정할 수 있다.
하지만 입력 작업에 버퍼를 쓰는 게 반드시 좋은 건 아니다.
빠른 반응이 요구되는 게임 등 프로그램에선 키를 누르는 즉시 전달돼야 한다.
https://lannstark.tistory.com/34
Java InputStream이란?
InputStream OutputStream을 실무에서 사용할 때면, 뭔가 알긴 알고 실제로 둘을 활용해 기능을 구현하는데는 전혀 문제가 없지만, 사용할때마다 찾아보게되고 뭔가 정확히 아는 것 같지는 않다라는 느
lannstark.tistory.com
InputStreamReader
이번 포스팅에서는 Java에서의 입력방법 중 하나인 InputStreamReader에 대해 얘기해볼 것이다. 2) InputStreamReader : 문자 단위로 읽어 들인다. 저번 포스팅에서 InputStream 클래스는 출력되는 값이 아스키
sy99.tistory.com
https://onlyfor-me-blog.tistory.com/368
[JAVA] 버퍼란? BufferedReader/Writer란? + 예제
딱 봤을 때 Bufferd와 reader, writer를 합친 단어같다. 그럼 프로그래밍에서 Buffer(버퍼)의 뜻이 뭔지부터 알아야 할 것 같다. 버퍼의 사전적 정의는 아래와 같다. buffer : 완충제, 완충 장치, 완화하다
onlyfor-me-blog.tistory.com