티스토리 뷰
학습할 것 (필수)
- 스트림 (Stream) / 버퍼 (Buffer) / 채널 (Channel) 기반의 I/O
- InputStream과 OutputStream
- Byte와 Character 스트림
- 표준 스트림 (System.in, System.out, System.err)
- 파일 읽고 쓰기
자바의 I/O는 Input과 Output의 약자이다.
자바에서는 데이터는 스트림(Stream)을 통해서 입출력된다. 외부에서 문자 또는 파일이 들어와도 스트림을 통해서 들어오고 내보낼 때도 스트림을 통해서 내보낸다.
그래서 프로그램이 데이터를 입력받을 때에는 InputStream, 데이터를 보낼 때에는 OutputStream 이라고 한다.
프로그램을 기준으로 생각했을 때 들어오면 InputStream 나가는 건 OutputStream 이란걸 명심해야 한다.
스트림의 특성은 단방향이므로 하나의 스트림으로 모두 입출력을 할 수 가 없다. 뒤에 나오는 채널(Channel) 기반은 이게 가능하다.
그러므로 스트림은 받거나 내보내려면 InputStream과 OutputStream이 따로따로 필요하다.
자바의 I/O API는 모두 java.io 패키지에서 제공하고 있다.
java.io 패키지에는 파일 시스템의 정보를 얻기위한 File 클래스 및 데이터를 입출력 하기 위한 다양한 I/O 스트림들이 있다.
스트림 클래스는 크게 두 종류로 나뉘는데 하나는 바이트(byte)기반 스트림이고, 다른 하나는 문자(character) 기반 스트림이다.
모든 종류의 스트림을 받는 바이트 기반 스트림을 제외하고 문자 기반 스트림은 문자를 받고 보낼 수 있도록 특화되어 있다.
이런 모든 입출력 최상위 스트림은 InputStream과 OutputStream 이다.
이 최상위 스트림은 추상클래스로 작성되어있으며 xxxFileInputStream xxxFileOutputStream 이 최상위 클래스를 상속받는 형태로 되어있다.
예를들어 바이트 단위로 읽을 때에는 InputStream 을 쓰고 출력은 OutputStream 을 사용한다.
예를 들어 그림, 멀티미디어, 텍스트등의 파일을 바이트단위로 읽을 때에는 FileInputStream 내보낼 때는 FileOutputStream을 사용한다.
문자 단위로 읽을 때는 Reader를 쓰고 출력은 Writer를 쓴다.
정리하자면 접미사로 바이트 기반은 InputStream, OutputStream이 붙고 문자 기반 스트림은 Reader와 Writer를 사용한다.
InputStream
InputStream은 바이트 기반 입력 스트림의 최상위 클래스로 추상 클래스이다. 모든 바이트 기반 스트림은 이 추상 클래스를 상속받아서 만들어진다.
이 InputStream 클래스에는 바이트 기반 입력 스트림이 기본적으로 가져야 할 메서드가 정의되어 있다.
read()는 기본적으로 입력 스트림으로부터 1 바이트를 읽고 읽은 바이트를 리턴한다. 나머지 read(byte[] b)는 read() 메서드처럼 1바이트만 읽는 것이 아닌 매개변수에 주어진 바이트 수만큼 읽는다.
나머지 read(byte[], int off, int len)은 off부터 len까지 읽어서 리턴한다.
read() 메서드만 코드로 작성해보자면 아래와 같다.
public class InputStreamExample {
public static void main(String[] args) {
try (InputStream fileInputStream = new FileInputStream("/data.txt");) {
int readByte = 0;
while ((readByte = fileInputStream.read()) != 1) {
....
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
파일을 읽어올 때 더 이상 입력 스트림으로부터 바이트를 읽을 수 없으면 read() 메서드는 -1을 리턴하므로 -1을 읽기전까지 반복을 돌려 읽을 수 있다.
OutputStream
OutputStream도 바이트 기반 출력 스트림의 최상위 클래스로 추상 클래스이다. 모든 바이트 기반 스트림은 이 추상 클래스를 상속받아서 만들어진다.
입력이 출력으로만 바뀐거고 read가 write로 만 바뀐걸 알 수 있다.
public class OutputStreamExample {
public static void main(String[] args) {
try(OutputStream outputStream = new FileOutputStream("/data.txt");) {
byte[] data = "ABC".getBytes();
for (int i = 0; i < data.length; i++) {
outputStream.write(data[i]); //"A", "B", "C"를 하나씩 출력
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
추가적으로 OutputStream에 있는 flush() 메서드는 버퍼에 잔류하고 있는 데이터를 모두 출력시키고 버퍼를 비우는 역할을 한다.
프로그램에서 더 이상 출력할 데이터가 없다면 flush() 메서드를 마지막으로 호출하여 버퍼에 잔류하는 모든 데이터가 출력되도록 해야 한다.
보조 스트림 Buffer
보조 스트림이란 다른 스트림과 연결되어 여러가지 편리한 기능을 제공해주는 스트림을 말한다.
이런 보조 스트림들은 자체적으로 입출력 스트림을 실행할 수 없기 때문에 입력 스트림과 출력스트림을 연결해서 입출력을 수행한다.
그 중에 이런 입출력 수행을 향상 시켜줄 수 있는 스트림 중에 하나인 Bufferedxxx 스트림이 있다.
컴퓨터의 모든 처리 속도는 항상 가장 낮은 처리속도로 맞춰 지는데 CPU나 메모리리의 입출력이 아무리 빨라도 하드디스크의 입출력이 늦어지면 프로그램의 실행 성능은 가장 느린 하드디스크의 처리 속도에 맞춰진다.
이를 해결하려는 방법으로 프로그램이 직접 입출력 입출력하지 않고 중간에 버퍼라는 곳에 보내고 버퍼는 데이터를 쌓이기를 기다렸다가 꽉 차게 되면 데이터를 한꺼번에 하드 디스크로 보냄으로써 출력 횟수를 줄인다.
이런 성능 향상 보조스트림에는 바이트 기반 스트림으로는
- BufferedInputStream
- BufferedOutputStream
문자 기반 성능 향상 보조스트림에는
- BufferedReader
- BufferedWriter
public class BufferedStream {
public static void main(String[] args) {
try (InputStream inputStream = new FileInputStream("/data.txt");
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);) {
} catch (Exception e) {
e.printStackTrace();
}
}
}
BufferedInputStream의 생성자 호출 시 입력 또는 출력 스트림을 넘겨준다. 문자 기반 스트림에서는 BufferedReader를 사용하면 된다.
NIO, Channel
자바의 4버전 부터는 새로운 입출력 ( NIO: New Input/Output) 이라는 뜻에서 java.nio 패키지가 포함되었다. 그런데 이게 자바 7버전으로 올라가면서 업그레이드 되어서 NIO2 API가 추가되었다. 자바7부터 추가된 NIO2는 따로 java.nio2 라는 패키지가 있는것이 아니고 기존java.nio의 하위 패키지에 통합되어 있다. 굳이 NIO1, NIO2 라고 생각하지 않고 NIO라고만 봐도 된다.
기존 io 패키지와 nio 패키지의 차이점이라면 여러가지가 있겠지만 대표적인 것만 보자면
- 기존 io 패키지는 스트림이라는 것으로 단방향이었지만 nio패키지는 채널이라는 양방향이 가능하다.
- 기존 io 패키지는 입출력 시 버퍼를 통해 성능을 향상 시켰지만 nio 패키지에서는 기본적으로 버퍼를 지원한다.
- io는 비동기 방식을 지원하지 않지만 nio는 비동기 방식을 지원한다.
- 블로킹과 넌블로킹 방식 중 io는 블로킹 방식만 지원하지만 nio는 둘 다 지원한다.
파일을 읽고 쓰는 방법
java.io 패키지에서 제공하는 File 클래스로 파일을 생성하고 삭제 또는 파일의 정보를 가져올 수 있다.
그러나 파일을 읽고 쓰는 기능은 파일 입출력 스트림을 사용해야 한다.
public class FileExample {
public static void main(String[] args) {
File file = new File("/data.txt");
FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream("output.txt");
int readByte = 0;
byte[] readBytes = new byte[1024];
while ((readByte = fis.read(readBytes)) != -1) {
//읽은 바이트 배열 (readBytes) 처리
fos.write(readBytes);
}
fis.close();
}
}
java.nio에 추가되어있는 java.nio.channels.FileChannel을 이용하면 파일 읽기와 쓰기를 할 수 있다. FileChannel은 동기화 처리가 되어 있기 때문에 멀티 스레드 환경에서 사용해도 안전하다.
dFileChannel은 정적 메서드인 open() 을 호출해서 얻을 수 있다. FileInputStream과 FileOutputStream의 getChannel() 메소드를 호출해서 얻을 수도 있다.
첫번째 인수는 java.nio 패키지에 있는 Paths 객체를 넘기고 두번째 Options 인수는 열기 옵션 값이다.
아래 코드는 data.txt를 생성하고 내용을 쓸수 있도록 지정한 코드이다.
public class FileChannelExample {
public static void main(String[] args) {
//FileChannel fileChannel = FileChannel.open("Path객체", "열기 옵션 값.");
try (FileChannel fileChannel = FileChannel.open(
Paths.get("/data.txt"),
StandardOpenOption.CREATE_NEW,
StandardOpenOption.WRITE
);){
} catch (IOException e) {
e.printStackTrace();
}
}
}
출처
자바의 정석 - www.yes24.com/Product/Goods/24259565?OzSrank=2
이것이 자바다 - www.yes24.com/Product/Goods/15651484
자바의 신 - www.yes24.com/Product/Goods/42643850
오라클 Docs - docs.oracle.com/javase/tutorial/java/index.html
라이브 방송
왜 버퍼를 쓰면 입출력이 빨라질까?
스트림 입출력 호출은 OS레벨에서 시스템 콜을 한다.
버퍼를 사용하면 OS 레벨의 시스템 콜 횟수가 줄어들었기 때문에 성능에 이점이 생긴것이다.
예를들어 물을 한모금씩 떠오라는 것은 버퍼를 사용하지 않고 사용한 것이고 주방에가서 물통(버퍼)에 물을 가득 담아와라 라는 차이? 이다.
- Total
- Today
- Yesterday
- 북리뷰
- config-location
- mybatis
- input
- k8s
- jQuery
- Java
- mybatis config
- JavaScript
- Spring
- intellij
- Mac
- Bash tab
- Spring Security
- LocalDateTime
- window
- 베리 심플
- elasticsearch
- LocalDate
- maven
- svn
- Github Status
- localtime
- docker
- oracle
- Linux
- Kotlin
- 오라클
- springboot
- rocky
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |