JAVA/JAVA

I/O

호두밥 2022. 2. 6. 18:45

I/O (input / output) 데이터 입출력

데이터가 들어오는 것 (Input)과 데이터가 나가는 것(Output)을 합쳐 I/O라고 합니다. 자바에서는 스트림, 채널, 버퍼 등을 통해 데이터 입출력이 가능합니다. 

Stream 스트림

스트림은 물이 한 방향으로 흘러가는 것처럼 단방향으로만 데이터 전송이 가능합니다. (입력과 출력 하나만 가능) 

예를 들어 파일의 데이터를 읽고 저장하는 작업을 모두 수행해야 한다면, File Input Stream과 File Output Stream을 2개를 생성해야 합니다. 

스트림은 바이트 스트림(Byte Stream)과 문자 스트림(Character Stream)으로 구분됩니다. 

  • 바이트 스트림 : 그림, 멀티미디어, 문자 등 모든 종류의 데이터 입출력이 가능함.
  • 문자 스트림 : 문자 타입의 데이터만 입출력이 가능함.

Buffer 버퍼

버퍼는 메모리 저장소입니다. 버퍼를 사용하면 데이터 여러 개를 한 번에 입력받고, 출력할 수 있어 입출력 성능이 좋아집니다. 

Channel 채널

채널은 양방향으로 데이터를 전송하는 것이 가능합니다. (입력과 출력 동시 가능) 

예를 들어 파일의 데이터를 읽고 저장하는 작업을 수행해야 한다면, File Channel 하나만 생성하면 됩니다.  

 

IO 패키지와 NIO 패키지

IO 패키지 (java.io)는 스트림 기반의 데이터 입출력 기능을 제공하는 패키지입니다. 데이터의 입력이나 출력 작업이 완전하게 끝날때까지 스레드를 제한하는 블로킹 방식(동기방식)으로 이루어집니다. 

NIO 패키지(java.nio)는 채널 기반의 데이터 입출력 기능을 제공하는 패키지입니다. 또 기본적으로 버퍼를 사용하기 때문에 IO보다 성능이 좋습니다. 데이터의 입력이나 출력 작업이 완전하게 끝나지 않았더라도 스레드가 다른 작업을 수행할 수 있는 넌블로킹 방식(비동기 방식)을 지원합니다. 그리고 한 스레드에서 여러 개의 채널을 사용할 수 있는 기능(Selector)도 지원합니다. 

구분 IO NIO
입출력방식 스트림 채널
버퍼 X (non-buffer) O (buffer)
블로킹(동기)/넌블로킹(비동기) 동기 방식만   동기/비동기 모두 가능

 

IO (java.io) 패키지

java.io 패키지는 파일 시스템의 정보를 얻기 위한 File 클래스와 데이터를 입출력하기 위한 입출력 Stream 클래스를 제공합니다. 

클래스 구분 설명
File   파일 정보를 얻기 위한 클래스
Console   콘솔에 문자 입출력
InputStream/OutputStream Byte Stream 최상위 바이트 스트림 클래스
FileInputStream/FileOutputStream
DataInputStream/DataOutputStream
ObjectInputStream/ObjectOutputStream
PrintStream
BufferedInputStream/BufferedOutputStream
Byte Stream InputStream/OutputStream 하위 클래스
Reader/Writer Character Stream 최상위 문자 스트림 클래스
FileReader/FileWriter
InputStreamReader/OutputStreamWriter
PrintWriter
BufferedReader/BufferedWriter
Character Stream Reader/Writer 하위 클래스

InputStream

InputStream은 바이트 기반 입력 스트림의 최상위 클래스로 추상 클래스입니다. 

return type  method 설명 
int  read() 1바이트를 읽고 읽은 바이트를 리턴합니다. 
int  read(byte[ ] b) 읽은 바이트들을 매개값으로 주어진 바이트 배열b에 저장하고 실제로 읽은 바이트 수를 리턴합니다.
int  read(byte[] b, int off, int len) len개의 바이트만큼 읽고 매개값으로 주어진 바이트 배열 b[off]부터 len개까지 저장합니다. 그리고 실제로 읽은 바이트 수인 len개를 리턴합니다. 만약 len개를 모두 읽지 못하면 실제로 읽은 바이트 수를 리턴합니다. 
void  close() 사용한 시스템 자원을 반납하고 InputStream을 닫습니다. 

*read 메소드는 데이터를 더 이상 읽을 수 없으면 -1을 리턴합니다.

