ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Java I/O <2 - InputStream>
    언어/자바 2023. 12. 23. 04:05

     

     

    막연하게만 사용하던 I/O를 조금 더 이해해보고자 작성한 글입니다.
    기본적으로 I/O는 O/S 레벨에서 이루어지고 byte를 다룬다는 것을 생각야해합니다.

     

     

    글 작성에 참고한 영상입니다.

    Java IO - Output Streams by Kody Simpson

     

     

     


     

    InputStream

     

    기본적으로 들어온 입력을 byte로 변환해주는 역할을 한다.
    System.in의 read 메소드를 사용해서 콘솔에서 받은 입력을 어떻게 보여주는지 확인해보자.

     

     

    1. read()

    입력된 스트림에서 1byte를 읽어서 int로 된 결과를 반환한다.

     

     

    - 영문 입력 (UTF-8 기준 1Byte 입력)

    class TestInputStream {
      public static void main(String[] args) {
       
       	InputStream in = System.in;
       	int data = in.read();
    
       	System.out.println(data); 
        
      }
    }

     

    위 코드는 아래와 같이 실행된다.

    class TestInputStream {
      public static void main(String[] args) {
       
       	InputStream in = System.in;
        
        // 1. 콘솔에서 a를 입력받는다.
        // a를 설정된 인코딩 방식을 적용해서 byte로 변경한다.
        // 해당 byte를 int 형식으로 반환한다.
      	// a => U+0061 => 01100001
       	int data = in.read();
    
    	// 2. 97을 콘솔에 보여준다.
        // 01100001은 10진수로 97
       	System.out.println(data); 
        
      }
    }

     

    [ 인코딩 ]
    
    컴퓨터는 문자를 2진수로 구성된 byte로 저장해야한다.
    문자를 어떻게 byte형식으로 변경할 것인가에 정의가 인코딩
    UTF-8, UTF-16 등의 방식이 있다.
    
    [ UTF-8 ]
    
    문자를 1byte ~ 4byte까지를 가지는 데이터로 변환하는 방식.
    
    1) byte로 변경해야할 문자를 Unicode에서 code point를 찾는다.
    2) Unicode의 위치에 따라서 1byte ~ 4byte사이의 길이가 결정된다.
    3) 16진수인 code point를 2진수로 변경하여 아래의 방법으로 저장한다.
    3) 저장되는 byte형식
    - 1byte 문자는 0xxxxxxx 으로 구성된다 ( 0 + 7bit ascii )
    - 2byte이상은 첫번째 byte는 110으로 시작되고, 나머지는 10으로 시작된다.

     

     

    - 한글 입력 (UTF-8 기준 3Byte 입력)

    class TestInputStream {
      public static void main(String[] args) {
       
       	InputStream in = System.in;
       	int data = in.read(); // 한글 '참' 입력
    
       	System.out.println(data); 
        
      }
    }

     

    위 코드는 아래와 같이 실행된다.

    class TestInputStream {
      public static void main(String[] args) {
       
       	InputStream in = System.in;
        
        // 1. 콘솔에서 '참'를 입력받는다.
        // '참'을 설정된 인코딩 방식을 적용해서 byte로 변경한다.
        // '참'은 3bytes로 변경되어 입력버퍼에 저장된다.
      	// read()는 입력버터에서 1byte만 읽어온다.
        // 11101100
       	int data = in.read();
    
    	// 2. 236을 콘솔에 보여준다.
        // 11101100은 10진수로 236
       	System.out.println(data); 
        
      }
    }

     

    '참'을 화면에서 보려면 아래와 같이 실행할 수 있다.

    class TestInputStream {
      public static void main(String[] args) {
       
       	   InputStream in = System.in;
            OutputStream out = System.out;
    
            int[] intArr = new int[3];
            
            System.out.println("1: " + in.available());  // 0 - 스트림 길이
            intArr[0] = in.read();	 		     // '참' + 엔터 입력
            					     // '참'의 첫번째 바이트 read
            
            System.out.println("2: " + in.available());  // 3
            intArr[1] = in.read();                       // '참'의 두번째 바이트 read
            
            System.out.println("3: " + in.available());  // 2
            intArr[2] = in.read();                       // '참'의 세번째 바이트 read
            
            System.out.println("4: " + in.available());  // 1 - 엔터로 인한 뉴라인 존재
    
            for (int i = 0; i < intArr.length; i++) {
                out.write(intArr[i]); // '참'의 1 ~ 3번째 바이트 write
               
            }
    
            out.flush(); // '참' 출력
      }
    }

     

     

    2. read(byte[])

    read()의 인자로 byte[ ]을 전달하면 버퍼로 사용할 수 있다.
    read(b)의 결과값은 byte[ ]에 들어간 데이터의 길이를 반환한다.

     

    public static void main(String[] args) throws IOException {
            InputStream in = System.in;
            OutputStream out = System.out;
    
            byte[] b = new byte[8];
    
            int data = 0;
            while((data = in.read(b)) != -1) {
                out.write(b, 0, data);
            }
        }
    
    
    // 풀어서 쓰면
    public static void main(String[] args) throws IOException {
            InputStream in = System.in;
            OutputStream out = System.out;
            
            byte[] b = new byte[8];
    
            int data = 0;
            boolean isOn = true;
            while(isOn) {
                data = in.read(b);
                
                System.out.println("\n data: " + data);  // 읽어들인 데이터의 길이 or -1
                
                if (data != -1) {
                    out.write(b, 0, data);    
                } else {
                    isOn = false; 
                }
            }
        }

     

     


     

    Summary

    • read 함수를 통해서 입력버퍼에 들어있는 1byte 데이터를 가져올 수 있다.
    • read 함수에 byte[ ] 을 전달하면 byte배열에 쓰여진 데이터의 길이를 반환한다.
    • isAvailable 함수를 통해서 입력버퍼에 남은 데이터의 길이를 알 수 있다.
    • 1byte를 읽지만 int 타입으로 변환하여 반환한다.

     

     


    [이미지 출처] 
    https://www.geeksforgeeks.org/java-io-tutorial/ (글 대표 이미지)

     

    [참고 자료]

    https://www.youtube.com/watch?v=eEjkxWo0NtE&list=PLfu_Bpi_zcDO4CdNYNS2Wten1vLuQfgp7&index=3



     

     

    '언어 > 자바' 카테고리의 다른 글

    Java I/O <4 - Network Stream>  (1) 2023.12.25
    Java I/O <3 - FileStream>  (0) 2023.12.25
    Java I/O <1 - OutputStream>  (0) 2023.12.23
    너무 다양한 List를 만드는 방법들..  (1) 2023.12.20
    Queue의 add와 offer의 차이  (0) 2023.12.20
Designed by Tistory.