I/O

kwang·2022년 7월 7일
0

Java-Live-Study

목록 보기
14/15

목표

자바의 Input과 Ontput에 대해 학습하세요.

학습할 것 (필수)

  • 스트림 (Stream) / 버퍼 (Buffer) / 채널 (Channel) 기반의 I/O
  • InputStream과 OutputStream
  • Byte와 Character 스트림
  • 표준 스트림 (System.in, System.out, System.err)
  • 파일 읽고 쓰기

스트림 (Stream) / 버퍼 (Buffer) / 채널 (Channel) 기반의 I/O

I/O 입출력

I/O 입출력이란 Input과 Ouput의 약자로 컴퓨터 내부 또는 외부장치와 프로그램간의 데이터를 주고 받는 것을 말한다.

스트림(Stream)

데이터를 전달하는 과정은 받는 쪽과 보내는 쪽이 필요한데 이 두 대상을 연결하여 데이터를 전송할 수 있게 도와주는 통로와 같은 개념이다.

스트림은 단방향통신만 가능하다. 그러므로 출력과 입력을 동시에 진행할려면 두개의 스트림이 필요하다.

스트림은 보내진 데이터 순으로 처리된다.즉 선입선출 큐와 같은 구조로 되어있다고 생각하면 된다.

InputStream과 OutputStream

InputStream과 OutputStream

InputStream과 OutputStream은 바이트 기반 스트림의 최상의 스트림이다.

InputStream은 읽기를 수행하는 read()를
OutputStream은 쓰기를 수행하는 write()를 추상메서드 형태로 제공한다.

따라서 대상에 알맞게 구현되어있는 Stream을 이용해야한다.

입력 대상에 따라 InputStream과 OutputStream을 상속받은 아래표와 같은 다른 스트림을 사용할 수 있다.

입력스트림출력스트림대상
FileInputStreamFileOutputStream파일
ByteArrayInputStreamByteArrayOutputStream메모리(byte배열)
PipedInputStreamPipedOutputStream프로세스(프로세스간 통신)
AudioInputStreamAudioOutputStream오디오 장치

보조 스트림

스트림의 기능을 보완하기 위해 지원하는 보조스트림이라한다.

보조스트림은 실제 데이터를 주고 받지는 않고 스트림의 기능 향상 및 추가를 할 수 있도록 지원한다.

//  InputStream 생성
FileInputStream fileInputStream = new FileInputStream("test.txt");

// 보조 스트림 생성
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);

// Buffered**Stream 생성 시 사이즈도 정의하여 생성할 수 있다. (2번째 파라미터)
// default : 8192
BufferedInputStream bis = new BufferedInputStream(fileInputStream, 8192);

// 보조스트림을 이용해 데이터를 읽는다.
bufferedInputStream.read();

이처럼 보조스트림인 BufferedInputStream을 이용하는 이유는 일정량의 데이터를 한번에 모아서 읽어 효율성을 높이기 때문이다.

Buffer 효율을 높이는 이유
위에 설명에서 모아서 보낸다고 효율이 높아진다고 말했다. 효율이 높아지는 이유는 입출력 횟수의 변화때문이다.

실생활에 생각해보면 우리가 짐을 옮길때 하나씩 옮기기 보다 본인이 들 수 있는 무게를 상자에 담아서 한번에 옮기면 더욱 효율이 높아진다.
이러한 점과 같은 개념이라고 보면 된다.

버퍼/채널

버퍼
버퍼는 데이터를 전송하는 장치간의 고속 장치와 저속 장치간의 속도 차이를 극복하기위해 데이터를 임시 저장하는 공간을 말한다.
버퍼를 사용하게 되면 호출 횟수를 줄일수 있어 입출력 성능을 개선할 수 있다.

채널
채널은 서버와 클라이언트 간의 통신 수단을 나타낸다.

읽기 쓰기가 동시에 가능한 양방향 통신으로써 기본적으로 바이트 버퍼를 사용하기에 데이터형에 맞는 전용 메모리 공간을 가지게 된다.

보조스트림 종류

