chap 14. 입출력 스트림

최준영·2021년 12월 2일
0

자바

목록 보기
8/8
post-custom-banner

1. 입출력 스트림


  • 자바에서 데이터는 스트림을 통해 입출력된다.
  • 키보드 / 파일 / 프로그램으로 입력받고, 모니터 / 파일 / 프로그램에 출력한다.

1) 입출력 스트림의 종류

(1) 바이트 기반 스트림

  • 그림, 멀티미디어 등의 바이너리 데이터를 읽고 출력할 때 사용

바이트 출력 스트림

  • 종류 : FileOutputStream, PrintStream, BufferedOutputStream, DataOutputStream

  • 최상위 클래스 : OutputStream

  • 주요 메소드

    리턴타입메소드 이름설명
    voidwrite(int b)1byte를 출력한다. 매개변수로 주어지는 int에서 끝 1byte만 출력 스트림으로 보낸다.
    voidwrite(byte[] b)배열 b의 모든 바이트를 출력
    voidwrite(byte[] b, int off, int len)b[off]부터 len개의 바이트를 출력
    voidflush()출력 버퍼에 잔류하는 모든 바이트 출력
    voidclose()출력 스트림을 닫는다.

바이트 입력 스트림

  • 종류 : FileInputStream, BufferedInputStream, DataInputStream

  • 최상위 클래스 : InputStream

  • 주요 메소드

    리턴타입메소드 이름설명
    intread()1byte를 읽고 읽은 바이트를 리턴. 따라서 리턴된 4byte 중 끝 1byte에만 데이터가 들어있다.
    intread(byte[] b)읽은 바이트를 매개값으로 주어진 배열에 저장하고 읽은 바이트 수를 리턴
    intread(byte[] b, int off, int len)len개의 바이트를 읽고 매개값으로 주어진 배열에서 b[off]에서 len개까지 저장. 읽은 바이트 수 리턴
    voidclose()입력 스트림을 닫는다.

(2) 문자 기반 스트림

  • 문자 데이터를 읽고 출력할 때 사용

문자 출력 스트림

  • 종류 : FileWriter, PrintWriter, BufferedWriter, OutputStreamWriter

  • 최상위 클래스 : Writer

  • 주요 메소드

    리턴타입메소드 이름설명
    voidwrite(int c)매개값으로 주어진 한문자를 출력스트림으로 보냄. 매개변수 int에서 끝 2byte(문자)만 보낸다.
    voidwrite(char[] cbuf)매개값으로 주어진 배열의 모든 문자를 보냄
    voidwrite(char[] cbuf, int off, int len)c[off]부터 len개의 문자를 보냄
    voidwrite(String str)매개값으로 주어진 문자열을 보낸다.
    voidwrite(String str, int off, int len)str의 off순번부터 len개의 문자를 보낸다.
    voidflush()버퍼에 잔류하는 모든 문자 출력
    voidclose()출력 스트림을 닫는다.

문자 입력 스트림

  • 종류 : FileReader, BufferedReader, InputStreamReader

  • 최상위 클래스 : Reader

  • 주요 메소드

    리턴타입메소드 이름설명
    intread()1개의 문자를 읽고 리턴. 입력 스트림으로부터 1개의 문자(2byte)를 읽고 int 타입으로 리턴하므로 끝의 2byte에 문자 데이터가 들어있음.
    intread(char[] cbuf)읽은 문자들을 매개값으로 주어진 문자 배열에 저장하고 읽은 문자 수를 리턴
    intread(char[] cbuf, int off, int len)len개의 문자를 읽고 매개값으로 주어진 문자 배열에서 cbuf[off]부터 len개까지 저장. 그리고 읽은 문자 수 리턴
    voidclose()입력 스트림을 닫는다.

2. 보조 스트림


  • 기본 스트림인 InputStream/OutputStream, Reader/Writer를 직접 사용해서 데이터를 입출력 할 수 있다.
  • 데이터를 변환해서 입출력하거나, 데이터의 출력 형식을 지정하고 싶은 경우, 그리고 입출력 성능을 향상시키고 싶은 경우가 있다. 이럴 때 기본 스트림에 보조스트림을 연결하여 사용하면 이런 기능들을 편리하게 수행할 수 있다.

1) 보조스트림 연결

보조스트림 변수 = new 보조스트림(연결 스트림)

// ex)
InputStream is = ...;
Input Stream reader = new InputStreamReader(is);
  • 보조스트림을 연속적으로 연결할 수도 있다.
InputStream is = System.in;
InputStreamReader reader = new InputStreamReader(is);
BufferedReader br = new BufferedReader(reader);

2) 문자 변환 보조 스트림

  • 소스 스트림이 바이트 기반 스트림이면서 입출력 데이터가 문자라면 Reader와 Writer로 변환해서 사용하는 것을 고려할 수 있다.
    • 문자 입출력은 Reader와 Writer가 편리하기 때문이다.

OutputStreamWriter

