[Java] 입출력 (I/O) 1
컴퓨터에서 제일 기본적인 입력 장치는 키보드이고, 출력 장치는 모니터이고 키보드와 모니터를 Standard Input output으로 말한다. Java에서 출력을 처리할 때 System.out.println등등 비슷한 메서드를 사용하고 입력을 받을 때는 Scanner 클래스를 이용해 처리하는데 이런 방법 말고 입력과 출력의 소스를 다르게 했을 때는 어떻게 처리 할 수 있을까?
입력과 출력을 합쳐서 입출력 (Input / Output) 이라고 하고 두 대상 간의 데이터를 주고 받는 걸 의미한다.
입력을 받을 때 쓰이는 통로와 출력을 처리할 때 쓰이는 통로는 각각 따로 정의돼야 하고, 이 통로를 Stream 이라고 한다. (입력스트림 / 출력스트림)
스트림은 바이트 단위로 데이터를 전송하고 입출력의 대상에 따라 위와 같은 입/출력 스트림이 있다.
파일에 대해서 입출력을 수행하려면 FileInputStream FileOutputStream을 사용하는 등 어떤 대상에 대해서 작업을 하는지에 따라 Stream을 선택한다.
위의 Stream들은 모두 InputStream과 OutputStream의 자식으로 조상의 추상메서드들은 타입에 맞게 구현돼있다.
byte 보다 int의 범위가 더 넓기 때문에 int로 byte타입의 데이터를 처리할 수 있다.
int read(byte[] b, int off, int len) 의 경우에는 off ~ len 까지를 한 번에 처리하라는 의미이다. 여기서 read() 메서드가 구현되어야 사용할 수 있다. (내부에서 read()를 호출함)
자체적으로 입력과 출력의 통로를 제공해 주는 것이 아니라, 입출력의 통로가 있을 때 그 통로를 인자로 받는 보조 스트림을 정의할 수 있다. 보조 스트림을 사용함으로써 기존 스트림에서의 연산 속도를 향상시키거나 특정 타입의 입력값을 좀 더 쉽게 처리할 수 있는 등 다양한 기능을 수행할 수 있다. (보조스트림은 스트림을 먼저 생성한 다음에 사용할 수 있다.)
FilterInputStream을 통해 필터를 이용해 입출력을 처리할 수 있고
BufferInputStream을 통해 입력을 버퍼에 저장했다가 한 번에 사용하게 해 입출력의 성능을 개선할 수 있다.
위를 보면 알 수 있듯, 보조 스트림도 입력과 출력을 따로 처리한다.
이 외에도 많은 보조 스트림이 있는데 Filter와 Buffer에 집중해 공부하자.
위에서는 1바이트 단위로 입출력을 다뤘는데, 자바에서 문자(char) 하나의 사이즈는 2바이트이다. (C언어에서는 1바이트임) 문자 단위로 입출력을 진행하기 위해서는 다른 스트림을 사용해야 한다. 스트림은 원래 1바이트 단위로 데이터를 다루지만 문자가 2바이트라서 문자 기반의 스트림이 따로 제공된다. 따라서 앞으로는 문자열 기반의 스트림을 제일 많이 다루게 될 것이다. 앞으로 문자데이터를 입출력할 때는 바이트기반 스트림 대신 문자기반 스트림을 사용하자.
InputStream 을 Reader로
OutputStream을 Writer로 바꾸면 문자기반 스트림이 된다. (ByteArray는 예외)
바이트 기반 스트림과 문자 기반 스트림은 이름만 조금 다르지 활용법은 거의 같다. (보조스트림도 마찬가지)
우선 바이트 기반 스트림에 대해 알아보자.
InputStream과 OutputStream 클래스는 바이트 기반 스트림의 최고 조상이다.
이 클래스를 상속받는 다양한 바이트 기반 클래스들은 위의 메서드를 포함한다.
가장 중요한 메서드는 역시 read와 write 메서드이고 (byte 단위로 처리할 수 있음에 주의하자.) 이 외에도 mark와 reset으로 이미 읽은 데이터를 되돌려서 다시 읽을 수 있는 메서드가 있다.
특정한 ByteArray를 읽거나 쓰는 통로를 정의하는 스트림으로 ByteArrayInputStream (Output도 동일) 이 있다.
바이트 타입의 배열에 데이터를 입출력하는데 사용하는 스트림이다.
read와 write를 사용하는 좋은 예시이다.
(data = input.read()) !=-1 는 괄호 순서대로 처리한다. 수학적 직관대로 하면 된다.
위의 코드에서 input은 inSrc 배열의 원소들을 byte 단위로 읽어온다.
읽어온 배열을 output 배열로 변환해 출력하는 예시이다.
이 예시는 배열의 원소를 하나씩 읽고 출력했는데, byte 타입의 배열을 사용하면 한 번에 읽어올 수 있지 않을까?
위의 경우 크기가 4인 byte 타입의 배열을 만들고 write메서드를 통해 그 배열을 읽어오도록 했는데, 이 경우 0,1,2,3 4,5,6,7 까지는 정상적으로 작동하지만 8,9를 읽어온 다음 6,7 이 남아있게 돼 output에 8,9,6,7 이 저장되게 된다.
read(temp) 하면 temp에 읽어온 값이 저장됨.
하지만 read의 인자로 byte타입의 배열을 넣어주면 읽어 온 데이터의 수를 반환한다.
따라서 오른쪽의 바꾼 코드로 실행했을 때는 처음에 4, 두번째로 4, 마지막으로 2개의 데이터를 읽어오게 되고 의도한 대로 출력된다. (temp의 0부터 len까지 write 하기)
그래서 len 처럼 별도의 변수를 도입해 코드를 작성하는 편이 합리적이다.
byte단위로 "파일"을 읽을 때에 대해 알아보자. (Filter File 헷갈리지 말기)
매개변수로는 파일의 이름을 받는다.
read와 write는 동일한 방식으로 사용한다.
파일을 읽어온 후에는 닫아준다.
실제로 프로그램을 작성할 때 파일을 생성할 때 사용할 수 있다.
byte 기반의 보조스트림에 대해 알아보자.
모든 byte기반 보조스트림의 조상은 FilterInputStream과 FilterOutputStream 클래스이다.
위의 클래스를 상속받아서 read와 write를 따로 정의해야 하지만..
FilterInputStream 과 OutputStream을 사용하기보다는 바로 BufferedStream이나 DataStream를 사용하는 경우가 많다.
입출력 값을 사용하기 전에 임시로 Buffer라는 메모리의 공간에 저장했다가 Buffer 단위로 사용함으로써 입출력의 성능을 끌어올린다.
Buffer는 보조 스트림이기 때문에 바로 ByteArray에 집어넣어서 정의할 수는 없고, 우선 Byte기반의 Stream을 정의한 다음 이 Stream을 인자로 가지는 Buffer를 생성해 주는 방식으로 사용해야 한다. (기본 버퍼사이즈는 8K 8192)
Buffer가 다 차진 않았지만 사용하고 싶을 때는 flush 메서드를 사용한다. (Buffer가 닫히면 자동으로 flush가 수행된다.)
버퍼 크기가 5이기 때문에 1 2 3 4 5 까지는 정상적으로 출력되지만 6 7 8 9 에서 파일을 닫았기 때문에 6 7 8 9는 출력되지 않는다. 버퍼를 닫을 시 6 7 8 9도 출력된다.
DataStream은 특정 자료형을 읽고 쓸 때 사용한다.
DataOutput 인터페이스를 구현했기 때문에 byte단위가 아닌 8가지 기본 자료형의 단위로 읽고 쓸 수 있다.
각 자료형의 크기가 달라서 출력한 데이터를 읽을 때는 순서에 주의해야 한다.
(보조 스트림으로 입력 출력 하는게 아니다. 입출력을 담당하는 스트림은 따로 있다.)
예시를 통해 알아보자.
FileOutputStream과 보조할 DataOutputStream을 정의했다.
DataStream을 통해 int 10 float 20.0 boolean true를 써서 출력을 확인하면 알 수 없는 문자를 볼 수 있다.
바이트 단위로 작성했기 때문에 알아볼 수 없는 거고, 반대로 위의 sample.dat를 읽어오면 정상적으로 데이터를 읽어올 수 있다. (형식만 다르다)
읽어 올 때도 같은 순서로 읽어야 한다.
읽어 올 때 어떤 단위로 읽을지에 따라 메서드가 정의돼있다.
'Programming Language > Java' 카테고리의 다른 글
[Java] 네트워킹 (Networking) 1 (0) | 2021.12.05 |
---|---|
[Java] 입출력 (I/O) 2 (0) | 2021.11.29 |
[Java] 쓰레드 (Thread) 2 (0) | 2021.11.12 |
[Java] 쓰레드 (Thread) 1 (0) | 2021.11.08 |
[Java] 래퍼 클래스 (Wrapper) (0) | 2021.10.29 |
댓글
이 글 공유하기
다른 글
-
[Java] 네트워킹 (Networking) 1
[Java] 네트워킹 (Networking) 1
2021.12.05 -
[Java] 입출력 (I/O) 2
[Java] 입출력 (I/O) 2
2021.11.29 -
[Java] 쓰레드 (Thread) 2
[Java] 쓰레드 (Thread) 2
2021.11.12 -
[Java] 쓰레드 (Thread) 1
[Java] 쓰레드 (Thread) 1
2021.11.08