입력출력설명
FilterInputStreamFilterOutputStream필터를 이용한 입출력 처리
BufferedInputStreamBufferedOutputStream버퍼를 이용한 입출력 성능향상
DataInputStreamDataOutputStream기본 자료형으로 데이터 처리가능
SequenceInputStream없음.두개의 스트림을 하나로 연결
LineNumberInputStream없음.읽어온 데이터의 라인번호 카운트
ObjectInputStreamObjectOutputStream데이터를 객체 단위로 읽고쓰는데 사용하며 주로 파일을 이용한 객체 직렬화
없음.PrintStream버퍼를 이용하며 추가적인 print관련 기능사용
PushbackInputStream없음.버퍼를 이용해서 읽어온 데이터 되돌리기 기능

Byte와 Character 스트림

스트림 종류

위에서 설명한 스트림들은 모두 바이트 기반 스트림이다.

문자기반스트림은 바이트기반 스트림이 1byte씩 처리하기 때문에 문자(2byte)의 처리가 어려움을 대신하기 위한 스트림이다.

위에서 설명한 스트림뒤에 들어가는 InputStream, OutputStream을 Reader와 Writer로 치환해주면 문자기반스트림이 된다.
아래는 비교를 위해 작성했다

바이트기반문자기반
FileInputStreamFileReader
FileOutputStreamFileWriter
ByteArrayInputStreamCharArrayReader
ByteArrayOutputStreamCharArrayWriter
PipedInputStreamPipedReader
PipedOutputStreamPipedWriter
StringBufferInputStream(deprecated)StringReader
StringBufferOutputStream(deprecated)StringWriter

표준 스트림 (System.in, System.out, System.err)

System 클래스는 실행시간, 환경과 관련된 속성과 메서드를 제공한다.

System 클래스에 out과 in은 표준 입출력, 에러출력에 관한 클래스 변수, 외부 정의 프로퍼티 및 환경변수 등등 유용한 기능들을 제공한다.

System.in
System.in 의 변수 타입이 InputStream 형태로 지정이 되어있다.

위에서 언급했지만 InputStream은 최상위 클래스이면서 추상 클래스이기 때문에 InputStream은 객체를 생성할 수 없는 클래스다

System.in 을 통해서 접근하는 객체는 JVM이 메모리로 올라오면서 미리 객체를 생성해 두는 대표적인 객체이다. 자료형이 InputStream이기 떄문에 바이트 단위로만 입출력된다.

키보드에서 입력하는 자료는 때에 따라서 두 바이트가 합쳐져야 의미를 가지는 경우가 있다. 그래서 System.in을 통해서 읽을 때는 영문과 한글의 처리를 분리해서 구성해야 잘 인식된다.

System.out
가장 흔하게 System.out.println으로 사용하면서 본 함수이다

System.out 변수는 표준 출력 장치 객체를 가리키는 대표적인 출력 변수이다.

System.out은 PrintStream 타입으로 되어있는데 여기서 PrintStream이란 OutputStream 클래스의 후손 클래스로 Exception을 안전하게 처리할 메소드로만 구성이 되어있다. 그래서 굳이 try-catch 문 같이 따로 처리를 해주지 않아도 괜찮다

System.err
System.err 객체는 표준 에러 출력 장치를 의미한다. 오류가 발생하게 되면 System.err로 알려줘야 하는 내용이 나온다고 생각하면 된다.

System.err 는 PrintStream 클래스 타입으로 System.out을 사용하는 방법과 같다.

파일 읽고 쓰기

public class Main {
    public static void main(String[] args) {
//  try with resources문을 이용해서 자원관리를 했다. 
        try (
                FileWriter fw = new FileWriter("d:\\test1.txt", true);
                BufferedWriter bw = new BufferedWriter(fw);){
//버퍼에 한줄 쓰고 다음라인으로 넘기는 코드
            bw.write("test1");
            bw.newLine();
            bw.write("test2");
            bw.newLine();
//            버퍼에 있는 내용 출력
            bw.flush();
        } catch (IOException e) {
            System.out.println(e);
        }

        try (
                FileReader fr = new FileReader("d:\\test1.txt");
                BufferedReader br = new BufferedReader(fr);
                ){
//  파일에 입력된 내용 확인하고 순차적으로 읽어오기
            String readLine = null;
            while ((readLine = br.readLine()) != null) {
                System.out.println(readLine);
            }

        } catch (IOException e) {
            System.out.println(e);
        }
    }
}

0개의 댓글