본문 바로가기

Java/기본

[Java] IO스트림 사용하기 - InputStream, OutputStream

IO 스트림은 데이터를 입력(input)과 출력(output)에 대한 내용이다. java.io 패키지에서 제공되는 클래스를 활용해 코드를 작성할 수 있다. 스트림은 일방향의 특징을 가지는 데이터 흐름이다. 역방향으로 데이터가 전송될 수 없기 때문에 input, output 을 위한 코드가 따로 존재하게 된다.

 

입출력의 단위는 크게 바이트, 문자로 나뉜다.

  • 바이트는 이미지, 오디오, 동영상 등의 바이너리 파일이 해당된다. 크기는 1byte
  • 문자는 한글, 한자 등이 해당된다. 크기는 2byte
    입력 출력
바이트 최상위 클래스 InputStream OutputStream
하위 클래스 AudioInputStream
ByteArrayInputStream
FileInputStream
FilterInputStream
InputStream
ObjectInputStream
PipedInputStream
SequenceInputStream
StringBufferInputStream
ByteArrayOutputStream
FileOutputStream
FilterOutputStream
ObjectOutputStream
OutputStream
PipedOutputStream
문자 최상위 클래스 Reader Writer
하위 클래스 BufferedReader
CharArrayReader
FilterReader
InputStreamReader
PipedReader
StringReader
BufferedWriter
CharArrayWriter
FilterWriter
OutputStreamWriter
PipedWriter
PrintWriter
StringWriter

 

 

1. InputStream

주요메서드

메서드 내용
int  available() 스트림에서 읽을 수 있는 바이트 개수 리턴
void  close() 스트림 닫고 자원해제
abstract int  read() 1 바이트를 읽고 읽은 바이트 리턴
int  read(byte[] b) 지정된 배열 크기만큼 읽고 버퍼배열에 저장, 읽은 개수 리턴
int  read(byte[] b, int off, int len) -지정된 배열 크기만큼 읽고 버퍼배열에 저장, 읽은 개수 리턴
-읽을 바이트의 시작과 개수를 지정할 수 있음

 

 

  • read()

아래 코드를 보자. 콘솔로 입력한 글자를 바이트로 읽어들이는 코드이다.

스트림 사용시에는 IOException 이 발생하기 때문에 try -catch 문으로 감싸거나 throws 구문이 필요하다.

public class Test01 {
    //IOException 이 발생한다. 예외 throws 처리
    public static void main(String[] args) throws IOException{
        System.out.println("start");

        InputStream is = new DataInputStream(System.in);
        int a = is.read();
        System.out.println("바이트 읽기: "+ a);
        byte b = (byte) a;
        System.out.println("바이트 char변환 : "+ (char)b);

        //스트림 사용한 뒤에는 닫아주기
        is.close();
        System.out.println("end");
    }
}

 

실행 결과

start
1
바이트 읽기: 49
바이트 char변환 : 1
end

 

다른 코드를 보자. 아래는 text 파일의 내용을 읽는 코드이다.

D:/Programming/_temp/ 폴더의 testIn.txt 은 아래와 같다.

 

 

public class Test02 {
    public static void main(String[] args) throws IOException {
        System.out.println("start");
        InputStream is = new FileInputStream("D:/Programming/_temp/testIn.txt");
        int readByte = 0;
        while((readByte = is.read()) != -1){
            byte b = (byte) readByte;
            System.out.println(readByte+ " char변환 : "+ (char)b);
        }

        is.close();
        System.out.println("end");
    }
}

 

실행 결과

-inputStream은 1바이트씩 끊어서 바이트를 인식한다. 문자는 2바이트이기 때문에 정상적으로 인식되지 않는다.

start
49 char변환 : 1
50 char변환 : 2
51 char변환 : 3
13 char변환 : 
10 char변환 : 

97 char변환 : a
98 char변환 : b
99 char변환 : c
13 char변환 : 
10 char변환 : 

234 char변환 : ?
176 char변환 : ?
128 char변환 : ?
235 char변환 : ?
130 char변환 : ?
152 char변환 : ?
235 char변환 : ?
139 char변환 : ?
164 char변환 : ?
end

 

 

  • read(byte[] b)
public class Test03 {
    public static void main(String[] args) throws IOException {
        System.out.println("start");
        InputStream is = new FileInputStream("D:/Programming/_temp/testIn.txt");
        byte[] byteArr = new byte[4];
        int readByte = 0;
        while((readByte = is.read(byteArr)) != -1){
            for(byte b : byteArr){
                System.out.println(b + " | "+ (char) b);
            }
        }
        is.close();
        System.out.println("end");
    }
}

 

실행 결과

start
49 | 1
50 | 2
51 | 3
13 | 
10 | 

97 | a
98 | b
99 | c
13 | 
10 | 

-22 | ?
-80 | ?
-128 | ?
-21 | ?
-126 | ?
-104 | ?
-21 | ?
-117 | ?
-92 | ?
-104 | ?
end

 

 

  • read(byte[] b, int off, int len)