InputStream inputStream = new FileInputStream("C:\\study\\sample\\file\\abc.txt");

int readData;
while ( (readData = inputStream.read()) != -1){
    System.out.write(readData);
    System.out.println();
}

inputStream.close();

OutputStream

outputStream은 바이트 기반 출력 스트림의 최상위 클래스로 추상 클래스입니다. 

return type method 설명 
void write(int b)  1바이트를 보냅니다.(b의 끝 1바이트) 
void write(byte[ ] b)  주어진 바이트 배열 b의 모든 바이트를 보냅니다.
void write(byte[ ] b, int off, int len)  바이트 배열 b[off]부터 len개까지의 바이트를 보냅니다. 
void flush()   버퍼에 잔류하는 모든 바이트를 출력하고 버퍼를 비웁니다.
void close()  사용한 시스템 자원을 반납하고 OutputStream을 닫습니다. 
OutputStream outputStream = new FileOutputStream("C:\\study\\sample\\file\\output_abc.txt");
byte[] data = "ABC".getBytes(StandardCharsets.UTF_8);
outputStream.write(data);
outputStream.close();

Reader

Reader는 문자 기반 입력 스트림의 최상위 클래스로 추상 클래스입니다.

return type  method 설명 
int  read() 한 개의 문자를 읽고 리턴합니다.
int  read(char[ ] b) 읽은 문자들을 매개값으로 주어진 문자 배열b에 저장하고 실제로 읽은 문자 수를 리턴합니다.
int  read(char[] b, int off, int len) len개의 문자를 읽고 매개값으로 주어진 문자 배열 b[off]부터 len개까지 저장합니다. 그리고 실제로 읽은 문자 수인 len개를 리턴합니다. 
void  close() 사용한 시스템 자원을 반납하고 InputStream을 닫습니다. 
Reader reader = new FileReader("C:\\study\\sample\\file\\abc.txt");

int readData;
while ( (readData = reader.read()) != -1){
    System.out.write(readData);
    System.out.println();
}

reader.close();

Writer

Writer는 문자 기반 출력 스트림의 최상위 클래스로 추상 클래스입니다. 

return type method 설명 
void write(int b)  문자 1개를 보냅니다.(b의 끝 2바이트) 
void write(char[ ] b)  주어진 문자 배열 b의 모든 문자를 보냅니다.
void write(char[ ] b, int off, int len)  문자 배열 b[off]부터 len개까지의 문자를 보냅니다. 
void flush()   버퍼에 잔류하는 모든 문자열을 출력하고 버퍼를 비웁니다.
void close()  사용한 시스템 자원을 반납하고 OutputStream을 닫습니다. 
Writer writer = new FileWriter("C:\\study\\sample\\file\\output_abc2.txt");
char[] data = "ABC".toCharArray();
writer.write(data);
writer.close();

 

보조 스트림

보조 스트림이란 다른 스트림과 연결해 여러가지 편리한 기능을 제공해주시는 스트림을 말합니다. 

아래처럼 InputStreamReader에 버퍼 기능을 추가할 수 있습니다. 

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
클래스명 설명
InputStreamReader 바이트 입력 스트림(InputStream)에 연결되어 문자 입력 스트림인 reader로 변환시켜 줍니다. 
OutputStreamReader 바이트 출력 스트림(OutputStream)에 연결되어 문자 출력 스트림인 writer로 변환시켜 줍니다.
BufferedInputStream 바이트 입력 스트림(InputStream)에 연결되어 버퍼 기능을 제공해줍니다.
BufferedReader 문자 입력 스트림(Reader)에 연결되어 버퍼 기능을 제공해줍니다. 
BufferedOutputStream 바이트 출력 스트림(OutputStream)에 연결되어 버퍼 기능을 제공해줍니다. 
BufferedWriter 문자 출력 스트림(Writer)에 연결되어 버퍼 기능을 제공해줍니다. 
DataInputStream 바이트 입력 스트림(InputStream)에 연결되어 바이트 타입을 자바 기본 데이터 타입(int, boolean, char 등)으로 변환시켜 줍니다. 
DataOutputStream 바이트 출력 스트림(OutputStream)에 연결되어 바이트 타입을 자바 기본 데이터 타입(int, boolean, char 등)으로 변환시켜 줍니다. 
PrintStream 바이트 출력 스트림(OutputStream)에 연결되어 콘솔에 데이터를 출력해줍니다.
PrintWriter 문자 출력 스트림(Writer)에 연결되어 콘솔에 데이터를 출력해줍니다.
ObjectInputStream 바이트 입력 스트림(InputStream)에 연결되어 바이트 데이터를 사용자가 생성한 객체(Class Object)로 변환시켜 줍니다. (역직렬화)
ObjectOutputStream 바이트 출력 스트림(OutputStream)에 연결되어 사용자가 생성한 객체(Class Object)를 바이트 데이터로 변환시켜 줍니다. (직렬화)

