본문 바로가기
[ JAVA ]/JAVA

[ Java ] I/O Stream

by 환이s 2023. 1. 10.
CHAPTER 21. 입출력 알아가기

 

오늘은 데이터 입출력에 대한 포스팅을 해보려 합니다!!

프로그램에서는 데이터를 외부에서 읽고 다시 외부로 출력하는 작업이 빈번하게 일어납니다.

 

데이터는 사용자로부터 키보드, 마우스 등을 통해 입력될 수도 있고, 파일 또는 네트워크를 통해 입력될 수도 있습니다. 또한 반대로 데이터를 사용자에게 모니터나 파일 등으로 출력할 수도 있는데 자바에서 데이터는 어떻게 입출력이 될까요??

 

■ Stream이란?

Java에서는 파일이나 콘솔의 입출력을 직접 다루지 않고, stream(스트림)이라는 흐름을 통해 다룹니다.

 

stream이란 실제의 입력이나 출력이 표현된 데이터의 이상화된 흐름을 의미합니다. 즉 단일 방향으로 연속적으로 흘러가는 것을 말하는데, 

즉, stream은 운영체제에 의해 생성되는 가상의 연결 고리를 의미하면서도 중간 매개자 역할을 합니다.

 

■ Java.io.Package

Java의 기본적인 데이터 입출력은 Java.io 패키지에서 제공합니다. Java.io 패키지에서는 파일 시스템의 정보를 얻기 위한 File클래스와 데이터를 입출력하기 위한 다양한 입출력 스트림 클래스를 제공합니다.

 

가 ) I/O Stream

  • InputStream(입력 스트림) : 입력 장치(키보드, 마우스 등)으로 부터 받은 입력 값을 자바 응용 프로그램으로 전달하는 객체입니다. 자바 응용 프로그램은 입력 장치로부터 직접 데이터를 읽지 않고 입력 스트림을 통해 데이터를 읽습니다.
  • OutputStream(출력 스트림) : 자바 응용 프로그램으로 부터 출력 장치(화면 등)으로 데이터를 보내는 객체입니다. 입력스트림과 마찬가지로 직접 데이터를 전달하지 않고 출력 스트림을 통해 데이터를 보냅니다.

 

자바에서 다음과 같은 I/O Stream을 제공하고 있습니다.

클래스 메소드 설 명
InputStream
(입력 스트림)
abstract read() 해당 입력 스트림으로부터 다음 byte를 읽어들임.
int read(byte[] b) 해당 입력 스트림으로부터 특정 byte를 읽어들인 후, 배열 b에 저장함
int read(byte[] b, int off, int len) 해당 입력 스트림으로부터 len byte를 읽어들인 후, 배열 b[off]부터 저장합니다.
OutputStream
(출력 스트림)
abstract void write(int b) 해당 출력 스트림에 특정 byte를 저장합니다.
void write(byte[] b) 배열 b의 특정 byte를 b의 길이만큼 해당 출력 스트림에 저장합니다.
void write(byte[] b, int off, int len) 배열 b[off]부터 len byte를 해당 출력 스트림에 저장합니다.

 

예제 코드를 통해서 알아봅시다.

 

<예제 1>

import java.io.InputStream;

