파게로그

입출력 본문

콤퓨타 왕기초/Java

입출력

파게 2020. 11. 8. 13:59

스트림(Stream)이란?

여기서 말하는 스트림은 Java 8에서 추가된 Stream API와는 무관하다.

스트림이란, 연속된 데이터가 단방향으로 흐름을 추상화한 것이다.

문자 그대로 '물의 흐름'을 떠올리면 쉬운데, 출발지로부터 도착지까지의, 방향이 하나로 일정한 흐름이다.

Java에서는 입출력 스트림 외에도 바이트 기반 스트림, 보조 스트림, 문자 기반 스트림이 제공된다.

스트림은 마치 큐(queue)처럼 FIFO(First In, First Out) 구조를 가져서, 스트림 속 데이터의 순서를 바꿀 수 없다.

 

입출력 스트림이란?

Java에서는 입출력을 처리하기 위한 입출력 스트림을 제공하고 있다.

InputStream의 경우 출발지는 키보드, 마우스와 같은 Input 장치나 다른 프로그램 등이고 도착지는 프로그램이다.

OutputStream의 경우 출발지는 프로그램이고 도착지는 모니터, 프린터와 같은 Output 장치나 다른 프로그램 등이다.

입출력 스트림 또한 FIFO 구조를 가지기에, 스트림 속 데이터의 순서는 바뀔 수 없다.

또한 스트림은 단방향으로만 통신할 수 있기에, 하나의 스트림을 통해서 Input과 Output 모두를 수행할 수는 없다.

Java에서 입출력 스트림은 java.io라는 패키지를 통해서 InputStream과 OutputStream이라는 클래스로 제공된다.

즉 Java에서의 스트림 생성이란, 이러한 스트림 클래스 타입의 인스턴스를 생성한다는 것을 의미한다.

이러한 스트림 클래스에는 다음과 같은 메서드가 정의되어 있다.

InputStream에는 abstract int read()라는 추상 메서드가,

OutputStream에는 abstract void write(int b)라는 추상 메서드가 정의되어 있다.

http://www.tcpschool.com/java/java_io_stream


응용 프로그램 ↔ 인터페이스 플랫폼(I/O기기, 다른 프로그램 등)

여기서 인터페이스는, 함수 형식을 가지고 있다.

예를 들어 다음의 구조와 같다.

 

절차언어: 프로그램 API(Kakao.Auth...(), fprintf(), ...) 카카오톡, 페이스북, 모니터, 디스크 등

여기서 절차언어란 연산자, 제어 구조, 변수, 배열 등 모든 것을 포함한다.

 

자바언어: 프로그램 (콘솔 (Java Platform))

자바에서는 이러한 API가 함수가 아니라 System.in, System.out이라는 객체로 묶여있다.

여기서 in, out은 클래스 변수로서, 각각 타입이 InputStream, OutputStream인 스트림 객체이다.

 

InputStream 클래스는 최상위 클래스이자 추상 클래스로서 객체를 생성할 수 없는데

어떻게 System.in은 실제로 객체가 존재할까?

변수의 타입은 조상 클래스이지만 실제 객체는 자손 객체이기 때문이고, 형 변환이 지원되기 때문에 가능한 일이다.

https://hyeonstorage.tistory.com/235

 

응용 프로그램에서 write()를 통해 출력하고 싶을 때, 값을 전달한다고 해서 바로 전달되는 건 아니다.

여러 프로그램이 동시에 실행되고 있는데 그렇다고 무작정 줄을 세워서 다른 프로그램들이 멈춰 있을 순 없으니까,

버퍼를 이용한다.

여기서는 출력 버퍼가 실행환경이며, 이 출력 버퍼가 자바에서는 OutputStream이다.

어플리케이션의 동기화를 막아주고, 비동기적으로 작업할 수 있도록 한다.

[버퍼] https://m.blog.naver.com/haha7037/221893441579

[버퍼] https://devshock.tistory.com/51


키보드를 누르면 입력버퍼에 key code(키 식별 번호)가 들어간다.

 

표준화: ASCII(American Standard Code for Information Interchange)

0~127: 7bit

0~255: 8bit

 

ASCII+KR = EUC-KR, ASCII+CN = EUC-CN, ASCII+JP = EUC-JP, ...

근데 같은 코드가 다른 체계에 동시에 존재하니까, 배타적으로 사용할 수 있도록 UNICODE를 사용한다.

 

System.out.write(3);	// 3이 출력되는 게 아니라 문자코드 3에 해당하는 문자가 출력된다.
System.out.flush();		// flush()를 사용하지 않으면 버퍼가 꽉 차야지만 출력된다.

System.out.wirte(51);	// 문자코드 51에 해당하는 문자 3이 출력된다.
System.out.write('3');	// 문자 3에 해당하는 문자코드 51에 해당하는 문자 3이 출력된다.
System.out.write('3'+1);// 문자 3에 해당하는 문자코드 51에 1을 더해 문자코드 52에 해당하는
						// 문자 4가 출력된다.

new PrintStream(new OutputSteram()); 을 통해 print(), println(), printf()을 이용할 수 있다.

C의 printf()처럼 동일하게 사용 가능하다.

System.out.printf("%d년 %월 %일", 2020, 11, 10); // 2020년 11월 10일

 

포맷 문자열에서 형식 지정자

%d 10진수 정수 // ("%5d", 29) // 29

%x 16진수 정수 // ("%x", 29) // 1D

%o 8진수 정수 // ("%o", 29) // 35

%f 실수

%e 지수형 실수

%c 문자

%s 문자열

 

형식 지정자의 옵션

[Begin Format Specifier][Argument Index][Flags][Width][Precision][Conversion]

[%][n$][+n][n][.n][f]

Flag: -일 경우 왼쪽 정렬

Argument Index: System.out.printf("%2$d %2$d %2$d %3$d %1$d\n", 1, 2, 3); // 2 2 2 3 1

 

%5.2f

앞에 쓰는 5는 정수부, 소수점, 소수부를 모두 포함한 총 길이를 고정시킨다.

단 이는 minimum 값이라, 실제 값이 이 자리수를 넘어간다고 하더라도 잘려서 표현되는 일은 없다.

소수점 둘째자리까지 표현된다.

 

입력

콘솔 입력 개체: System.in (InputStream의 실체화)

int code = System.in.read(); // 1byte의 ASCII 값이 전달됨

 

Scanner 클래스

Scanner scan = new java.util.Scanner(System.in); // System.in: 바이트 단위로 읽음

또는

import java.util.Scanner;

Scanner scan = new Scanner(System.in);

과 같이 사용한다.

 

나중에 scan.close()를 통해 닫아주어야 한다.

 

nextInt(), nextFloat(), nextDouble()을 통해 자동 캐스팅이 가능하다.

int inputValue = scan.nextInt();

 

버퍼의 내용을 한번에 문자열로 읽고자 한다면 System.in.nextLine()을,

공백 문자로 구분해서 읽고자 한다면 System.in.next()을 사용한다.

Comments