일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 메서드명
- 블로그 병행
- 카카오 2차 코딩테스트
- N+1
- 프리코스
- java
- Blue-Green
- 백기선 스터디
- DeleteAll
- mysql
- 도커
- Jenkins
- B+TREE
- ci/cd
- 어댑티브 해시 인덱스
- 멀티쓰레드 프로그래밍
- InnoDB 버퍼 풀
- jacoco
- BalancedTree
- useQuery
- 회고
- SQL 실행순서
- useMutation
- 기능별 구조
- db
- 우테코
- 계층별 구조
- 주간회고
- 월간회고
- 클래스
- Today
- Total
Haneul's Blog
[Java] I/O 본문
목표 [백기선 자바 스터디 13주차]
자바의 Input과 Ontput에 대해 학습하세요.
학습할 것
- 스트림 (Stream) / 버퍼 (Buffer) / 채널 (Channel) 기반의 I/O
- InputStream과 OutputStream
- Byte와 Character 스트림
- 표준 스트림 (System.in, System.out, System.err)
- 파일 읽고 쓰기
스트림/버퍼/채널이란?
스트림
스트림은 흐름이라는 뜻을 가지고 있습니다. 람다의 스트림과 헷갈릴 수 있지만 전혀 다른 것입니다.
여기서 말하는 스트림은 입력에서 출력으로 흐르는 단방향 데이터 흐름을 말하는데, 자료의 입출력을 도와주는 중간 통로(매개체)라고 생각하면 좋을 것 같습니다.
그렇다면 여러 개의 데이터를 하나의 스트림으로 보낸다고 생각하면 어떻게 되는 걸까요?
큐(queue) 형식으로 진행된다고 생각하면 됩니다. 즉, 먼저 입력 받은 것이 가장 먼저 출력되는 시스템인 것입니다.
이러한 스트림은 데이터를 어떤 방식으로 전달하느냐에 따라서 2가지로 나뉩니다.
- 바이트 스트림(Byte Stream)
-> 데이터를 Byte 단위로 주고 받고, binary 데이터를 입출력하는 스트림입니다. 주로 미이지나 동영상 등의 모든 종유릐 데이터들을 송수한할 때 사용하며 대표적인 바이트 스트림에는 InputStream과 OutputStream이 있고 이 두 추상 클래스는 byte 기반 stream의 최고 조상입니다. - 문자 스트림(Character Stream)
-> 문자 단위로 인코딩 처리를 하는 스트림으로, 주로 텍스트 파일등을 송수신할 때 사용합니다.
버퍼
버퍼는 일반적인 입출력과 다르게, 한 곳에 저장한 뒤에 한 번에 보내는 방식입니다. 이렇게 버퍼를 사용하면 운영체제의 API 호출 횟수를 줄여서 입출력 성능을 개선할 수 있습니다.
채널
채널은 데이터가 흘러다니는 양방향 통로입니다. 양방향이기 때문에 input/output을 구분하지 않으며 스트림과 다르게 기본적으로 버퍼를 통해서만 read write를 할 수 있는 버퍼 방식입니다.
또한, NIO의 입출력 흐름에 사용된다는 것이 스트림과 다릅니다.
기존의 IO방식은 stream을 이용한 입/출력 방식으로 스트림에서 데이터가 입력되거나 출력하기 전까지 blocking(대기) 상태로 즉, 스레드는 입/출력 작업을 기다려야 하는 상태가 됩니다. 이러한 단점 때문에 NIO가 등장하게 되었습니다.
NIO는 blocking과 non-blocking의 특징을 모두 가집니다. 여기서 non-blocking이란 스레드가 대기 상태가 되지 않는 것으로, NIO는 스레드를 인터럽트함으로써 blocking 상태에서 빠져나올 수 있습니다.
InputStream과 OutputStream
위에서 잠깐 언급했듯이 InputStream과 OutStream은 모든 바이트 기반 스트림의 조상으로, 입출력을 처리할 수 있는 표준적인 방법을 제공하기 때문에 대상이 달라져도 동일한 방법으로 입출력이 가능해 프로그래밍 하기 편리합니다.
InputStream의 메서드
메서드 | 간단한 설명 |
int available() | 현재 읽을 수 있는 바이트 수를 반환 |
void close() | 현재 열려있는 InputStream을 닫는다 |
void mark(int readlimit) | InputStream에서 현재의 위치를 표시 |
boolean markSupported() | 해당 InputStream에서 mark()로 지정된 지점이 있는지에 대한 여부를 확인 |
abstract int read() | InputStream에서 한 바이트를 읽어서 int 값으로 반환 |
int read(byte[] b) | 인자 만큼의 데이터를 읽어서 b에 저장하고 읽은 바이트 수 반환 |
int read(byte b, int off, int len) | len만큼 읽어서 b의 off위치에 저장하고 읽은 바이트 수 반환 |
void reset() | mark()를 마지막으로 호출한 위치로 이동 |
long skip(long n) | InputStream에서 n바이트 만큼 데이터를 스킵하고 바이트 수를 반환 |
OutputStream의 메서드
메서드 | 간단한 설명 |
void close() | OutputStream을 닫는다 |
void flush() | 버퍼에 남아있는 출력 스트림을 출력 |
void write(byte[] b) | 버퍼의 내용을 출력 |
void write(byte[] b, int off, int len) | b 배열 안에 있는 시작 off부터 len만큼 출력 |
abstract void write(int b) | 정수 b의 하위 1바이트를 출력 |
표준 스트림 (System.in, System.out, System.err)
표준 스트림이란 프로그램과 환경(키보드, 모니터, 콘솔 등..) 사이에 연결된 입출력 스트림을 의미합니다. 이는 JVM이 메모리에 올라갈 때 생성하는 코드를 제공하기 때문에 별도의 스트림을 만들 필요가 없습니다.
System.in
콘솔로부터 입력을 받는 표준 스트림을 가리키는 상수로 InputStream으로 byte 단위를 입력 받을 수 있습니다.
하지만 InputStream은 ByteStream이기 때문에 한글을 입력받는 데 있어서 어려움이 있습니다. 이럴 때는 CharacterStream인 InputStreamReader를 활용할 수 있습니다.
그리고 2byte가 넘는 데이터를 읽고 싶다면 BufferedReader를 활용할 수도 있습니다.
System.out
콘솔로 출력을 하는 표준 스트림을 가리키는 상수로 System.out.println()을 생각해보면 이해가 쉽습니다.
System.err
표준 에러 출력 장치를 가리키는 상수입니다.
파일 읽고 쓰기 예시
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Test {
public static void main(String[] args) {
// 파일 쓰기
// try 블록 안에 리소스를 감싸서 코드가 끝나면 알아서 자원 반납하도록 한다.
try (FileWriter fw = new FileWriter("example.txt", true);
BufferedWriter bw = new BufferedWriter(fw)
) {
bw.write("1");
bw.newLine();
bw.write("2");
bw.newLine();
// 버퍼의 내용을 example.txt에 작성
bw.flush();
} catch (IOException e) {
System.out.println("error 발생");
}
File f = new File("example.txt");
if (f.isFile()) {
System.out.println("example.txt 파일 존재하고 있음");
}
//파일을 읽는 코드
try(
FileReader rw = new FileReader("example.txt");
BufferedReader br = new BufferedReader(rw);
){
String readLine = null;
//만약 읽을라인이 없다면 null을 리턴한다
while((readLine = br.readLine()) != null){
System.out.println(readLine);
}
}catch (IOException e){
System.out.println("error 발생");
}
}
}
예시 코드 결과

'Java' 카테고리의 다른 글
[Java] 람다식 (0) | 2022.10.27 |
---|---|
[Java] 제네릭 (0) | 2022.10.26 |
[Java] 애노테이션 (0) | 2022.10.24 |
[Java] Enum (0) | 2022.10.23 |
[Java] 멀티쓰레드 프로그래밍 (0) | 2022.10.22 |