Writer writer = new OutputStreamWriter(바이트 기반 출력 스트림);
  • 바이트 기반 출력 스트림에 연결되어 문자 출력 스트림인 Writer로 변환하는 보조 스트림이다.

InputStreamReader

Reader reader = new InputStreamReader(바이트 기반 입력 스트림);
  • 바이트 기반 입력 스트림에 연결되어 문자 입력 스트림인 Reader로 변환하는 보조 스트림이다.

3) 성능 향상 보조 스트림

  • 프로그램의 실행 성능은 입출력이 가장 늦은 장치를 따라간다.
    • CPU와 메모리가 아무리 뛰어나도 하드 디스크의 입출력이 늦어지면 프로그램의 실행 성능은 하드 디스크의 처리 속도에 맞춰진다.
    • 네트워크로 데이터 전송하는 것도 마찬가지이다. 느린 데이터 환경이라면 컴퓨터 사양이 아무리 좋아도 메신저와 게임의 속도는 느리다.
  • 프로그램이 입출력 소스와 직접 작업하지 않고 중간에 메모리 버퍼와 작업함으로써 실행 성능을 향상시킬 수 있다.
    • 프로그램은 직접 하드디스크에 데이터를 보내지 않고 메모리 버퍼에 보냄으로써 쓰기 속도가 향상된다.
    • 버퍼의 데이터가 꽉 차면 한꺼번에 하드 디스크로 보냄으로써 출력 횟수를 줄여준다.
  • 기본적으로 출력 스트림은 내부에 작은 버퍼를 가지고 있다. 하지만 이것으로 불충분하므로 보조 스트림 중에서 메모리 버퍼를 추가로 제공하는 것들이 있다.
    • 바이트 기반 스트림 : BufferInputStream, BufferedOutputSteram
    • 문자 기반 스트림 : BufferedReader, BufferedWriter

BufferedOutputStream, BufferedWriter

  • BufferedOutputStream은 바이트 기반 출력 스트림에 연결되어 버퍼를 제공해주는 보조 스트림이다.
  • BufferedWriter은 문자 기반 출력 스트림에 연결되어 버퍼를 제공해주는 보조 스트림이다.
  • 둘다 프로그램에서 전송한 데이터를 내부 버퍼에 쌓아 두었다가 버퍼가 꽉 차면, 버퍼의 모든 데이터를 한꺼번에 보낸다.
BufferedOutputStream bos = new BufferedOutputStream(바이트 기반 출력 스트림);
BufferedWriter bw = new BufferedWriter(문자 기반 출력 스트림);

BufferInputStream, BufferedReader

  • BufferInputStream은 바이트 기반 스트림에 연결되어 버퍼를 제공해주는 보조 스트림이다.
  • BufferedReader은 문자 기반 입력 스트림에 연결되어 버퍼를 제공해주는 보조 스트림이다.
    • readLine() 메소드로 Enter키(\r + \n) 이전의 모든 문자열을 읽고 리턴한다. 더이상 읽을 라인이 없다면 null을 리턴한다.
  • 둘 다 입력 소슬부터 자신의 내부 버퍼 크기만큼 데이터를 미리 읽고 버퍼에 저장해둔다.
BufferedInputStream bis = new BufferedInputStream(바이트 기반 출력 스트림);
BufferedReader br = new BufferedReader(문자 기반 입력 스트림);

4) 기본 타입 입출력 보조 스트림

  • DateInputStream과 DateOutputStream 보조 스트림을 연결하면 기본 타입인 boolean, char, short, int, float, double을 입출력 할 수 있다.
  • 데이터 타입의 크기가 모두 다르므로 DataOutputStream으로 출력한 데이터를 다시 DataInputStream으로 읽어올 때는 출력한 순서와 동일한 순서로 읽어야 한다.
    • ex) 출력 순서가 int -> boolean -> double이라면 읽을 때는 int -> boolean -> double이어야 한다.
DataInput Stream dis = new DataInputStream(바이트 기반 입력 스트림);
DataOutputStream dos = new DataOuputStream(바이트 기반 출력 스트림);

주요 메소드

DataInputStream

  • boolean readBoolean(), double readDouble(), String readUTF() 등

DataOutputStream

  • void writeBoolean(boolean v), void writeByte(int v), void writeShort(int v), void writeUTF(String str) 등

5) 프린터 보조 스트림

  • PrintStream과 PrintWriter는 프린터와 유사하게 출력하는 print(), println() 메소드를 가지고 있는 보조 스트림이다.
  • PrintStream은 바이트 기반 출력 스트림과 연결되고, PrintWriter는 문자 기반 출력 스트림과 연결된다.
  • 콘솔 출력 스트림인 System.out이 printStream 타입이다.
  • PrintStream의 Println() 메소드로 출력한 내용은 BufferedReader의 readLine()으로 읽으면 편리하다.
    • println()은 개행 문자를 포함하여 출력하고, readLine()은 개행 문자 앞까지 읽기 때문이다.
PrintStream ps = new PrintStream(바이트 기반 출력 스트림);
PrintWriter pw = new PrintWriter(문자 기반 출력 스트림);

