티스토리 뷰
스트림 (Stream) / 버퍼 (Buffer) / 채널 (Channel) 기반의 I/O
스트림
- 데이터를 운반하는데 사용하는 연결통로
- 단방향 통신만 가능
- 입력, 출력을 동시에 하려면 입력스트림, 출력스트림 총 2개의 스트림이 필요
- 먼저 보낸 데이터를 먼저 받음 (First In First Out)
버퍼
- 스트림의 입출력 효율을 높이기 위해 사용
- 한 바이트씩 입출력하는 것보다 한 번에 여러 바이트를 입출력하는 것이 빠름
- BufferedInputStream
- read() 호출 시 입력소스로부터 버퍼 크기만큼 데이터를 읽어다 자신 내부 버퍼에 저장. 외부 입력소스로부터 읽는 것보다 내부 버퍼로 부터 읽는 것이 훨씬 빠름
- BufferedOutputStream
- write() 호출시 내부 버퍼에 출력할 내용을 저장. 버퍼가 가득 차거나 flush()를 호출했을 때 버퍼 내용을 출력소스에 출력하고 버퍼를 비움
- close() 호출시 내부적으로 flush() 호출
public class BufferedOutputStreamEx1 {
public static void main(String[] args) {
try {
FileOutputStream fos = new FileOutputStream("123.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos, 5);
for (int i = '1'; i < '9'; i++) {
bos.write(i);
}
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
NIO
- Channel : Stream과 달리 양방향성. 즉, InputChannel , OutputChannel을 따로 만들 필요 없음.
- Buffer 를 통해서만 읽고 쓰기 가능
- 논블로킹, 블로킹 모두 가능
- blocking : 기존 Stream 방식의 IO. Thread가 read(), write() 호출시 해당 Thread는 available한 data가 있거나 data가 완전히 써질 때까지 blocked 됨
- non-blocking : data가 read되거나 write 될 때까지 기다리지 않음.
- Selector
- 하나의 Thread가 여러 개의 channel을 모니터링.
- input이 available한 channel이 있거나 writing할 준비가 된 channel이 있으면 알려줌.
InputStream과 OutputStream
- 스트림은 바이트 단위로 데이터를 전송
- 입출력 대상에 따라 입출력 스트림 종류가 결정됨
- FileInputStream / FileOutputStream: 파일 전송
- ByteArrayInputStream / ByteArrayOutputStream : 메모리 전송
- PipedInputStream / PipedOutputStream: 프로세스 간 통신
- AudioInputStream / AudioOutputStream : 오디오
- 위 클래스들은 모두 InputStream / OutputStream을 상속
public class IOEx1 {
public static void main(String[] args) {
byte[] inSrc = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
byte[] outSrc = null;
ByteArrayInputStream input = null;
ByteArrayOutputStream output = null;
input = new ByteArrayInputStream(inSrc);
output = new ByteArrayOutputStream();
int data = 0;
while ((data = input.read()) != -1) {
output.write(data);
}
outSrc = output.toByteArray();
System.out.println("inSrc = " + Arrays.toString(inSrc));
System.out.println("outSrc = " + Arrays.toString(outSrc));
}
}
public class IOEx2 {
public static void main(String[] args) {
byte[] inSrc = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
byte[] outSrc = null;
byte[] temp = new byte[10];
ByteArrayInputStream input = null;
ByteArrayOutputStream output = null;
input = new ByteArrayInputStream(inSrc);
output = new ByteArrayOutputStream();
input.read(temp, 0, temp.length); //읽어 온 데이터를 temp에 담는다.
output.write(temp, 5, 5); //temp[5]부터 5개의 데이터를 write
outSrc = output.toByteArray();
System.out.println("inSrc = " + Arrays.toString(inSrc));
System.out.println("temp = " + Arrays.toString(temp));
System.out.println("outSrc = " + Arrays.toString(outSrc));
}
}
inSrc = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
temp = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
outSrc = [5, 6, 7, 8, 9]
InputStream
- abstract int read()
- 입력스트림으로부터 1 byte를 읽어서 반환. 읽을 수 없으면 -1을 반환
- int read(byte[] b)
- 입력스트림으로부터 b의 크기만큼 데이터를 읽어서 배열 b에 저장
- int read(byte[] b, int off, int len)
- 입력스트림으로부터 len개의 byte를 읽어서 byte배열 b의 off위치부터 저장
- int available()
- 스트림으로부터 읽어 올 수 있는 데이터의 크기를 반환
- void close()
- 스트림을 닫고 사용하고 있던 자원을 반환
- void mark(int readlimit)
- 현재 위치를 표시. 나중에 reset() 에 의해 표시해 놓은 위치로 돌아갈 수 있음. readlimit은 되돌아갈 수 있는 byte의 수를 의미.
- boolean markSupported()
- mark() , reset() 의 지원 여부
- void reset()
- 스트림에서의 위치를 마지막으로 mark()가 호출된 위치로 되돌림
- long skip(long n)
- 스트림에서 주어진 길이(n) 만큼을 건너뜀
OutputStream
- abstract void write(int b)
- 주어진 값을 출력소스에 씀 (b는 무슨 역할?)
- void write(byte[] b)
- 주어진 배열 b 에 저장된 모든 내용을 출력소스에 씀
- void write(byte[] b, int off, int len)
- 주어진 배열 b에 저장된 내용 중에서 off번째부터 len개 만큼만을 읽어서 출력소스에 씀
- void close()
- 입력소스를 닫음으로써 사용하고 있던 자원을 반환
- void flush()
- 스트림의 버퍼에 있던 모든 내용을 출력소스에 씀
- 버퍼가 있는 출력스트림에서만 의미가 있음. OutputStream에서는 아무런 기능X
Byte와 Character 스트림
Character 스트림
- Java 에서 char은 2 byte
- 바이트기반 stream 으로 문자를 처리하는 것은 어려움이 있음
- FileReader / FileWriter
- CharArrayReader / CharArrayWriter
- PipedReader / PipedWriter
- StringReader / StringWriter
Reader
- int read()
- 입력소스로부터 하나의 문자를 읽어 옴. char의 범위인 0~65536 범위의 정수를 반환. 입력스트림의 마지막 데이터에 도달 시 -1 반환
- int read(char[] c)
- 입력소스로부터 매개변수로 주어진 배열 c의 크기만큼 읽어서 배열 c에 저장. 읽어 온 데이터의 개수 혹은 -1을 반환
- abstract int read(char[] c, int off, int len)
- 입력소스로부터 최대 len개의 문자를 읽어서 배열 c의 off 번째 위치에 읽은 만큼 저장한다. 읽어온 데이터의 개수 혹은 -1 반환
Writer
- void write(int c)
- 주어진 값을 출력소스에 쓴다
- void write(char[] c)
- 배열 c에 저장된 모든 내용을 출력소스에 쓴다
- abstract void write(char[] c, int off, int len)
- 배열 c에 저장된 내용 중에서 off번째부터 len길이만큼만 출력소스에 쓴다
- void write(String str)
- 주어진 문자열을 출력소스에 쓴다
- void write(String str, int off, int len)
- 주어진 문자열의 일부를 출력소스에 쓴다. (off번째 문자부터 len개 만큼의 문자열)
public class BufferedReaderEx1 {
//';' 을 포함한 line을 출력하는 예제
public static void main(String[] args) {
try {
FileReader fr = new FileReader("BufferedReaderEx1.java");
BufferedReader br = new BufferedReader(fr);
String line = "";
for (int i = 1; (line = br.readLine()) != null ; i++) {
if (line.indexOf(";") != -1) {
System.out.println(i + ":" + line);
}
}
br.close();
} catch (IOException e) {
}
}
}
표준 입출력 (System.in, System.out, System.err)
- 콘솔을 통한 데이터 입력과 데이터 출력을 의미
- 자바에서는 표준 입출력을 위해 3가지 입출력을 제공.
- 자바 어플리케이션 실행과 동시에 자동적으로 생성되기 때문에 개발자가 별도로 스트림을 생성하는 코드를 작성할 필요 없음
- 내부적으로 BufferedInputStream, BufferedOutputStream의 인스턴스를 사용
- System.in
- 콘솔로부터 데이터를 입력받는데 사용
- System.out
- 콘솔로 데이터를 출력하는데 사용
- System.err
- 콘솔로 데이터를 출력하는데 사용
public class StandardIOEx1 {
public static void main(String[] args) throws IOException {
int input = 0;
while ((input = System.in.read()) != -1) {
System.out.println("input : " + input + ", (char)input : " + (char)input);
}
}
}
hello
input : 104, (char)input : h
input : 101, (char)input : e
input : 108, (char)input : l
input : 108, (char)input : l
input : 111, (char)input : o
input : 10, (char)input :
파일 읽고 쓰기
File 클래스
- 파일과 디렉토리를 다룸
- File(String fileName)
- 주어진 문자열을 이름으로 갖는 파일(혹은 디렉토리)을 위한 File 인스턴스 생성
- fileName은 주로 경로를 포함해서 지정. 파일이름만 명시하면 프로그램이 실행되는 위치가 경로로 간주됨
public class FileEx2 {
public static void main(String[] args) {
if (args.length != 1) {
System.out.println("USAGE : java FileEx2 DIRECTORY");
System.exit(0);
}
File f = new File(args[0]);
if (!f.exists() || !f.isDirectory()) {
System.out.println("Invalid Directory!");
System.exit(0);
}
File[] files = f.listFiles();
for (int i = 0; i < files.length; i++) {
String fileName = files[i].getName();
System.out.println(files[i].isDirectory() ? "[" + fileName + "]" : fileName);
}
}
}
기선님 리뷰 영상
- read() 의 반환값은 int (4 bytes) 지만 InputStream / OutputStream 은 그 중 일부인 1 byte만 읽어 옴. char 기반의 Stream의 경우는 그 중 2 bytes만 읽어 옴.
- BufferedStream을 쓰면 속도가 빨라지는 이유
- OS 레벨에서 system call 횟수를 줄이기 때문에 (물 뜨러 주방에 가는 것에 비유)
- (업무 팁) blocked 되는 순간 질문하는 것이 좋다.
- direct buffer / non-direct buffer 학습 후 creating a Java off-heap in memory database 아티클 읽어보기
References
'JAVA' 카테고리의 다른 글
[자바 스터디] 13주차 : 람다식 (0) | 2022.03.20 |
---|---|
[자바 스터디] 12주차 : 제네릭 (0) | 2022.03.20 |
[자바 스터디] 10주차(2) : Annotation (0) | 2022.02.26 |
[자바 스터디] 10주차(1) : Enum (0) | 2022.02.26 |
[자바 스터디] 9주차 : 멀티쓰레드 프로그래밍 (0) | 2022.02.20 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 백기선
- 프로그래머스
- 메서드레퍼런스
- 자바
- 토비의스프링
- BOJ
- 자바스터디
- 카카오
- AOP
- 템플릿콜백
- 디자인패턴
- 데코레이터패턴
- provider
- ec2
- 코테
- 객체지향
- OOP
- 예외처리
- 프록시
- 김영한
- c++
- gracefulshutdown
- SOLID
- 토비
- 코딩테스트
- java
- 스프링
- 프록시패턴
- 서비스추상화
- 토비의봄TV
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
글 보관함