// ~Stream 객체들은 1byte단위로 스트림 처리하며, 영문 대소문자,숫자,특수문자만 처리할 수 있다.(한글처리불가)
//InputStream,OutputStream
public class InputStreamEx1 {
    public static void main(String[] args) {
        InputStream is = System.in; //대표적으로 System.in은 InputStream이다.
        System.out.print("문자를 입력하세요 : " );
        try {//입출력, 네트워크,DB는 필수적 예외처리
            int code = is.read();//키보드로부터 1byte로 읽음, 따라서 한글(2byte)처리가 안됨
            // => InputStreamReader를 써야함
            System.out.println(code);
            char ch = (char) code;//모든 문자에는 고유한 숫자코드가 있다. 따라서 int형 code를
            // char형으로 형변환해서 코드값을 문자값으로 볼 수도 있다.
            System.out.println("char : "+ ch);

        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

 

<예제1> 코드를 실행하면 아래와 같은 결과가 표출됩니다.

 

모든 문자에는 고유한 코드값이 있습니다.(맨 아래 글 참고!) 

그리고 Stream은 Try~catch문을 활용하셔야 합니다.

 

 

그럼 OutputStream도 예제 코드를 통해서 알아봅시다.

 

<예제 2>

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;

public class OutputStreamEx {
    public static void main(String[] args) {
        PrintStream ps = System.out; //PrintStream 전용 객체
        OutputStream os = ps;//PrintStream 객체를 부모타입인 OutputStream으로 받아 처리
        //OutputStream도 1Byte 처리 스트림이다. 한글 X
        try {
            os.write(97); // 97 = a
            os.write(98); // 98 = b
            os.write(99); // 99 = c
            os.flush(); // flush()메소드를 써야 출력까지 된다.

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

위 예시는 문자 단위 입출력 스트림을 기반으로 작성해 보았습니다.

문자 스트림(InputStream : Reader),출력 문자 스트림(OutputStream : Writer)

 

<예제 2> 코드를 실행하면 아래와 같은 결과가 표출됩니다.

OutputStream도 1byte로 처리하는 스트림으로 한글은 출력할 수 없습니다.

그렇다면 한글은 출력이 안될까?? 

 

문자 스트림을 활용하시면 한글 포함 문자처리를 할 수 있습니다.(2byte)

 

<예제 3>

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintStream;

public class OutputStreamWriterEx {
    public static void main(String[] args) {
        PrintStream ps = System.out;
        OutputStream os = ps;
        OutputStreamWriter osw = new OutputStreamWriter(os);
        // OutputStreamWriter(OutputStream);
        // OutputStreamWriter는 한글포함 문자처리(2byte)
        try {
            osw.write(44032); // 가
            osw.write("나다라");
            osw.flush(); // 출력
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 

<예제 3> 코드를 실행하면 아래와 같은 결과가 표출됩니다.

 

그럼 예제 코드에서 사용했던 메서드를 알기 위해 Stream에 종류와 각 메서드를 알아봅시다.

 

나 ) Byte Stream

 

Java에서는 스트림은 기본적으로 바이트 단위로 데이터를 전송합니다.

 

Byte Stream은 문자 데이터, 바이너리 데이터 상관없이 데이터를 바이너리 2진 데이터 그대로 읽고 저장합니다. 바이트 입력 스트림의 경우 바이트 입력 스트림을 거쳐도 바이트 상태로 입출력 데이터를 단순 바이트의 흐름으로 처리합니다.

 

참고로 한글은 2byte가 한 글자로 구성됩니다.

 

자바에서 다음과 같은  Byte Stream을 제공하고 있습니다.

InputStream OutputStream  I/O 대상
FileInputStream FileOutputStream 파일
ByteArrayInputStream ByteArrayOutputStream 메모리
pipedInputStream pipedOutputStream 프로세스
AudioInputStream AudioOutputStream 오디오 장치

 

 

또한 다른 스트림의 기능을 향상하거나 새로운 기능을 추가해 주는 스트림도 있습니다.

InputStream OutputStream 설 명
FilterInputStream FilterOutputStream 필터를 이용한 입출력 입니다.
BufferedInputStream BufferedOutputStream 버퍼를 이용한 입출력 입니다.
DataInputStream DataOutputStream 입출력 스트림으로부터 자바의 기본 타입으로 데이터를 읽어올 수 있게 합니다.
ObjectInputStream ObjectOutputStream 데이터를 객체 단위로 읽거나, 읽어 들인 객체를 역직렬화 시켜줍니다.

 

다 ) 문자 단위 스트림

 

Java에서는 바이트 기반 스트림뿐만 아니라 문자 기반의 스트림도 별도로 제공합니다.

 

문자 스트림에는 크게 입력 문자 스트림(InputStream : Reader)과 출력 문자 스트림(OutputStream : Writer)이 존재하는데, 문자 스트림은 문자(text)만 입출력하는 스트림으로 다른 데이터는 처리하지 못합니다. 바이너리로 들어온 문자 데이터가 문자 스트림을 거치면 문자로 변환됩니다.

 

자바에서 다음과 같은  문자 단위 스트림을 제공하고 있습니다.

InputStream OutputStream I/O 대상 및 설명
FileReader FileWriter 파일
CharArrayReader CharArrayWriter 메모리
PipedReader PipedWriter 프로세스
StringReader StringWriter 문자열
FilterReader FilterWriter 필터를 이용한 입출력입니다.
BufferedReader BufferedWriter 버퍼를 이용한 입출력입니다.
PushbackReader x 다른 입력 스트림에 버퍼를 이용하여 push back이나 unread와 같은 기능을 추가합니다.
x PrintWriter 다른 출력 스트림에 버퍼를 이용하여 다양한 데이터를 출력하기 위한 기능을 추가합니다.

 

※  입출력 스트림 계층 구조

 

라 ) Buffer I/O Stream

 

버퍼(buffer)는 한 곳에서 다른 한 곳으로 전송하는 동안 일시적으로 그 데이터를 보관하는 임시 메모리 영역으로, 입출력의 속도 향상을 위해 버퍼를 사용합니다. 

 

그럼 버퍼를 이용하여 입출력은 어떻게 할까요??

// 버퍼를 이용한 입력
BufferedReader
// 버퍼를 이용한 출력
BufferedWriter

선언 방식은 위와 같습니다. 그렇다면 예제를 통해서 알아봅시다.

 

<예제 4>

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class BufferedReaderEx1 {
    public static void main(String[] args) {
        InputStream is = System.in;
        InputStreamReader isr = new InputStreamReader(is);
        BufferedReader br = new BufferedReader(isr);
        //Buffered 계열(Reader 계열(Stream))형태로 구성됨


        System.out.print("문자열 한줄로 입력하세요 : ");
        String line;
        try {
            line = br.readLine();//문자열 한줄 입력받기
            System.out.println("입력한 문자열 : "+ line);
        } catch (IOException e) {
            System.out.println("프로그램 종료");
        }
    }
}

 

<예제 4> 코드를 실행하면 아래와 같은 결과가 표출됩니다.

 

그럼 이번에는 Output을 알아봅시다.

 

<예제 5>

import java.io.*;

public class BufferedWriterEx {
    public static void main(String[] args) {
//        PrintStream ps = System.out;
//        OutputStream os = ps;
//        OutputStreamWriter osw = new OutputStreamWriter(os);
//        BufferedWriter bw = new BufferedWriter(osw);
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

        try {
            bw.write("환영합니다.\n");
            bw.write("Java");
            bw.newLine(); // 개행처리 해주는 메소드
            bw.write("World!!");
            bw.flush();
            bw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 

<예제 5> 코드를 실행하면 아래와 같은 결과가 표출됩니다.

 

 

■ 표준 입출력

입출력은 프로그램이 시작되면 입출력을 위한 객체가 자동으로 생성됩니다.

 

  • 키보드 입력 관련 객체 : System.in(기본 InputStream을 씁니다.)
  • 모니터 출력 관련 객체 : System.out

위 예시 코드에서 작성했던 것처럼 모든 문자에는 고유한 코드값이 있습니다.

 

<ASCII code>

 

<키보드 키코드>


마치며

 

자바를 처음 언어로 공부하시는 분들은 입출력 단계에서 어려움을 느끼실 수 있습니다. 

어려운 만큼 포스팅을 많이 보시면서 직접 코딩을 해보시는 게 좋을 거 같아요..!!

 

728x90

'[ JAVA ] > JAVA' 카테고리의 다른 글

[ Java ] Socket Programming  (0) 2023.01.13
[ Java ] 객체 직렬화(Object serialization)  (1) 2023.01.11
[ Java ] GUI 프로그래밍 응용  (2) 2023.01.09
[ Java ] GUI 프로그래밍 개념  (2) 2023.01.07
[ Java ] Thread  (0) 2023.01.05