1.버퍼
- NIO에서는 데이터를 입출력하기 위해서 항상 버퍼를 사용한다.
- 버퍼는 읽고 쓰기가 가능한 메모리 배열이다.
Buffer 종류
- Buffer는 저장되는 데이터 타입에 따라 분류될 수 있고, 어떤 메모리를 사용하느냐에 따라서 다이렉트(Direct)와 넌다이렉트(NonDirect)로 분류 할 수 있다.
데이터 타입에 따른 버퍼
- NIO버퍼는 저장되는 데이터 타입에 따라서 별도의 클래스로 제공
- 버퍼 클래스들은 Buffer 추상 클래스를 모두 상속
- 버퍼 클래스의 이름을 보면 어떤 데이터가 저장되는 버퍼 인지 쉽게 알 수 있다.
- MappedByteBuffer는 ByteBuffer의 하위 클래스로 파일의 내용에 랜던하게 접하기 위해서 파일의 내용을 메모리와 맵핑 시킨 버퍼
넌다이렉트 다이렉트 버퍼
- 버퍼가 사용하는 메모리의 위치에 따라 구분됨
넌다이렉트 버퍼 : JVM이 관리하는 힙 메모리 공간을 이용하는 버퍼
- 버퍼 생성 시간 빠름, 버퍼 크기 작음, 입출력 성능 낮다.
다이렉트 버퍼 : 운영체제가 관리하는 메모리 공간을 이용하는 버퍼
- 버퍼 생성 시간 느림, 대용량 버퍼 생성 가능, 입출력 유리
Buffer 생성
- 각 데이터 타입별로 넌다이렉트 버퍼를 생성하기 위해서는 각 Buffer클래스의 allocte()와 wrap 메소드를 호출하면 됨, 다이렉트 버퍼는 ByteBuffer의 allocateDirect()메소드를 호출하면 된다.
allocate() 메소드
- 위에 언급했듯 allocate() 메소드는 JVM 힙 메모리에 넌다이렉트 버퍼를 생성한다.
리턴 타입 | 메소드(매개 변수) | 설명 |
XXXBuffer | XXXBuffer.allocate(int capacity) | capacity개 만큼의 XXX(타입)값을 저장 |
ex. 최대 100개의 바이트를 저장하는 ByteBuffer 생성, 최대 100개의 문자를 저장하는 CharBuffer 생성 코드
ByteBuffer byteBuffer = ByteBuffer.allocate(100);
CharBuffer charBuffer = CharBuffer.allcate(100);
wrap() 메소드
- 각 타입별 Buffer클래스는 모두 wrap()메소드를 가지고 있다.
- wrap()메소드는 이미 생성되어 있는 자바 배열을 래핑해서 Buffer객체를 생성한다.
- 자바 배열은 JVM힙 메모리에 생성되므로 wrap()은 넌다이렉트 버퍼를 생성한다.
ex. 길이 100인 byte[]를 ByteBuffer로 생성, 길이 100인 char[]를 이용하여 CharBuffer 생성
byte[] byteArray = new byte[100];
ByteBuffer byteBuffer = ByteBuffer.wrap(byteArray);
char[] charArray = new char[100];
CharBuffer charBuffer = CharBuffer.wrap(charArray);
- 배열의 일부 데이터만 가지고 Buffer 객체를 생성할 수도 있다.
byte[] byteArray = new byte[100];
ByteBuffer byteBuffer = ByteBuffer.wrap(byteArray, 0, 50); //0인덱스부터 50개만 버퍼로 생성
allocateDirect() 메소드
- 운영체제가 관리하는 메모리에 다이렉트 버퍼를 생성한다.
- 이 메소드 각 타입별 Buffer 클래스에는 없고, ByteBuffer에만 제공된다.
- 우선 ByteBuffer의 allocateDirect()메소드로 버퍼 생성한 다음 asXXXBuffer() 형태에 메소드를 붙여 해당 타입을 지정
ex.
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(100); // 100개의 byte값 저장 가능
CharBuffer charBuffer = ByteBuffer.allocateDirect(100).asCharBuffer(); // 50개의 char값 저장 가능 (byte*2 = char)
IntBuffer intBuffer = ByteBuffer.allocateDirect(100).asIntBuffer();// 25개의 int값 저장 가능 (byte*4 =int)
Buffer의 위치 속성
- Buffer의 사용 방법을 알기 위해서 Buffer의 위치 속성 개념과 위치 속성이 언제 변경되는지 알고 있어야 한다.
Buffer 사용을 위한 관련 속성
위 속성의 관계는 0 <= mark <= position <= limit <= capacity 이다
- 위 속성들은 생성된 버퍼에 데이터를 쓰거나 읽을 때 변화는 버퍼의 위치들을 말한다.
position : 데이터를 쓸때 버퍼의 배열에 데이터를 하나씩 넣는다. position은 데이터를 넣을 위치를 알려준다.
limit : 데이터를 쓰기 상태에서 flip()메소드를 호출하면 읽기 상태로 변경되는데 이때 position이 있던 위치가 limit이 되어 자리를 표시
capacity : 버퍼 생성 시 지정해준 버퍼의 크기
mark : mark() 메소드로 mark를 정해주면 reset()메소드를 사용하면 mark가 있던 자리로 position이 온다.
Buffer 메소드
Buffer 공통 메소드
- 각 타입별 버퍼 클래스는 Buffer 추상 클래스를 상속한다. Buffer 추상 클래스는 모든 버퍼가 공통적으로 가져야 할 메소드들이 정의됨
데이터를 읽고 저장하는 메소드
- 버퍼에 데이터를 저장하는 메소드는 put()이고, 데이터를 읽는 메소드는 get()이다
- 이 메소드는 Buffer 추상 클래스에 없고, 각 타입별 하위 Buffer 클래스가 가지고 있다.
- get()과 put() 메소드는 상대적(Relative)과 절대적(Absolute)으로 구분된다.
상대적 get()과 put()메소드 : posotion을 이용해서 데이터를 읽고 저장
절대적 get()과 put()메소드 : 버퍼 배열의 인덱스를 가지고 데이터를 읽고 저장
※각 타입 버터 클래스별로 get(), put()있는다. 종류는 많으나 같은 내용이 반복되므로 생략한다.
Buffer 변환
- 체널이 데이터를 읽고 쓰는 버퍼는 모두 ByteBuffer이다.
- 채널을 통해 읽은 데이터를 복원하려면 ByteBuffer를 문자열 또는 다른 타입 버퍼(CharBuffer, ShortBuffer 등등)으로 변환해야 함
- 반대로 문자열 또는 다른 타입 버퍼의 내용을 채널을 통해 쓰고 싶다면 ByteBuffer로 변환 해야 한다.
ByteBuffer <-> String
- 채널을 통해 문자열을 파일이나 네트워크로 전송하려면 특정 문자셋으로 인코딩해서 ByteBuffer로 변환해야함
- 파일과 네트워크 운영체제로 주고 받기 때문에
- 이를 위해 java.nio.charset.Charset 객체가 필요
Charset 생성 방법 2가지
Charset charset = Charset.forName("UTF-8"); //매개값으로 주어진 문자셋
Charset charset = Charset.defaultCharset(); //운영체제가 사용하는 디폴트 문자셋
- Charset을 이용하여 문자열을 ByteBuffer로 변환하려면 encode()메소드 호출한다.
String data = "...";
ByteBuffer byteBuffer = charset.encode(data);
- 반대로 파일이나 네트워크로부터 읽은 ByteBuffer가 특정 문자셋으로 인코딩되어 있을 경우. 해당 문자셋으로 디코딩해야 문자열 복원할 수 있다.
- Charset은 ByteBuffer를 디코딩해서 CharBuffer로 변환시키는 decode()메소드 제공
ByteBuffer byteBuffer = ...;
String data = charset.decode(byteBuffer).toString();
ByteBuffer <-> IntBuffer
- IntBuffer는 한 배열당 4개의 byte를 저장할 수 있다. 그래서 IntBuffer -> ByteBuffer 할때 ByteBuffer의 크기를 capacity()*4한다.
- ByteBuffer -> IntBuffer의 경우 ByteBuffer의 asIntBuffer()메소드를 사용하여 IntBuffer로 변환해준다.
- ByteBuffer <-> IntBuffer 간의 변환만 이해하면 나머지 ShortBuffer,LongBuffer 등이 쉽게 예측할 수 있다.
'👨🏫Study > JAVA' 카테고리의 다른 글
[JAVA] 19. NIO 기반 입출력 및 네트워킹(4) (0) | 2022.04.06 |
---|---|
[JAVA] 19. NIO 기반 입출력 및 네트워킹(3) (0) | 2022.04.06 |
[JAVA] 19. NIO 기반 입출력 및 네트워킹(1) (0) | 2022.04.06 |
[JAVA] 인텔리제이 오류 해결 (0) | 2022.04.01 |
[JAVA] 18 - 4. UDP 네트워킹 (0) | 2022.03.31 |
댓글