목표
자바의 Input과 Ontput에 대해 학습하세요.
학습할 것 (필수)
- 스트림 (Stream) / 버퍼 (Buffer) / 채널 (Channel) 기반의 I/O
- InputStream과 OutputStream
- Byte와 Character 스트림
- 표준 스트림 (System.in, System.out, System.err)
- 파일 읽고 쓰기
1. 스트림 (Stream) / 버퍼 (Buffer) / 채널 (Channel) 기반의 I/O
IO
- 데이터 입력(Input)과 출력(Output)을 다룬다.
NIO
- 자바 4부터 새로운 입출력 java.nio 패키지가 포함됐다.
- 자바 7로 버전업하면서 기존의 IO와 NIO 사이의 일관성 없는 클래스 설계를 잡고, 비동기 채널 등의 네트워크 지원을 대폭 강화한 NIO.2 API가 추가됐다.
스트림
- 스트림이란 데이터를 운반하는데 사용되는 연결통로
- 단방향 통신만 가능하기 때문에 하나의 스트림으로 입력과 출력을 동시에 처리할 수 없다.
- 입력과 출력을 하기 위해선 입력 스트림과 출력 스트림 2개가 필요하다.
- 스트림은 먼저 보낸 데이터를 먼저 받게 되어 있으며 중간에 건너뜀 없이 연속적으로 데이터를 주고 받는다.(queue와 FIFO 구조)
버퍼(Buffer)
- 읽고 쓰기가 가능한 메모리 배열
- 복수 개의 바이트를 한번에 입력받고 출력할 수 있다.(빠른 성능)
- NIO는 기본적으로 버퍼를 사용하므로 입출력 시 IO보다 성능이 좋다.
- NIO는 읽은 데이터를 무조건 버퍼에 저장하므로 버퍼 내에서 데이터의 위치를 이동해 가면서 필요한 부분만 읽고 쓸 수 있다.
메소드 | 설명 |
---|---|
int available() | 현재 읽을 수 있는 바이트 수를 반환한다 |
void close() | 현재 열려있는 InputStream을 닫는다 |
void mark(int readlimit) | InputStream에서 현재의 위치를 표시해준다. |
boolean markSupported() | 해당 InputStream에서 mark()로 지정된 지점이 있는지에 대한 여부를 확인한다. |
abstract int read() | InputStream에서 한 바이트를 읽어서 int값으로 반환한다. |
int read(byte[] b) | byte[] b 만큼의 데이터를 읽어서 b에 저장하고 읽은 바이트 수를 반환한다. |
int read(byte[] b, int off, int len) | len만큼 읽어서 byte[] b 의 off 위치에 저장하고 읽은 바이트 수를 반환한다. |
void reset() | mark()를 마지막으로 호출한 위치로 이동 |
long skip(long n) | InputStream에서 n바이트만큼 데이터를 스킵하고 바이트 수를 반환한다. |
OutputStream의 메소드
메소드 | 설명 |
---|---|
abstract void write(int b) | 정수 b의 하위 1바이트를 출력한다 |
void write(byte[] b) | 버퍼의 내용을 출력한다 |
void write(byte[] b, int off, int len) | b배열 안에 있는 시작 off부터 len만큼 출력한다 |
채널(Channel)
- blocking 방식과 Non-Buffer의 특징으로 인해 입출력 속도가 느렸음 -> 이를 해결하기 위해NIO(New Input Output)가 java.nio 패키지에 포함되어 나옴 -> Channel이 그 NIO의 기본 입출력 방식
- 데이터가 통과하는 양방향 통로이며, 채널에서 데이터를 주고 받을 때 사용 되는 것이 버퍼이다.
- 채널에는 소켓과 연결된 SocketChannel, 파일과 연결된 FileChannel, 파이프와 연결된 Pipe.SinkChannel과 Pipe.Source등이 존재하며, 서버소켓과 연결된 ServerSocketChannel도 존재한다.
IO VS NIO
- IO 의 방식으로 각각의 스트림에서 read() 와 write() 가 호출이 되면 데이터가 입력 되고, 데이터가 출력되기전까지, 스레드는 블로킹(멈춤) 상태가 된다. 이렇게 되면 작업이 끝날때까지 기다려야 하며, 그 이전에는 해당 IO 스레드는 사용할 수 없게 되고, 인터럽트도 할 수 없다. 블로킹을 빠져나오려면 스트림을 닫는 방법 밖에 없다.
- NIO 의 블로킹 상태에서는 Interrupt 를 이용하여 빠져나올 수 있다.
입출력 방식 | 스트림 | 채널 |
버퍼 방식 | Non-Buffer | Buffer |
비동기 방식 지원 | X | O |
Blocking/Non-Blocking 방식 | Blocking Only | 둘 다 가능 |
사용 케이스 | 연결 클라이언트가 적고, IO 가 큰 경우(대용량) | 연결 클라이언트가 많고, IO 처리가 작은 경우(저용량) |
2. InputStream과 OutputStream
- InputStream
- 바이트 기반 입력 스트림의 최상위 추상 클래스
- 모든 바이트 기반 입력 스트림은 이 클래스를 상속 받아서 만들어 진다.
- 버퍼, 파일, 네트워크 단에서 입력되는 데이터를 읽어오는 기능을 수행한다.
public abstract class InputStream{
public abstract int read() throws IOException;
public int read(byte b[]) throws IOException;
public int read(byte b[], int off, int len) throws IOException;
public long skip(long n) throws IOException;
public int available() throws IOException;
public void close() throws IOException;
public synchronized void mark(int readlimit);
public synchronized void reset() throws IOException;
public boolean markSupported();
}
메서드 | 설명 |
read() | 입력 스트림으로 부터 1바이트를 읽어서 바이트를 리턴 |
read(byte[] b) | 입력 스트림으로부터 읽은 바이트들을 매개값으로 주어진 바이트 배열 b 에 저장하고 실제로 읽은 바이트 수를 리턴 |
read(byte[] b, int off, int len) | 입력 스트림으로부터 len 개의 바이트만큼 읽고 매개값으로 주어진 바이트 배열 b[off] 부터 len 개까지 저장. 그리고 실제로 읽은 바이트 수인 len 개를 리턴. 만약 len 개를 모두 읽지 못하면 실제로 읽은 바이트 수를 리턴 |
close() | 사용한 시스템 자원을 반납하고 입력 스트림 닫기 |
- OutputStream
- 바이트 기반 출력 스트림의 최상위 추상 클래스
- 모든 바이트 기반 출력 스트림은 이 클래스를 상속 받아서 만들어 진다.
- 버퍼, 파일, 네트워크 단으로 데이터를 내보내는 기능을 수행한다.
public abstract class OutputStream{
public abstract void write(int i) throws IOException;
public void write (byte b[]) throws IOException;
public void write (byte b[], int off, int len) throws IOException;
public long flush() throws IOException;
public void close() throws IOException;
}
메서드 | 설명 |
write(int b) | 출력 스트림으로부터 1바이트를 보낸다. (b의 끝 1바이트) |
write(byte[] b) | 출력 스트림으로부터 주어진 바이트 배열 b의 모든 바이트를 보낸다. |
write(byte[] b, int off, int len) | 출력 스트림으로 주어진 바이트 배열 b[off] 부터 len 개까지의 바이트를 보낸다. |
flush() | 버퍼에 잔류하는 모든 바이트를 출력한다. |
close() | 사용한 시스템 자원을 반납하고 입력 스트림 닫기 |
3. Byte와 Character 스트림
Byte기반 스트림
- 입출력 단위가 1byte
- InputStream - 바이트 입력 스트림
Byte Input Stream
InputStream은 Byte Input을 수행하는데 필요한 메서드를 정의하는 추상 class이다.
자바는 객체를 생성하고 생성된 객체와 Byte Stream과 연결함으로써 파일을 연다. - OutStream - 바이트 출력 스트림
Byte Output Stream은 Byte Output을 수행하는 필요한 메서드를 정의한 추상 class이다.
장치와 연결된 두 개의 Output Stream은 System.out, System.err를 생성한다.
Character 기반 스트림
- 처리할 데이터가 문자인 경우에 사용한다.
- 문자는 스트림은 16bit 유니코드 문자를 주고 받는다.
public class CharacterStream {
public static void main(String[] args) {
try {
FileReader input = new FileReader("a.text");
FileWriter output = new FileWriter("b.txt");
int a;
while((a = input.read()) != -1){
output.write(a);
}
input.close();
output.close();
}catch(IOException e) {
e.printStackTrace();
}
}
}
4. 표준 스트림 (System.in, System.out, System.err)
System.in, System.out, System.err은 자바 어플리케이션의 실행과 동시에 사용할 수 있게 자동적으로 생성되기 때문에 개발자가 별도로 스트림을 생성하는 코드를 작성하지 않고 사용 가능하다.
in, out, err는 System에 정의된 클래스(static) 변수이다.
아래의 코드처럼 InputStream과 PrintStream이 선언부로 되어있지만, BufferInputStream과 BufferOutputStream의 인스턴스를 사용한다.
public final class System {
public final static InputStream in = nullInputStream();
public final static PrintStream out = nullInputStream();
public final static PrintStream err = nullInputStream();
---
}
5. 파일 읽고 쓰기
1. 특정 파일 1개 읽기
String path = "C:\\dev\filterSearch\\";
String fileNm = "FileSearch.xml";
// 파일 객체 생성
File file = new File(path + fileNm);
2. 폴더 내 파일 모두 읽기
String path = "C:\\dev\fileSearch\\";
// 폴더 내 파일 객체 배열 생성
File folder = new(path);
File[] fileList = folder.listfiles();
- 폴더 내 파일 검색일 경우, 아래 내용을 객체 배열의 for문 안에 작성하면 된다.
for(File file : fileList){ if( file.isFile() && file.canRead() ){ // 파일이 파일인지, && 읽을 수 있는지 // 아래 내용 } }
3. 파일 읽기 (FileReader / BufferedReader)
// 파일 입력스트림 생성
FileReader fileReader = new FileReader(file);
// 입력 버퍼 생성
BufferReader bufferReader = new BufferReader(fileReader);
// 읽기 수행
String line = "";
String result = "";
int cnt = 0;
while ((line = bufferReader.readLine()) != null ){ // 파일 내 문자열을 1줄씩 읽기 while
if(line.contaions("찾을 문자열")){ // 찾고자하는 문자열이 있을 때 작성
result += line + "|n"; // 한줄씩 읽어 결과에 추가
cnt++; // 찾을 문자열이 몇개 포함되었는지 체크
}
}
4. 파일 쓰기 (FileReader / BufferedReader)
// copy 폴더에 새로운 파일 생성
File newFile = new File(path + "copy\\" + fileNm);
// 파일 출력스트림 생성
FileWriter fileWriter = new FileWriter(newFile);
// 출력 버퍼 생성
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
// 파일 출력
if ( !result.isEmpty() ){
bufferedWriter.writer(result);
}
// 폴더 내 읽기 for문이면 여기서 닫아주는게 좋음
bufferedWriter.flush();
bufferedWriter.close();
출처: https://studyingazae.tistory.com/16 [똘아재의 노트:티스토리]
출처: https://babgeuleus.tistory.com/entry/IO-백기선-자바라이브스터디 [EVO:티스토리]
출처: https://doyoung.tistory.com/26 [귀찮다고 망설이지 말자.:티스토리]
'Java > JavaStudy' 카테고리의 다른 글
Java Study 7주차 - 람다식 (0) | 2023.11.16 |
---|---|
Java Study 7주차 - 제네릭 (0) | 2023.11.16 |
Java Study 6주차 - 열거형, 어노테이션 (0) | 2023.11.12 |
Java Study 5주차 - 멀티쓰레드 프로그래밍 (0) | 2023.11.05 |
Java Study 5주차 - 예외 처리 (0) | 2023.11.05 |