* 직렬화/역직렬화

  • 객체 직렬화 : 객체 데이터(필드값)을 일렬로 늘어선 연속적인 바이트 데이터로 변경하는 것
  • 객체 역직렬화 : 늘어선 연속적인 바이트 데이터를 객체의 데이터(필드값)으로 변경하는 것 
  • Serializable : 객체의 직렬화가 가능하게 하려면, 객체가 Serializable 인터페이스를 구현해야 합니다. 
public class Stream {

 public static void main(String[] args) throws IOException, ClassNotFoundException {
        Person person = new Person(1, "manta");

        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\study\\sample\\file\\serialize.txt"));
        oos.writeObject(person);
        oos.close();

        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\study\\sample\\file\\serialize.txt"));
        Person readPerson = (Person) ois.readObject();
        ois.close();

        System.out.println("readPerson.getName() = " + readPerson.getName());
}

public static class Person implements Serializable {
        int id;
        String name;

        public Person(int id, String name) {
            this.id = id;
            this.name = name;
        }

        public int getId() {
            return id;
        }

        public String getName() {
            return name;
        }
    }
 }
readPerson.getName() = manta

* serialize.txt :  sr com.company.io.Stream$Person�'�v��� I idL namet Ljava/lang/String;xp   t manta

Console 

Console은 콘솔에서 입력받은 데이터를 읽는 클래스입니다.

return type method 설명
String readLine() Enter 키를 입력하기 전의 모든 문자열을 읽습니다.
char[] readPassword() 키보드 입력 문자를 콘솔에 보여주지 않고 읽습니다. 
Console console = System.console();
String readLine = console.readLine();
System.out.println("readLine = " + readLine);

char[] readPassword = console.readPassword();
System.out.println("readPassword = " + Arrays.toString(readPassword));

* console은 IDE(이클립스, 인텔리제이)에서 실행하면 NullPointerException이 발생하기 때문에 Terminal(명령프롬프트)에서 실행해야 합니다. 

$ java Stream.java
aaaaa
readLine = aaaaa

readPassword = [1, 2, 3, 4]

Console 클래스는 문자열은 읽을 수 있지만, 숫자 타입의 값을 바로 읽을 수 없습니다. 이럴 때는 Scanner (java.util) 클래스를 이용합니다. nextInt() - int형 반환, nextDouble() - double형 반환 등의 메소드가 있습니다.  

Scanner sc = new Scanner(System.in);
int i = sc.nextInt();
System.out.println("i = " + i);
1
i = 1

 

File

File은 파일 크기, 파일 이름 등의 정보를 얻어내는 기능과 파일 생성 및 삭제 기능을 하는 클래스입니다. 디렉토리를 생성하고, 디렉토리의 파일 리스트를 얻어내는 기능도 있습니다. ( 파일의 데이터를 읽고 쓰는 기능은 FileInputStream/FileOutputStream 을 사용해야 합니다.)

new File("경로")를 통해 파일 객체를 생성했다고 해서 실제로 파일이 생성되는 것은 아닙니다. 경로가 잘못되었더라고 에러가 발생하지 않습니다. exists메소드를 통해 실제로 파일/디렉토리가 있는지 확인해야 합니다.  

File file = new File("C:\\study\\sample\\file\\abc3.txt");
System.out.println("file.exists() = " + file.exists());
file.exists() = false

* java.io.file 클래스의 메소드 목록

 

표준 스트림 System.in, System.out, System.err

자바는 콘솔로 데이터 입출력을 해야하는 경우 System 클래스(java.lang 패키지)를 사용합니다.

  • System.in : 콘솔에서 데이터 입력 
  • System.out : 콘솔에서 데이터 출력
  • System.err : 콘솔에서 에러 출력

System.in 

system.in은 콘솔에서 데이터를 입력받을 때 사용하는 표준 스트림으로, InputStream을 반환합니다. 

InputStream inputStream = System.in;
char input = (char) inputStream.read();
System.out.println("input = " + input);
1                           -> 키보드로 콘솔에 입력한 값
input = 1                -> 출력   

System.out

