Java I/O <1 - OutputStream>

devhan·2023년 8월 29일
0

자바 I/O 입문

목록 보기
1/7

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

글 작성에 참고한 영상입니다.
Java IO - Output Streams by Kody Simpson


OutputStream

데이터를 Byte로 변경하여 목적지로 보내는 역할을 한다.
크게 1개의 Byte를 사용하는 것과 Byte[ ]을 사용하는 경우로 나누어서 볼 수 있겠다.

- 단일 Byte 사용

1. byte타입

	class TestOuputStream {
    	public static void main(String[] args) {
        
        	byte b = 75;
        	
            OutputStream out = System.out;
            out.write(b);
            out.flush();  
            
            // 콘솔에 K 출력
        }
    }

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

	class TestOuputStream {
    	public static void main(String[] args) {
        
        	// 1.byte는 signed 8bit의 데이터를 갖는다.
            // 따라서 b의 실제 데이터는 75를 2진수로 변환한 '01001011'이다.
        	byte b = 75; 
        	
            OutputStream out = System.out;
            
            // 2.write에 1byte인 '01001011' 전달한다.
            out.write(b);
            
            // 3.버퍼에 들어있는 내용을 강제로 목적지로 보낸다.
            out.flush();  
 
            
            // 4.터미널에서 전달받은 출력스트림을 인코딩한다.
            // 5.해당 결과를 기반으로 unicode에서 매치되는 글자를 찾는다.
            // 6.해당 글자를 console에 보여준다.
            
            
        
        }
    }

UTF - 8

가변길이 인코딩 방식으로 문자를 1byte에서 4byte로 인코딩한다.
'01001011'은 0으로 시작하기때문에 1Byte 데이터임을 알 수 있다.
'01001011'를 Unicode 코드포인트로 변경하면 U+004B이다.
( 01001011 => 0100 1011 => 4B => U+004B )
U+004B는 K를 의미

2. int 타입

	class TestOuputStream {
    	public static void main(String[] args) {
        
        	int i = 75;
        	
            OutputStream out = System.out;
            out.write(b);
            out.flush();  
   
            // 콘솔에 K 출력
        }
    }

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

	class TestOuputStream {
    	public static void main(String[] args) {
        	
            // 1. int는 signed 32bit의 데이터를 갖는다.
        	int i = 75;
        	
            OutputStream out = System.out;
            
            // 2. write(int a)의 경우는 32bit 중 하위 8bit만 사용한다.
            // 공식 문서 참고
            out.write(b);
            out.flush();  
            
            // 3. 이후 진행은 byte와 동일
        }
    }

3. char 타입

	class TestOuputStream {
    	public static void main(String[] args) {
        
        	char c = 75;
            char c1 = 'K';
        	
            OutputStream out = System.out;
            out.write(c);
            out.write(c1);
            out.flush();  
            
            // 콘솔에 K 출력
        }
    }

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

	class TestOuputStream {
    	public static void main(String[] args) {
        	
            // 1. char은 unsigned 16bit 데이터 타입
            // 기본적으로 unicode의 codepoint를 저장하기 위해 고안된 타입
            // 컴파일 타임에 숫자인지 문자 리터럴인지 확인
            // 숫자의 경우 해당 숫자를 16bit 데이터로 할당
            // 00000000 01001011 저장
        	char c = 75;
            
            // 문자리터럴의 경우, 해당 문자열을 unicode에서 찾고
            // 해당 코드포인트를 16bit로 변경하여 할당
            // U+004B => 0100 1011 => 00000000 01001011 저장 
            char c1 = 'K';
        	
            OutputStream out = System.out;
            
            // write()는 int 혹은 byte[]을 입력으로 받는다.
            // char 타입을 write에 넣으면 자동으로 int로 변경된다.
            // 16bit char이 32bit int로 변경되고, 하위 8bit만 사용된다.
            out.write(c);
            out.write(c1);
            out.flush();  
        }
    }

Type Promotion

자바는 기본적으로 데이터의 손실이 발생하지 않는다면, 더 적은 크기의 데이터 타입은 더 큰 크기의 데이터타입으로 변경이 가능하다.

1. char => int (o)

char c = 'K' (00000000 01001011);
int i = c (00000000 000000000 00000000 01001011);

2. int => float (o)

데이터의 손실이 없기때문에 변환된다.

int i = 3; (00000000 000000000 00000000 01001011)
float f = i; (0 10000000 10000000000000000000000)

3. float => int (x)

int로 변경할 경우, 소수점이 사라지는데 이는 데이터 손실을 의미한다.
따라서 개발자가 데이터 손실을 인지한다는 것을 의미하는 casting을 해줘야 사용가능하다.

float f = 3.3;
int i = f; // x
int i2 = (int) f; // o

- Byte[] 사용

1. byte[]

	class TestOutputStream {
    	public static void main(String[] args) {
       		
            byte[] b = new byte[4];

            for (int i = 0; i < b.length; i++) {
                int character = 65 + i;
                b[i] = (byte) character;
            }

            OutputStream out = System.out;

            out.write(b);
            out.flush();
        	
            // 콘솔에 ABCD 출력
        }
    }

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

	class TestOutputStream {
    	public static void main(String[] args) {
       		// 1. 보통은 InputStream을 통해 전달받은 byte배열을 사용
            // 테스트를 위한 byte배열 생성
            byte[] b = new byte[4];
			
            // 2. byte배열에 65 ~ 68 의 byte를 넣는다.
            for (int i = 0; i < b.length; i++) {
                int character = 65 + i;
                b[i] = (byte) character;
            }

            OutputStream out = System.out;

			// 3. byte[]을 받는 경우, 해당 배열을 순회하면서 하나씩 write를 수행
            // 콘솔에 ABCD 출력
            out.write(b);
            out.flush();
        
        }
    }

2. byte[]와 구간 설정

	class TestOutputStream {
    	public static void main(String[] args) {
       		
            byte[] b = new byte[4];

            for (int i = 0; i < b.length; i++) {
                int character = 65 + i;
                b[i] = (byte) character;
            }

            OutputStream out = System.out;

            out.write(b, 1, 2); 
            out.flush();
        	
            // 콘솔에 BC 출력
        }
    }

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

	class TestOutputStream {
    	public static void main(String[] args) {
       		
            byte[] b = new byte[4];
			
            for (int i = 0; i < b.length; i++) {
                int character = 65 + i;
                b[i] = (byte) character;
            }

            OutputStream out = System.out;

			// 위 코드와 모두 동일하고,
            // 2번째 인자는 시작 index, 3번째 인자는 길이이다.
            // byte 배열의 1번 인덱스부터 2개를 보여준다는 의미
            out.write(b, 1, 2);
            out.flush();
        
        }
    }

Sumamry

  • 개념적으로는 write() 메소드는 1byte를 입력받고 1byte를 출력버퍼에 쓴다.
  • 구현은 int를 입력 받고 있지만, byte보다 큰 타입은 int로 변경되고 하위 8bit만 사용한다.
  • write() 메소드는 내부적으로 system call을 호출해서 출력버퍼에 입력한다.
  • write 메소드는 출력버퍼가 가득 찰 때가지 1byte씩 입력한다.
  • 출력버퍼가 가득차기 전에 스트림을 흘려보내려면 flush() 메소드를 사용한다.
profile
한번에 한가지씩

0개의 댓글

관련 채용 정보