[java] 자바 비동기 IO를 활용하여 파일 입출력 처리하기

자바에서 파일 입출력은 주로 동기적인 방식으로 처리됩니다. 하지만, 대량의 파일이나 크기가 큰 파일을 처리할 때는 이러한 동기 방식으로의 입출력은 성능 저하나 블로킹 문제를 일으킬 수 있습니다. 이러한 문제를 해결하기 위해 자바에서는 비동기 IO를 제공하고 있습니다.

비동기 IO를 사용하면 파일 입출력 작업을 백그라운드에서 비동기적으로 처리할 수 있으며, 이를 통해 더욱 효율적인 입출력 처리를 할 수 있습니다. 이번 글에서는 자바 비동기 IO를 활용하여 파일을 읽고 쓰는 방법에 대해 알아보겠습니다.

1. NIO(Non-blocking IO) 소개

NIO(Non-blocking IO)는 자바 1.4 버전부터 도입된 비동기 IO 패키지입니다. NIO를 사용하면 비동기 IO를 간편하게 처리할 수 있습니다. NIO는 java.nio 패키지에 정의되어 있으며, FileChannel 클래스를 통해 파일의 비동기 입출력을 처리할 수 있습니다.

2. 파일 비동기 읽기

비동기적으로 파일을 읽기 위해서는 FileChannel.read() 메서드를 사용합니다. 다음은 파일을 비동기적으로 읽는 예제 코드입니다.

import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.CompletionHandler;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.Future;

public class AsyncFileReader {
    public static void main(String[] args) throws Exception {
        Path path = Paths.get("file.txt");
        AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(path);

        ByteBuffer buffer = ByteBuffer.allocate(1024);
        long position = 0;

        fileChannel.read(buffer, position, null, new CompletionHandler<Integer, Void>() {
            @Override
            public void completed(Integer result, Void attachment) {
                buffer.flip();
                byte[] data = new byte[result];
                buffer.get(data);
                String content = new String(data);
                System.out.println(content);
                buffer.clear();
            }

            @Override
            public void failed(Throwable exc, Void attachment) {
                System.out.println("Failed to read file: " + exc.getMessage());
            }
        });

        fileChannel.close();
    }
}

위 코드에서는 AsynchronousFileChannel 클래스를 사용하여 비동기적으로 파일을 읽습니다. read() 메서드에 ByteBuffer를 전달하여 파일의 내용을 버퍼에 읽어옵니다. CompletionHandler를 사용하여 비동기 작업이 완료되면 해당 내용을 처리합니다. 읽은 내용을 출력하고, 버퍼를 초기화한 후에는 파일 채널을 닫습니다.

3. 파일 비동기 쓰기

비동기적으로 파일을 쓰기 위해서는 FileChannel.write() 메서드를 사용합니다. 다음은 파일을 비동기적으로 쓰는 예제 코드입니다.

import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.CompletionHandler;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

public class AsyncFileWriter {
    public static void main(String[] args) throws Exception {
        String content = "Hello, World!";
        ByteBuffer buffer = ByteBuffer.wrap(content.getBytes());

        Path path = Paths.get("file.txt");
        AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(path);

        Future<Integer> writeResult = fileChannel.write(buffer, 0);

        try {
            int bytesWritten = writeResult.get();
            System.out.println("Bytes written: " + bytesWritten);
        } catch (ExecutionException e) {
            System.out.println("Failed to write file: " + e.getMessage());
        }

        fileChannel.close();
    }
}

위 코드에서는 AsynchronousFileChannel 클래스를 사용하여 비동기적으로 파일을 씁니다. write() 메서드에 ByteBuffer를 전달하여 버퍼에 있는 내용을 파일에 씁니다. 비동기 작업이 완료되면 Future를 통해 작업 결과를 얻어옵니다. 쓰기 완료 후에는 파일 채널을 닫습니다.

4. 결론

이렇게 자바에서는 비동기 IO를 통해 파일의 입출력 처리를 효율적으로 할 수 있습니다. 비동기 IO는 대량의 파일이나 크기가 큰 파일을 처리할 때 성능을 높일 수 있으며, 블로킹 문제에서 자유롭습니다. 이를 통해 자바 프로그램의 성능을 향상시킬 수 있습니다.