♨학습내용
☞ 스트림 (Stream) / 버퍼 (Buffer) / 채널 (Channel) 기반의 I/O
☞ InputStream과 OutputStream
☞ Byte와 Character 스트림
☞ 표준 스트림 (System.in, System.out, System.err)
☞ 파일 읽고 쓰기
- 입출력 이란?
- 입출력(I/O)란 Input과 Output의 약자로 입력과 출력, 간단히 입출력이라 한다.
- 입출력은 컴퓨터 내부 또는 외부 장치와 프로그램간의 데이터를 주고 받는 것을 말한다.
- 키보드로부터 데이터를 입력받거나, System.out.println()을 이용해 모니터 화면에 출력하는 것을 말한다.
- 스트림 (Stream) / 버퍼 (Buffer) / 채널 (Channel) 기반의 I/O
- 스트림 이란?
- 연속된 데이터의 흐름. 입출력 진행 시 다른 작업을 할 수 없는 블록킹 상태가 된다.
- 입출력을 변경하기 편하고, 동일한 프로그램 구조를 유지할 수 있다.
- 단방향으로 흐르기 때문에 입력과 출력을 동시에 할 수 없다.
- 버퍼 란?
- byte, char, int 등 기본 데이터 타입을 저장할 수 있는 저장소. 배열과 마찬가지로 제한된 크기에 순서대로 데이터를 저장한다.
- 데이터를 저장하기 위한 것이지만 실제 사용은 채널을 통해 데이터를 주고 받을 때 사용된다.
- 채널을 통해 소켓, 파일 등에 데이터를 전송하거나 읽어올 때 버퍼를 사용함으로써 불필요한 데이터의 양을 줄일 수 있고, 서버의 전체 처리량을 늘릴 수 있다.
- 채널 이란?
- 데이터가 통과하는 쌍방향 통로. 버퍼와 데이터를 주고 받는다.
- 채널에는 소켓과 연결된 SocketChannel, 파일과 연결된 FileChannel, 파이프와 연결된 Pipe.SinkChannel 과 Pipe.SourceChannel 등이 존재하며, 서버소켓과 연결된 ServerSocketChannel 도 존재한다.
- IO vs NIO
- IO 의 방식으로 각각의 스트림에서 read() 와 write() 가 호출이 되면 데이터가 입력 되고, 데이터가 출력되기전까지, 스레드는 블로킹(멈춤) 상태가 된다.
- 이렇게 되면 작업이 끝날때까지 기다려야 하며, 그 이전에는 해당 IO 스레드는 사용할 수 없게 되고, 인터럽트도 할 수 없다.
- 블로킹을 빠져나오려면 스트림을 닫는 방법 밖에 없다.
- NIO(New I/O) 기존 IO의 단점을 보완하기 위해 java 4부터 추가된 패키지이다.
- 블로킹 상태에서는 Interrupt를 이용하여 빠져나올 수 있다.
IO | NIO | |
입출력 방식 | 스트림 방식 | 채널방식 |
버퍼 방식 | 논버퍼 | 버퍼 |
비동기 방식 | 지원안함 | 지원 |
블로킹/ 논블로킹 방식 | 블로킹 방식만 지원 (동기) |
블로킹/ 논블로킹 모두 지원 (동기/ 비동기 모두 지원) |
※ non-buffer vs. buffer
- IO에서는 출력 스트림이 1바이트를 쓰면 입력 스트림이 1바이트를 읽는다.
- 이런 시스템은 대체로 느리다.
- 하지만 버퍼를 사용해서 한 번에 입력받고 출력하는 것이 가능하므로 성능이 좋아진다.
- IO에서는 버퍼를 제공해주는 보조 스트림인 BufferedInputStream, BufferedOutputStream을 연결해서 사용하기도 한다.
- 하지만 NIO는 기본적으로 버퍼를 사용하기 때문에 IO보다 입출력 성능이 좋다.
- 채널은 버퍼에 저장된 데이터를 출력하고, 입력된 데이터를 버퍼에 저장한다.
※ 블로킹 vs. 넌블로킹
- 입력 스트림의 read() 메서드를 호출하면 데이터가 입력되기 전 까지 스레드는 블로킹(대기 상태)가 되므로 아무일도 할 수가 없고 블로킹 상태를 인터럽트하여 빠져나올 수도 없다. write() 메서드도 마찬가지이다.
- NIO는 블로킹, 넌블로킹의 특징을 모두 가지고 있는데 IO와의 차이점은 블로킹 시 인터럽트하여 스레드를 빠져나올 수 있다는 것이다.
- NIO의 넌블로킹은 입출력 작업준비가 완료된 채널만 선택해서 작업 스레드가 처리하기 때문에 작업 스레드가 블로킹 되지 않는다.
- InputStream과 OutputStream
- InputStream
- 바이트 기반 입력 스트림의 최상위 추상 클래스이다.
- 모든 바이트 기반 입력 스트림은 이 클래스를 상속 받아서 만들어진다.
- 버퍼, 파일, 네트워크 단에서 입력되는 데이터를 읽어오는 기능을 수행한다.
- InputStream의 주요 메소드
메서드 | 내용 |
int available() | 스트림으로부터 읽어올 수 있는 데이터의 크기를 반환 |
void close() | 닫음으로써 사용하고 있던 자원을 반환 |
void mark(int readlimit) | InputStream에서 현재 위치를 표시 해줌 |
boolean markSupported() | 해당 InputStream에서 mark()로 지정된 지점이 있는지에 대한 여부 |
abstract int read() | 1 byte를 읽어온다. (0~255사이의 값.) 더 이상 읽어올 값이 없으면 -1을 반환 abstract 추상 메서드임으로 InputStream의 자손들은 자신의 상황에 알맞게 구현해야함 |
int read(byte[] b) | 배열 b의 크기만큼 읽어서 배열을 채우고 읽어 온 데이터의 수를 반환 반환하는 값은 항상 배열의 크기보다 작거나 같음 |
int read(byte[] b, int off, int len) | 최대 len개의 byte를 읽어서, 배열 b의 지정된 위치(off)부터 저장 실제로 읽어 올 수 있는 데이터가 len개보다 적을 수도 있음 |
void reset() | 스트림에서의 위치를 마지막으로 mark()이 호출되었던 위치로 되돌림 |
long skip(long n) | 스트림에서 주어진 길이(n) 만큼 건너뜀 |
InputStream
try (FileInputStream fis = new FileInputStream(new File(fileName))) {
int content;
// 돌면서 byte를 읽고 file의 끝에 도달하면 -1을 return한다.
while ((content = fis.read()) != -1) {
System.out.println((char)content);
}
} catch (IOException e) {
e.printStackTrace();
}
- OutputStream
- 바이트 기반 출력 스트림의 최상위 추상 클래스이다.
- 모든 바이트 기반 출력 스트림은 이 클래스를 상속 받아서 만들어진다.
- 버퍼, 파일, 네트워크 단으로 데이터를 내보내는 기능을 수행한다.
- OutputStream의 주요 메소드
메서드 | 내용 |
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개 만큼만을 읽어서 출력소스에 씀 |
OutputStream
try (FileOutputStream outputStream = new FileOutputStream(file, false)) {
int read;
byte[] bytes = new byte[DEFAULT_BUFFER_SIZE];
while ((read = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, read);
}
}
- Byte와 Character 스트림
- InputStream과 OutputStream은 대표적인 byteStream이다.
- 1 byte 단위로 데이터를 입출력한다.
- characterStream은 2 byte단위로 데이터를 전송한다.
- 유니코드는 기본단위가 2 byte로 문자를 입출력할때 characterStream을 쓰는것이 적절하다.
- characterStream은 클래스명에 Reader, Writer가 들어가 있다.
- BufferedReader
// 리소스 폴더로부터 파일을 불러온다.
InputStream is = InputStreamToReaderExample.class
.getClassLoader()
.getResourceAsStream("file/abc.txt");
// BufferedReader -> InputStreamReader -> InputStream
// try-with-resources, auto close
String line;
try (BufferedReader br = new BufferedReader(
new InputStreamReader(is, StandardCharsets.UTF_8))) {
// read line by line
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
- BufferedWriter
try (FileWriter writer = new FileWriter("app.log");
BufferedWriter bw = new BufferedWriter(writer)) {
bw.write(content);
} catch (IOException e) {
System.err.format("IOException: %s%n", e);
}
- 표준 스트림 (System.in, System.out, System.err)
- 콘솔을 통해 데이터입력과 콘솔로의 데이터 출력을 의미한다.
- 자바에서는 표준 입출력을 위해 3가지 입출력 스트림 in,out,err를 제공한다.
- 자바앱의 실행과 동시에 자동으로 생성되기 때문에 별도의 스트림없이 사용이 가능하다.
- System.in
- 콘솔로부터 데이터를 입력받는데 사용된다.
- System.out
- 콘솔로 데이터를 출력하는데 사용된다.
- System.err
- 콘솔로 데이터를 출력하는데 사용된다.
- 버퍼링 지원을 하지 않는다.
- 파일 읽고 쓰기
- 파일 읽기 (read)
- FileReader 객체와 BufferedReader객체가 사용된다.
String fileName = "C:/test.txt" // 읽어들일 파일명
FileReader fileReader = new FileReader(fileName);
BufferedReader reader = new BufferedReader(fileReadrer);
String line = null;
while((line = reader.readLine()) != null) { // readLine() 은 한줄 단위로 읽어들임
System.out.println(line);
}
reader.close();
public class FileReadTest {
public static void main(String[] args) {
//파일 객체 생성
File file = new File("/Users/zayson/Documents/spring study/sample.rtf");
try {
//입력 스트림, 입력 버퍼 생성
FileReader fileReader = new FileReader(file);
BufferedReader br = new BufferedReader(fileReader);
String line = "";
//한줄 씩 읽기
while((line = br.readLine())!=null) {
System.out.println(line);
}
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 파일 쓰기 (write)
- FileWriter객체와 BufferedWriter객체가 사용된다.
String fileName = "C:/test.txt" // 생성할 파일명
String str = "abc" // 작성할 문자열
FileWriter fileWriter = new FileWriter(fileName);
BufferedWriter out = new BufferedWriter(fileWriter);
out.write(str); // 쓰기
out.newLine(); // 줄바꾸기
out.close();
public class FileWriteTest {
public static void main(String[] args) {
try {
//파일 객체 생성
File file = new File("/Users/zayson/Documents/spring study/write_test.txt");
BufferedWriter bw = new BufferedWriter(new FileWriter(file));
if (file.isFile() && file.canWrite()) {
//쓰기
bw.write("Write 1 line");
bw.newLine();
bw.write("두번째 라인 추가");
bw.newLine();
bw.write("마지막 확인");
bw.close();
}
} catch (IOException e) {
System.out.println(e);
}
}
}
'Study > Java_study' 카테고리의 다른 글
Java_study_15 (람다식) (0) | 2021.09.27 |
---|---|
Java_study_14 (제네릭) (0) | 2021.09.20 |
Java_study_12 (애노테이션) (0) | 2021.09.14 |
Java_study_11 (Enum) (0) | 2021.09.07 |
Java_study_10 (멀티쓰레드 프로그래밍) (0) | 2021.08.30 |