system.out은 콘솔에서 데이터 출력할 때 사용하는 표준 스트림으로,  PrintStream(outputStream)을 반환합니다.

write 메소드를 사용하면, 데이터를 바이트로 변환하는 과정이 있기 때문에 불편합니다. 때문에 String 타입을 출력할 수 있는 PrintStream의 print, println을 주로 사용합니다. 

OutputStream outputStream = System.out;
outputStream.write(65);
outputStream.write(10);

byte[] data = "A".getBytes(StandardCharsets.UTF_8);
outputStream.write(data);
outputStream.write(10);

System.out.println("A");
A
A
A

System.err

system.err는 콘솔에서 에러메세지를 출력할 때 사용하는 표준 스트림입니다. PrintStream(outputStream)을 반환합니다. 

System.err.println("err");

 

 

NIO (java.nio) 패키지

 

NIO 패키지(java.nio)는 채널 기반의 데이터 입출력 기능을 제공하는 패키지입니다. 또 기본적으로 버퍼를 사용하기 때문에 IO보다 성능이 좋습니다. 데이터의 입력이나 출력 작업이 완전하게 끝나지 않았더라도 스레드가 다른 작업을 수행할 수 있는 넌블로킹 방식(비동기 방식)을 지원합니다. 그리고 한 스레드에서 여러 개의 채널을 사용할 수 있는 기능(Selector)도 지원합니다. 

method 설명
java.nio 버퍼 클래스
java.nio.channels 파일 채널, TCP 채널, UDP 채널 등의 클래스
java.nio.channels.spi java.nio.channel을 위한 서비스 제공자 클래스 
java.nio.charset 문자셋, 인코더, 디코더 API
java.nio.charset.spi java.nio.charset을 위한 서비스 제공자 클래스
java.nio.file 파일 및 파일 시스템 접근을 위한 클래스
java.nio.file.attribute 파일 및 파일 시스템의 속성에 접근하기 위한 클래스
java.nio.file.spi java.nio.file 패키지를 위한 서비스 제공자 클래스

 

java.nio.file

nio.file 메소드 목록

Path (java.nio.file.path)는 파일이 경로와 관련된 정보를 조회할 수 있도록 해주는 패키지입니다.

 Path path1 = Paths.get("/usr", "local", "bin");
 Path path2 = Paths.get("/user/local/bin");

Files (java.nio.file.Files) 클래스는 파일/디렉토리를 생성, 삭제하고 속성 정보를 조회하는 패키지입니다. 

FileSystem(java.nio.file.FileSystem) 클래스는 디렉토리 관련 정보를 조회하는 패키지입니다. 

FileStore(java.nio.file.FileStore) 클래스는 드라이버를 표현한 객체로, 드라이버의 전체고간 크기, 읽기 전용 여부 등을 조회하는 패키지입니다. 

WatchService 변경 감지

파일의 생성, 삭제, 수정을 감시하는데 사용되는 클래스입니다.

     //와치 서비스 생성
        WatchService watchService = FileSystems.getDefault().newWatchService();
        //감시대상 경로 설정
        Path path = Paths.get("C:\\study\\sample\\file");
        //경로에 와치서비스 등록
        path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE,
                StandardWatchEventKinds.ENTRY_MODIFY,
                StandardWatchEventKinds.ENTRY_DELETE);

        // 와치서비스 실행
        while(true){
            // 이벤트 큐 조회
            WatchKey watchKey = watchService.take();
            List<WatchEvent<?>> watchEvents = watchKey.pollEvents();

            for (WatchEvent<?> watchEvent : watchEvents) {
                WatchEvent.Kind<?> kind = watchEvent.kind(); //이밴트 종류 얻기
                Path evetnPath = (Path) watchEvent.context(); // 이벤트 발생 경로 얻기
                // 파일이 생성됐을 때
                if(StandardWatchEventKinds.ENTRY_CREATE.equals(kind)){
                    System.out.println("파일이 생성되었습니다. path : " + evetnPath);
                }
                //파일이 수정됐을 때
                if(StandardWatchEventKinds.ENTRY_DELETE.equals(kind)){
                    System.out.println("파일이 삭제되었습니다. path : " + evetnPath);
                }
                //파일이 삭제됐을 때
                if(StandardWatchEventKinds.ENTRY_MODIFY.equals(kind)){
                    System.out.println("파일이 수정되었습니다. path : " + evetnPath);
                }
            }

            boolean valid = watchKey.reset();// 큐 초기화
            // 감시 대상 (파일경로)가 사라지거나, 문제가 발생하면  false를 리턴한다.
            if(!valid) {
                break;
            }
        }

        watchService.close(); // 와치 서비스 종료