6) 객체 입출력 보조 스트림

  • ObjectOutputStream과 ObjectInputStream 보조 스트림을 연결하면 메모리에 생성된 객체를 파일 또는 네트워크로 출력할 수 있다.

(1) ObjectOutputStream

ObjectOutputStream oos = new ObjectOutputStream(바이트 기반 출력 스트림);
  • ObjectOutputStream은 객체를 직렬화한다.
    • 직렬화란 객체를 바이트 배열로 만드는 것을 말한다.
  • oos.writeObject(객체) : 객체를 직렬화 해서 출력 스트림으로 보낸다.

(2) ObjectInputStream

ObjectInputStream ois = new ObjectInputStream(바이트 기반 입력 스트림);
  • ObjectInputStream은 객체를 역직렬화 한다.
    • 역직렬화란 바이트 배열을 다시 객체로 복원하는 것을 말한다.
  • 객체타입 변수 = (객체타입) ois.readObject() : 입력 스트림에서 읽은 바이트를 역직렬화해서 다시 객체로 복원해서 리턴한다. 리턴 타입이 Object이기 때문에 원래 타입으로 강제 변환해야한다.

Serializable 인터페이스

  • 자바는 java.io.Serializable 인터페이스를 구현한 객체만 직렬화한다.
  • Serializable 인터페이스는 메소드 선언이 없는 인터페이스이다.
  • 객체를 파일로 저장하거나, 네트워크로 전송할 목적이라면 개발자는 클래스를 선언할 때 implements Serializable을 추가해야 한다.
    • 개발자가 JVM에게 직렬화 해도 좋다고 승인하는 역할을 한다.
public class XXX implements Serializable{...}

3. 입출력 관련 API


  • 콘솔은 시스템을 사용하기 위해 키보드로 입력받고 모니터로 출력하는 소프트웨어를 말한다.
    • 유닉스나 리눅스 운영체제는 터미널에 해당된다.
    • 윈도우 운영체제는 명령 프롬프트에 해당된다.
  • 자바는 콘솔로부터 데이터를 입력받을 때 System.in을 사용하고, 콘솔에 데이터를 출력할 때 System.out을 사용한다. 그리고 에러를 출력할 때에는 System.err를 사용한다.

1) System.in 필드

  • System 클래스의 in 정적필드는 InputStream 타입의 필드이므로 InputStream 변수로 참조할 수 있다.
InputStream is = System.in;
int keyCode = is.read(); // 1byte를 읽는다.
  • 라인 단위로 전체 문자열을 읽는 방법
InputStream is = System.in;
Reader reader = new InputStream(is);
BufferedReader br = new BufferedReader(reader);

// 한줄로 작성
BufferedReader br = new BufferedReader(new InputStream(System.in));

// 메소드 사용
String lineStr = br.readLine();

2) System.out 필드

  • System 클래스의 out 정적필드는 PrintStream 타입의 필드이다.
  • 따라서 PrintStream이 제공하는 print(), println(), printf()와 같은 메소드를 이용해서 모니터로 출력할 수 있다.

3) Scanner 클래스

  • 해당 클래스는 문자 파일이나 바이트 기반 입력 스트림에서 라인 단위 문자열을 쉽게 읽도록 하기 위해 java.util 패키지에서 제공하는 클래스이다.
    • 입출력 스트림도 아니고, 보조 스트림도 아니다.
  • 보조 스트림 없이 쉽게 라인 단위의 문자열을 읽을 수 있다.
    • 하지만 성능은 BufferedReader를 사용한 것이 훨씬 빠르다.
Scanner scanner = new Scanner(Sytem.in);
String InputData = scanner.nextLine(); // 이외에도 여러 타입을 받을 수 있다.

4) File 클래스

  • java.io 패키지에서 제공하는 File 클래스는 파일 및 폴더(디렉토리) 정보를 제공해주는 역할을 한다.
File file = new File("C:/Temp/file.txt");
File file = new File("C:\\Temp\\file.txt");
  • 객체 생성시 문자열 경로를 제공해야 한다.
  • 윈도우에서는 \ 또는 /를 둘 다 사용할 수 있고, 유닉스나 리눅스에서는 /를 사용한다.
  • File 객체를 생성했다고 해서 파일이나 폴더가 생성되는 것은 아니다. 그리고 제공되는 문자열 경로에 실제 파일이나 폴더가 없더라도 예외가 발생하지 않는다.
    • 해당 경로에 실제로 파일이나 폴더가 있는지 확인하려면 boolean isExist = file.exists()를 사용하면 된다.
  • 파일 또는 폴더의 정보를 얻기 위해 File 객체를 단독으로 사용할 수 있지만, 파일 입출력 스트림(FileInputStream, FileOutputStream, FileReader, FileWriter) 객체를 생성할 때 경로 정보를 제공할 목적으로도 사용한다.
File file = new File("C:/Temp/file.txt");
FileInputStream fis = new FileInputStream(file);
profile
do for me
post-custom-banner

0개의 댓글