public class Test04 {
    public static void main(String[] args) throws IOException {
        System.out.println("start");
        InputStream is = new FileInputStream("D:/Programming/_temp/testIn.txt");
        byte[] byteArr = new byte[4];
        int readByte = 0;
        while((readByte = is.read(byteArr, 0, byteArr.length)) != -1){
            for(byte b : byteArr){
                System.out.println(b + " | "+ (char) b);
            }
        }
        is.close();
        System.out.println("end");
    }
}

 

실행 결과

start
49 | 1
50 | 2
51 | 3
13 | 
10 | 

97 | a
98 | b
99 | c
13 | 
10 | 

-22 | ?
-80 | ?
-128 | ?
-21 | ?
-126 | ?
-104 | ?
-21 | ?
-117 | ?
-92 | ?
-104 | ?
end

 

2. OutputStream

 

주요 메서드

메서드 내용
void  close() 스트림 닫고 자원해제
void  flush() 버퍼를 비우기. 버퍼내의 모든 데이터 출력
void  write(byte[] b) 바이트배열 출력하기
void  write(byte[] b, int off, int len) 바이트배열 출력하기(시작과 끝 설정)
abstract void  write(int b) 바이트 1개를 출력하기

 

 

  • write(int b)
public class Test01 {
    public static void main(String[] args) throws IOException {
        System.out.println("start");
        OutputStream os = new FileOutputStream("D:/Programming/_temp/testOut.txt");
        byte[] sendDate = "ABC123가나".getBytes();
        for(byte b: sendDate){
            os.write(b);
        }
        os.flush();
        os.close();
        System.out.println("end");
    }
}

 

실행 결과 - 콘솔

start
end

실행 결과 - testOut.txt

ABC123가나

 

 

  • write(byte[] b)
public class Test02 {
    public static void main(String[] args) throws IOException {
        OutputStream os = new FileOutputStream("D:/Programming/_temp/testOut.txt");
        byte[] sendDate = "ABC234홍길동".getBytes();
        os.write(sendDate);
        os.flush();
        os.close();
    }
}

 

실행 결과 - testOut.txt

ABC234홍길동

 

 

  • write(byte[] b, int off, int len)
public class Test03 {
    public static void main(String[] args) throws IOException {
        OutputStream os = new FileOutputStream("D:/Programming/_temp/testOut.txt");
        byte[] sendDate = "ABC12345".getBytes();
        //write(byte[] b) 과 동일한 결과가 나온다
        os.write(sendDate, 0, sendDate.length);
        os.flush();
        os.close();
    }
}

 

실행 결과 - testOut.txt

ABC12345

 

 

 

  • 바이트 배열의 시작과 끝을 설정하기
public class Test04 {
    public static void main(String[] args) throws IOException {
        OutputStream os = new FileOutputStream("D:/Programming/_temp/testOut.txt");
        byte[] sendDate = "ABC12345".getBytes();
        os.write(sendDate, 3, 3);
        os.flush();
        os.close();
    }
}

 

실행 결과 - testOut.txt

123

 

 

 

3. Reader

 

주요 메서드

메서드 내용
int read() 문자 한개 읽기. 읽은 문자값을 유니코드 값으로 리턴한다
읽은 값이 없으면 -1 리턴
int read(char[] cbuf) 문자를 하나씩 읽어 cbuf 에 저장하고 읽은 문자개수 리턴
abstract int read(char[] b, int start, int length) 문자를 length 만큼 읽기, cbuf의 start 부터 저장. 읽은 문자개수 리턴
abstract void close() 스트림 닫고 자원해제

 

아래 코드를 보자

public class Test03 {
    public static void main(String[] args) throws IOException {
        String fileOut = "D:/Programming/_temp/testWrite.txt";
        Writer fw = new FileWriter(fileOut);

        char[] charArr = "123abc홍길동".toCharArray();
        fw.write(charArr);

        fw.flush();
        fw.close();
    }
}

 

실행 결과

-지정한 위치에 파일이 생성됨

 

4. Writer

주요 메서드 내용
abstract void write(int c) int 값을 char로 변환해서 쓰기
void write(char[] cbuf) char 배열 내용 쓰기
abstract void write(char[] cbuf, int start, int length) char 배열 내용 쓰기. start부터 length 만큼
void write(String str) str 쓰기
abstract void flush() 버퍼가 가득차 있지 않아도 버퍼 비우기
abstract void close() 스트림 닫고 자원해제

 

아래 코드를 보자

public class Test01 {
    public static void main(String[] args) throws IOException {
        String fileName = "D:/Programming/_temp/test01.txt";
        Writer fw = new FileWriter(fileName);
        String message = "hello 홍길동";
        fw.write(message);
        fw.close();
    }
}

 

실행 결과

-해당 경로에 파일이 생성된다

 

 

 

 

5. Console 클래스

콘솔로 문자열을 입력받아 처리할 수 있는 클래스이다.

 

System 정적메서드로 콘솔 호출하기

Console console = System.console();

 

System.in 호출해 InputStream으로 받기

public class Test01 {
    public static void main(String[] args) throws IOException {
        System.out.println("start");
        InputStream istream = System.in;

        int a;
        while((a = istream.read()) != -1){
            if(a == 13 || a == 10) { break; }   //캐리지 리턴 걸러내기
            System.out.println((char) a);
        }
        System.out.println("end");
    }
}