IT_Term

[IT_Term] java.nio(new input output).pakage_방통대 교재 정리

KKuGii 2023. 6. 10. 14:15
728x90

###. NIO

#. nio는 New Input Output의 약자로 기존의 io 패키지의 문제점을 한계를 극복하기위해 1.4버전 부터 새롭게 추가된 입출력 관련 패키지

#. 1.7버전 부터는 NIO2라고 부르는 API가 추가 되었는데 nio 패키지의 서브 패키지 형태로 제공

#. IO방식과 NIO 방식의 차이점

 - io 패키지에서 사용하던 입출력 스트림 대신 nio에서는 FileChannel 클래스를 사용

 - Io에서는 input output class 를 정의해서 사용하지만, nio에서는 FileChannel class 하나로 모두 사용 가능

 - nio에서 path interface를 제공

 - nio에서는 기본적으로 buffer 기능을 사용

 - io에서는 read, write 메서드가 호출되는 동안에는 다른 작업을 수행할수 없지만, nio에서는 AsysnchronousFileChannel class를 이용해서 다른 작업을 수행할 수 있게 한다.

 

###. File / Directory

#. path interface

 - path 인터페이스는 java.nio.file 패키지에 정의된 인터페이스로 io의 File class를 대신하기 위해 만들어 졌다.

 - path 인터페이스의 객체는 java.nio.file 패키지의 paths 클래스가 제공하는 static 메서드인 get() 메서드로 생성된다. 그 외 path인터페이스의 메서드는 다음과 같다.

 : int compartTo(Path other) : 다른 경로인 other와 비교하여 동일하면 0, 다르면 0이 아닌값으로 리턴

 : Path getFileName() : 현재 path 객체가 가리키는 디렉토리 또는 파일 이름을 리턴

 : FileStream getFileSystem() : FileSystem 객체를 리턴

 : Path getName(int Index) : 현재 공로에서 index에 해당하는 이름을 Path 객체로 리턴

 : int getNameCount() : 현재 경로에 포함된 디렉토리 또는 파일의 개수를 리턴

 : Iterator <Path> iterator() : 현재 경로에 있는 모든 디렉토리와 파일에 대한 iterator 객체를 리턴

 : FIle toFIle() : 현재 경로에 대한 java.io.Fil 객체를 리턴

 : String toString() : 현재 경로에 문자열로 리턴

 

###. FileSystem Class

#. 파일시스템 클래스는 현재 프로그램이 저장된 디스크 드라이브에 대한 정보를 확인하는 메서드를 제공

#.FileSystem Class는 별도의 생성자를 제공하지 않으며 FileSystems클래스의 static 메서드인 getDefault() 메서드로 객체를 생성 시킬 수 있다.

 #. FileSystem의 메서드는 간단하게 뭐가 있는지만 적겠다. 위와 비슷한 맥락

 : Iterator <FIleStore> getFileStores() : 현재 시스템에 탑재된 디스크 드라이브 정보를 가진 FileStore 객체를 리턴

 : String getSeparator()

 

###. File Class

#. File 클래스는 1,7 버전부터 nio.files에 추가된 클래스

#. 적절한 소스코드로 확인해보기

 - Path path = Paths.get("c:\\a");

 

DirectoryStream <Path> ds = Files.newDirectoryStream(path);

for(Path p : ds){

    if(Files.i'Derectory(p)){

      Syso("[디렉토리]" + p.getFileName());

      }else {

         syso("[파일]"+ p.getFileName());}

}

 - 위는 디렉토리 내용 확인하기 소스

 

###.Buffer