파일이 삭제되었습니다. path : serialize - 복사본.txt
파일이 생성되었습니다. path : test.txt
파일이 수정되었습니다. path : serialize.txt

 

Buffer 버퍼

NIO에서는 데이터 입출력을 위해 항상 버퍼를 사용해야 합니다.

버퍼는 저장되는 데이터 타입에 따라 Byte Buffer, CharBuffer, IntBuffer 등으로 분류됩니다. 참고

또 사용하는 메모리에 따라 넌다이렉트 버퍼, 다이렉트 버퍼로 구분합니다. 

구분 넌다이렉트 버퍼 다이렉트 버퍼
사용하는 메모리 공간 JVM 힙 운영체제 메모리
버퍼 생성 시간 빠름 느림
버퍼 크기 작다 크다(큰 데이터를 처리할 때 유리)
입출력 성능 낮다 높다(입출력이 잦을때 유리)

넌다이렉트 버퍼는 allocate, wrap 메소드를 사용해서 생성합니다. allocate는 매개변수에 버퍼의 크기를 넣어주고, wrap은 이미 생성된 배열을 넣어줍니다.

//넌다이렉트 버퍼 생성 (매개변수는 데이터 저장 용량)
ByteBuffer nonDirectBuffer = ByteBuffer.allocate(100*1024*1024);
byte[] byteArray = new Byte[100];
ByteBuffer nonDirectBufferArray = ByteBuffer.wrap(byteArray);

다이렉트 버퍼는 allocateDirect로 생성합니다. 다만, allocateDirect는 ByteBuffer 클래스에만 있는 메소드이기 때문에, 다른 타입의 버퍼를 생성해야 한다면 asCharBuffer()와 같은 메소드를 추가로 연결해주어야 합니다.

//다이렉트 버퍼 생성 (매개변수는 데이터 저장 용량)
ByteBuffer directBuffer = ByteBuffer.allocateDirect(100*1024*1024);
CharBuffer charBuffer = ByteBuffer.allocateDirect(100*1024*1024).asCharBuffer();

버퍼의 메소드를 사용하려면 버퍼의 위치 속성 개념을 살펴볼 필요가 있습니다. 

속성 설명
position 현재 위치
limit 버퍼에서 읽거나 쓸 수 있는 한계값 (최대치)
capacity 버퍼의 최대 데이터 개수(메모리 크기)
mark reset() 메소드 실행 시 돌아오는 위치값 (savepoint와 비슷)
0 ≤ mark ≤ position ≤ limit ≤ capacity 

https://javapapers.com/java/java-nio-buffer/

IntBuffer intBuffer = IntBuffer.allocate(10);
System.out.println("intBuffer.capacity() = " + intBuffer.capacity());
System.out.println("intBuffer.array().length = " + intBuffer.array().length);

intBuffer.put(1);
intBuffer.put(2);
intBuffer.put(3);

System.out.println("intBuffer.position() = " + intBuffer.position());
System.out.println("intBuffer.limit() = " + intBuffer.limit());
intBuffer.capacity() = 10
intBuffer.array().length = 10
intBuffer.position() = 3
intBuffer.limit() = 10

버퍼 메소드

method 설명
filp() limit = position, position = 0으로 변경
rewind() position = 0 으로 변경 (mark된 값이 무시됨)
mark() 현재 position을 저장
reset() 마지막으로 저장한 (mark) 위치로  position 이동
clear() position = 0, limit=capacity, mark된 값 삭제
put() 버퍼에 데이터 저장
get(), get(int index) 버퍼에서 데이터 조회
System.out.println("intBuffer.position() = " + intBuffer.position());
System.out.println("intBuffer.limit() = " + intBuffer.limit());

intBuffer.flip();

System.out.println("after flip, intBuffer.position() = " + intBuffer.position());
System.out.println("after flip, intBuffer.limit() = "+intBuffer.limit());
intBuffer.position() = 3
intBuffer.limit() = 10
after flip, intBuffer.position() = 0
after flip, intBuffer.limit() = 3
intBuffer.clear();
System.out.println("after clear, intBuffer.position() = " + intBuffer.position());
System.out.println("after clear, intBuffer.limit() = " + intBuffer.limit());
after clear, intBuffer.position() = 0
after clear, intBuffer.limit() = 10

 

