자바 기본 13. I/O
13주차 과제: I/O
📌 목표
자바의 Input과 Ontput에 대해 학습하세요.
📌 학습할 것
- 스트림 (Stream) / 버퍼 (Buffer) / 채널 (Channel) 기반의 I/O
- InputStream과 OutputStream
- Byte와 Character 스트림
- 표준 스트림 (System.in, System.out, System.err)
- 파일 읽고 쓰기
📜 시작에 앞서
- 백기선 님의 라이브 스터디(2020년 11월부터 2021년 3월까지) 커리큘럼을 따라 진행한 학습입니다
- 뒤늦게 알게 되어 스터디 참여는 못했지만 남아있는 스터디 깃허브 주소와 유튜브 영상을 참고했습니다
📑 스트림 (Stream) / 버퍼 (Buffer) / 채널 (Channel) 기반의 I/O
스트림
- 데이터가 들어온 순서로 나가는 단방향 통로(queue와 같은 FIFO 구조)
- 단방향이기 때문에 입력과 출력을 모두 수행하려면 2개의 스트림 생성
- 블로킹 방식(동기적)으로 동작
- 데이터의 흐름 입출력 진행시 해당 쓰레드는 다른 작업을 할 수 없는 상태가 된다
버퍼
- 임시로 데이터를 담아둘 수 있는 메모리 공간
- 기존 IO에서는 보조 스트림
BufferedInputStream
BufferedOutputStream
사용해 버퍼 제공 가능 - NIO는 기본적으로 버퍼 사용
- 기존 IO에서는 보조 스트림
- 데이터를 모아서 처리하여 OS레벨의 I/O 시스템 콜 수를 줄이기 때문에 입출력 성능 빨라진다
- NIO에서는 데이터 타입별로
java.nio.Buffer
를 상속해 별도의 클래스 제공 - NIO에서는 관련 메서드를 통해 넌다이렉트 버퍼와 다이렉트 버퍼 선택 가능
- 다이렉트 버퍼 사용시 JVM이 아닌 운영체제가 관리하는 메모리 공간을 사용하여, 운영체지 native I/O 작업 중 중간 버퍼로 버퍼의 내용을 복사하는 것을 방지하여 입출력 성능이 높다
채널
- NIO에서 등장한 IO에 대한 새로운 추상화
- 데이터가 양방향으로 다닐 수 있기 때문에 입력과 출력을 위해 두 통로를 생성할 필요 X
- 버퍼를 통해서만 읽고 쓰기 수행
- 블로킹 방식과 논블로킹 방식 모두 가능
📑 Byte와 Character 스트림
InputStream과 OutputStream
- 바이트 기반 스트림 최상위 클래스
InputStream
출저: 오니님의짱깬뽀: java 스트림의 개념, 종류/파일 입출력/InputStream/OutputStream/Reader/Writer
주요 메서드
메서드 | 설명 |
---|---|
void cloase() | 스트림을 닫고 사용하던 자원을 반환 |
abstract int read() | 다음 1byte를 읽어 온다. 읽어올 데이터가 없다면 -1 반환. |
int read(byte[] b) | 배열 b의 크기만큼 다음 byte를 읽으며 배열을 채운다. 읽은 데이터 수를 반환하며, 읽을 데이터가 없다면 -1 반환 |
int read(byte[] b, inf off, int len) | 최대 len개의 다음 byte를 읽고, 배열 b의 off 부터 저장. 읽은 데이터 수 반환하며 읽을 데이터 없다면 -1 반환 |
OutputStream
출저: 오니님의짱깬뽀: java 스트림의 개념, 종류/파일 입출력/InputStream/OutputStream/Reader/Writer
주요 메서드
메서드 | 설명 |
---|---|
void close() | 입력소스를 닫고 사용하던 자원을 반환 |
void flush() | 스트림의 버퍼에 있는 모든 데이터를 출력소스에 쓴다 |
abstract void write(int b) | 주어진 값을 출력소스에 쓴다 |
void write(byte[] b) | b에 저장된 모든 데이터를 출력소스에 쓴다 |
void write(byte[] b, int off, int len) | b의 off부터 len개의 데이터를 읽어서 출력소스에 쓴다 |
flush()
는 버퍼가 있는 경우에만 사용 의미가 있다
Reader와 Wirter
- 문자 기반 최상위 입출력 스트림 클래스
- 자바에서 char형이 2byte기 때문에 2byte로 스트림 처리
- 문자기반 스트림은 여러 종류의 인코딩과 자바에서 사용하는 유니코드(UTF-16)간의 변환을 자동으로 처리
- 주요 메서드는 InputStream/OutputStream 거의 동일하므로 생략
출저: 오니님의짱깬뽀: java 스트림의 개념, 종류/파일 입출력/InputStream/OutputStream/Reader/Writer
출저: 오니님의짱깬뽀: java 스트림의 개념, 종류/파일 입출력/InputStream/OutputStream/Reader/Writer
📑 표준 스트림 (System.in, System.out, System.err)
- 콘솔을 통한 데이터 입출력을 위한 스트림
java.lang.System
public final class System {
...
public final static InputStream in = nullInputStream();
public final static PrintStream out = nullPrintStream();
public final static PrintStream err = nullPrintStream();
...
}
- 선언부와 달리 in, out의 경우 실제로는 버퍼를 이용하는 BufferedInputStream과 BufferedOutputStream의 인스턴스 사용
- err은 OS에 의해 버퍼링 되지 않고 즉시 출력
✏️ 보조 스트림
보조 스트림
- 스트림과 연결되, 여러 편리한 기능을 제공하는 스트림
- 보조 스트림 만으로는 입출력 불가, 스트림 생성후 이에 연결
- 스트림에 여러 보조 스트림 연쇄 연결 가능
보조_스트림 변수 = new 보조_스트림(연결_스트림)
//기반 스트림
FileInputStream fis = new FileInputStream("hello.text");
//보조 스트림 생성
BufferedInputStream bis = new BufferedInputStream(fis);
입력 | 출력 | 설명 |
---|---|---|
BufferedInputStream | BufferedOutputStream | 버퍼를 이용한 입출력 성능 개선 |
DataInputStream | DataOutputStream | 프리미티브 타입 단위로 데이터 제어 |
FilterInputStream | FilterOutputStream | 필터를 이용한 입출력 처리 |
ObjectInputStream | ObjectOutputStream | 데이터 객체 단위로 처리, 직렬화와 역직렬화 관련 |
PrintStream | print() 관련 버퍼 이용한 추가적인 기능 제공 print(), println(), printf() | |
PushbackInputStream | 버퍼를 이용해 읽어온 데이터 되돌리기 가능 | |
SequenceInputStream | 두 개의 스트림을 하나로 연결 |
보조 스트림은 어떻게 스트렘에 동적으로 새로운 책임을 추가할까?
- 데코레이터 패턴
데코레이터 패턴
- 런타임 동안 객체에 동적으로 새로운 책임을 추가할 수 있게 해준다(탈부착 가능한 책임)
- 상속은 정적이고 전체 클래스에 적용되기 때문에 실현 불가
출저: w3sdesign
데코레이터 패턴 적용전
- 상속을 통해 서브클래스를 계속 만드는 것이 비효율적이다
- 더 많은 옵션을 추가할 수록 조합에 따른 서브클래스 수의 증가량이 늘어난다
데코레이터 패턴 적용후
코드
public interface MyOutput {
public void write();
}
public class MyHelloOutput implements MyOutput{
@Override
public void write() {
System.out.println("MyHelloOutput: hello");
}
}
public abstract class MyOutputDecorator implements MyOutput {
private MyOutput out;
public MyOutputDecorator(MyOutput out) {
this.out = out;
}
@Override
public void write() {
out.write();
}
}
public class MyBufferdOutput extends MyOutputDecorator{
public MyBufferdOutput(MyOutput out) {
super(out);
}
@Override
public void write() {
System.out.println("MyBufferdOutput: buffer...");
super.write();
}
}
public class MyFilterOutput extends MyOutputDecorator{
public MyFilterOutput(MyOutput out) {
super(out);
}
@Override
public void write() {
System.out.println("MyFilterOutput: filter...");
super.write();
}
}
public class DecoratorPattern {
public static void main(String[] args) {
new MyHelloOutput().write();
System.out.println("===========================");
new MyBufferdOutput(new MyHelloOutput()).write();
System.out.println("===========================");
new MyFilterOutput(
new MyBufferdOutput(
new MyHelloOutput())
).write();
}
}
/*
MyHelloOutput: hello
===========================
MyBufferdOutput: buffer...
MyHelloOutput: hello
===========================
MyFilterOutput: filter...
MyBufferdOutput: buffer...
MyHelloOutput: hello
*/
관련 읽을 거리
- 기계인간 Jhon Grib: 데코레이터 패턴 (Decorator Pattern)
- 사바라다는 차곡차곡: Java에서 발견한 디자인패턴_Decorator Pattern
📑 파일 읽고 쓰기
- 포스트에서 NIO를 다루지 않았으므로 IO에서 파일을 읽고 쓰는 방법을 다룬다
- 다루는 파일의 종류에 따라 바이트 기반, 문자 기반의 입출력 적절히 선택
- 바이트 기반의 FileInputStream/FileOutputStream
- 문자 기반의 FileReader/FileWriter
- 파일의 공백을 제거해
*.min.*
처럼 해주는 예제- 문자 기반 파일을 다룰 것이기 때문에 FileReader/FileWriter 사용
- 버퍼 이용한 입출력 성능 향상 위해 보조 스트림 BufferedReader/BufferedWriter 사용
package week13;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class MinMaker {
public static void main(String[] args) {
try (BufferedReader bfr = new BufferedReader(new FileReader(args[0]));
BufferedWriter bfw = new BufferedWriter(new FileWriter(args[1]))){
int data = 0;
while((data = bfr.read()) != -1){
if(data != '\t' && data != '\n' && data != ' ' && data != '\r'){
bfw.write(data);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
D:\javaBox> java week13.MinMaker week13/MinMaker.java week13/MinMaker.min.java
MinMaker.min.java 파일 생성
packageweek13;importjava.io.BufferedReader;importjava.io.BufferedWriter;importjava.io.FileReader;importjava.io.FileWriter;importjava.io.IOException;publicclassMinMaker{publicstaticvoidmain(String[]args){try(BufferedReaderbfr=newBufferedReader(newFileReader(args[0]));BufferedWriterbfw=newBufferedWriter(newFileWriter(args[1]))){intdata=0;while((data=bfr.read())!=-1){if(data!='\t'&&data!='\n'&&data!=''&&data!='\r'){bfw.write(data);}}}catch(IOExceptione){e.printStackTrace();}}}
📑📌📜✏️
Author And Source
이 문제에 관하여(자바 기본 13. I/O), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@butterf12/자바-기본-13.-IO저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)