#. 프로그램은 데이터 생산자로부터 데이터를 입력받거나 데이터 소비자에게 데이터를 출력할 수 있다. 데이터 생산자로는 파일, 네트워크, 또 다른 프로그램 등이 될 수 있는데 예를들어 데이터 생산자가 파일이라면 프로그램 파일을 열어서 데이터를 읽어오게 된다. 데이터 소비자 역시 파일이나 네트워크 등이 될 수 있다.

 프로그램이 데이터 생산자로부터 데이터를 입력 받고 처리할 떄 데이터가 입력되는 속도와 처리하는 속도가 다르면 지연이 생기게 된다. 데이터가 입력되는 속도보다 프로그램이 데이터를 처리하는 속도가 느리다면 데이터 생산자에게 지연이 생기게 되고 프로그램의데이터 처리 속도가 생산자의 데이터 입력 속도보다 빠르다면 프로그램이 기다려야 하는 현상이 생기게 된다. 마찬가지로 프로그램 데이터 소비자에게 데이터를 출력할 떄에도 서로 속도가 다르게 되면 지연 현상이 생기게 된다. 

 버퍼는 프로그램과 데이터 생산자/소비자 사이의 처리 속도 차이로 오는 지연현상을 막기 위해 일종의 완충 역할을 하는 메모리 공간을 말한다. 버퍼를 사용하게 되면 데이터 생산자는 프로그램에 바로 데이터를 보내는 것이 아니라 버퍼로 데이터를 보낸다. 프로그램은 생산자로부터 데이터를 직접 받는 것이 아니라 버퍼로부터 데이터를 읽어온다. 반대로 데이터 소비자는 프로그램으로부터 데이터를 직접 입력 받는 것이 아니라 버퍼로부터 데이터를 읽어오는 프로그갬은 소비자가 아닌 버퍼로 데이터를 출력 시킨다. 이렇게 버퍼를 사용하면 생산자/ 소비자와 프로그램 간의 처리 속도 차이 떄문에 생기는 지연 현상을 방지할 수 있게 된다. 데이터 소비자의 데이터 입력 속도가 느리더라도 프로그램은 소비자에게 보낼 데이터를 버퍼에 미리 다 보내 놓고 다른 이일을 할 수 있다.

 데이터 입출력 과정에서 버퍼를 사용하는 것을 버퍼링이라고 한다.

 

#. Buffer Class

 - 버퍼 클래스는 nio 패키지에 정의 되어 있는 추상 클래스

 - 버퍼를 실제로 사용할 떄에는 데이터의 종류에 따라 Buffer 클래스의 서브 class를 사용

  : ByteBuffer - MappedByteBuffer

  : CharBuffer

 : DoubleBuffer

 : FloatBuffer

 : IntBuffer

 : LongBuffer

 

#. 버퍼의 속성

 - capacity : 버퍼의 크기를 의미하며 버퍼에 저장되는 데이터의 갯수를 나타냄

 - limit : 데이터를 읽거나 쓸 수 있는 최대 위치를 나나냄 0보다 크고 capacity보다 작거나 같아야함

 - position : 버퍼에게 읽거나 쓰기가 적용되는 위치를 의미

 

#. 버퍼의 변환

 - String 형으로 변환

 : 한글이 포함된 문자열을 채널을 통해 파일이나 네트워크로 전달하려면 UTF-8이나 EUC-KR 문자 세트로 인코딩 해서 ByteBuffer로 변환해아 한다.

 : 필요한 문자 세트는 nio.charset 패키지에 정의된 Charset Class를 이용해서 얻을 수 있다.

 : Charset cs = Charset.forName("UTF-8");  지정된 이름의 문자 세트 객체 생성

 : Charset cs = Charset.defaultCharset(); : 운영체제가 사용하는 기본 문자 세트 객체 생성

 : String 변수에 들어 있는 문자들을 지정된 문자 세트를 이용해서 ByteBuffer로 변환하려면 다음과 같이 Charset 클래스가 제공하는 encode() 메서드를 사용

 : Charset cs = Charset.defaultCharset();

 : String str = "핵단추";

 :  ByteBuffer buffer = cs.encode(str);

 - 길지만 이해하기 쉬운 소스코드

import java.nio.charset.*;

main---------

String [] data = {

   "안녕하세요 여러분 핵단추 엔지니어입니다.",

   "자바를 공부하고 있지만 ㅋㅋ 제가 개발자는 아닙니다."

};

 

Charset cs = Charset.defaultCharset();

ByteByffer buffer;

for (int i =0; i <data.length[i]; i++){

   buffer= cs.encode(data[i]);

   syso(cs.decode(buffer));

};

 - 위 소스는 문자열을 변환하는 코드이다.

 - int형으로 변환도 있다.

 