intBuffer.put(3);
System.out.println("after put(3), intBuffer.position() = " + intBuffer.position());
System.out.println("after put(3), intBuffer.limit() = " + intBuffer.limit());
after put(3), intBuffer.position() = 1
after put(3), intBuffer.limit() = 10
intBuffer.get();
System.out.println("after get(), intBuffer.position() = " + intBuffer.position());
System.out.println("after get(), intBuffer.limit() = " + intBuffer.limit());
after get(), intBuffer.position() = 2
after get(), intBuffer.limit() = 10
intBuffer.mark();
intBuffer.get();

System.out.println("after get(), intBuffer.position() = " + intBuffer.position());
System.out.println("after get(), intBuffer.limit() = " + intBuffer.limit());

 intBuffer.reset();
 
 System.out.println("after reset, intBuffer.position() = " + intBuffer.position());
 System.out.println("after reset, intBuffer.limit() = " + intBuffer.limit());
after get(), intBuffer.position() = 3
after get(), intBuffer.limit() = 10
after reset, intBuffer.position() = 2
after reset, intBuffer.limit() = 10
intBuffer.rewind();
System.out.println("after rewind, intBuffer.position() = " + intBuffer.position());
System.out.println("after rewind, intBuffer.limit() = " + intBuffer.limit());

intBuffer.reset();
System.out.println("after reset, intBuffer.position() = " + intBuffer.position());
System.out.println("after reset, intBuffer.limit() = " + intBuffer.limit());
after rewind, intBuffer.position() = 0
after rewind, intBuffer.limit() = 10

Exception in thread "main" java.nio.InvalidMarkException
at java.base/java.nio.Buffer.reset(Buffer.java:399)
at java.base/java.nio.IntBuffer.reset(IntBuffer.java:1197)
at com.company.io.PositionTest.main(PositionTest.java:45)

* rewind() 실행 시 mark가 무시되어, 이후에 reset을 호출하면 InvalidMarkException이 발생합니다.

 

채널 Channel

파일 채널 java.io.channels.FileChannel

* 파일 채널 사용법 참고자료 : https://www.baeldung.com/java-filechannel 

파일 읽기

//읽기 모드로 파일 채널 열기
FileChannel fileChannel = FileChannel.open(Paths.get("C:\\study\\sample\\file\\abc.txt"),
        StandardOpenOption.READ);

//버퍼 생성
ByteBuffer byteBuffer = ByteBuffer.allocate(100);
ByteArrayOutputStream out = new ByteArrayOutputStream();

//내용 읽기
while(fileChannel.read(byteBuffer) > -1){
    byteBuffer.flip();
    out.write(byteBuffer.array());
    byteBuffer.clear();
}

fileChannel.close();

String data = new String(out.toByteArray(), StandardCharsets.UTF_8);
System.out.println("data = " + data);
data = ABC

파일 쓰기

 //파일 신규 생성 && 쓰기 모드로 파일 채널 열기
FileChannel fileChannel = FileChannel.open(Paths.get("C:\\study\\sample\\file\\write_test.txt"),
        StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE);

//파일에 쓸 내용 생성
byte[] contents = "삶이란 어떻게든 의미를 지니고 계속 된다는 것을 기억하며, 겨우 살아가야겠다.".getBytes(StandardCharsets.UTF_8);

//버퍼 생성
ByteBuffer byteBuffer = ByteBuffer.wrap(contents);

//내용 쓰기
fileChannel.write(byteBuffer);

fileChannel.close();

비동기 파일 채널 AsynchronousFileChannel

비동기 파일 채널은 파일의 데이터 입출력을 위해 read()와 write() 메소드를 호출하면 스레드 풀에 작업처리를 요청하고, 이 메소드들을 바로 리턴시킵니다. 실질적인 입출력 작업 처리는 작업 스레드가 담당합니다. 작업 스레드가 파일 입출력을 완료하게 되면, 콜백 메소드가 자동 호출되기 때문에 작업 완료 후 실행해야 할 코드가 있다면 콜백 메소드를 작성하면 됩니다.  

* 비동기 파일 채널 사용법 참고자료 : https://www.baeldung.com/java-nio2-async-file-channel

참고자료

'JAVA > JAVA' 카테고리의 다른 글

Enum, EnumSet, EnumMap  (0) 2023.07.11
정적 팩토리 메소드와 빌더 패턴  (0) 2023.06.24
인터페이스  (0) 2021.11.30
Optional  (0) 2021.11.07
스트림 Stream  (0) 2021.11.07