#. FileChannel Class

 - nio 패키지에 포함된 파일 채널은 java.io 패키지의 파일 관련 스트림을 대체하기 위한 것으로 파일에 대한 읽기, 쓰기 등을 지원한다. 파일 채널은 io 패키지에서 제공하는 스트림과는 달리 멀티 스레드 환경에서도 문제 없이 사용될 수 있다. 기본적으로 파일에 대한 입출력은 FileChannel 클래스의 객체를 생성한 후 read(), write() 메서드 호출 하는 것으로 진행

 - 객체 생성 방법

 : FIle Channel Class의 객체는 open 메서드를 호출해서 생성할 수 있다.

 : io 패키지와 호환을 위해 Input, output class의 getChannel()을 사용할 수 있다.

 - FileChannel 객체 생성에 사용되는 옵션 값

 : READ, WRITE, CREATE, APPEND

 

 - 파일 만들기

 : main---------

String [] data = {

   "안녕하세요 여러분 핵단추 엔지니어입니다.",

   "자바를 공부하고 있지만 ㅋㅋ 제가 개발자는 아닙니다."

};

Path path = Paths.get("c:\\a.txt");

File.crateDirectories(path.getParet());

 

FileChannel fileChannel = FileChannel.open(path,

StandardOpenOption.CREATE, StandatdOpenOption.WRETE);

 

Charset charset = Charset.defaultCharset();

ByteBuffer buffer;

int byteCount = 0;

for (int i = 0 ;  i <data.length; i++){

 buffer = charset.encode(data[i]);

 byteCount = fileChannel.wrtie(buffer);

}

syso(byteCount);

fileChannel.close();

 

###. AsynchronusFileChannel

#. FileChannel 클래스는 파일에 대해 입력과 출력을 할 때 각각 read(), write() 메서드를 사용한다. 그런데 ead와 write 메서드를 호출하는 동안  다른 작업은 할 수 없다. 이런 입출력 방식을 블로킹 또는 동기식 입출력이라 하는데 파일에 대한 입출력 작업이 진행되는 동안에는 다른 작업을 할 수 없다는 말이다. 만약 다른 작업을 해야 한다면 별도의 스레드를 직접 만들어 관리해야한다.

 AsynchronousFileChannel 클래스를 사용하면 비동기식 입출력이 가능해진다. 즉 ,Asynchronous 클래스를 통해 수행하는 읽기/쓰기 작업은 Asynchronous 클래스가 자체적으로 제공하는 스레드 풀에서 관리되기 때문에 입출력 작업이 진행되는 동안 다른 작업을 수행할 수 있게 해준다.

 AsynchronousFileChannel 클래스의 read( )메 메서드를 호출할 때에는 데이터를 읽어 올 버퍼 객체, 파일 채널 객체, 읽기 작업 완료 후 호출할 메서드(call back)를 설정한다. 그러면 해당 작업 내역이 스레드 풀이 관리하는 대기열 queue에 저장되고 read () 메서드는 바로 리턴 된다. read() 메서드가 바로 리턴되기 때문에 메인 스레드에서는 다른 작업을 수행할 수 있다.

 스레드 풀이 관리하는 대기열에 저장된 읽기 작업은 AsynchronousFileChannel이 내부적으로 자동 생성하는 스레드에 의해 수행된다. 읽기 작업이 완료되면 raed() 를 호출할 떄 지정된 allback 메서드를 자동으로 호출하고 읽기작업을 수행한 스레드는 종료된다. 읽기 작업의 callback 메서드는 파일을 닫고 파일로부터 읽어 온 데이터가 저장된 버퍼를 처리하게 하면 된다.

 write() 메서드도 비슷한 방식으로 수행된다.write( ) 메서드는 호출 후 바로 리턴되기 떄문에 메인 스레드에서는 다른 작업을 수행할 수 있고, write() 메서드로 지정된 쓰기 작업은 스레드 풀에 있는 스레드가 수행하게 된다. 스레드 풀에 있는 스레드는 쓰기 작업을 수행하고 완료되면 해당 작업의 callback 메서드를 호출한다. 쓰기 작업의 callback 메서드에서는 파일을 닫으면 된다.

728x90