스트림은 쉽게 이야기해서 Byte 형태로 데이터를 운반하는데 사용되는 연결통로라고 생각하면 된다.
이는 자료(data)의 흐름이 물의 흐름과 같다는 의미에서 사용되었다고 한다. 다만 물이 한쪽 방향으로만 흐르는 것과 같이 스트림은 단방향 통신만 가능하기 때문에 하나의 스트림으로 입력과 출력을 동시에 처리 할 수 없다.
또한 스트림은 먼저 보낸 데이터를 먼저 받게 되어있으며 연속적으로 데이터를 주고 받는다는 점에서 큐(queue)의 FIFO(First in Frist Out) 구조로 되어 있다.
이때 데이터의 스트림의 근원지(시작점)을 Source, 데이터 종착점을 Sink, 연결한 것을 Stream 이라고 표현하며, Source - 입력 스트림 input Stream- 출력 스트림 output Stream- Sink 으로 연결된다.
여러 개의 스트림을 연결하여 사용할 수 있다.
파일 입출력 동안 예외 발생 가능
스트림 생성 동안FileNotFoundException 발생 가능!!
----> 파일의 경로명이 틀리거나 디스크의 고장 등으로 파일을 열 수 없을 때
파일 읽기, 쓰기, 닫기를 하는 동안: IOException 발생 가능!!
----> 디스크 오동작, 파일이 중간에 깨진 경우, 디스크 공간이 모자라서 파일 입출력이 불가능한 경우.
즉, try-catch 블록이 반드시 필요하다.
스트림을 이용하여 실제 다양한 하드웨어와 입출력을 수행하는 일은 JVM에 의해 실행된다.
자바는 입출력을 위한 클래스들을 java.io 패키지로 제공하고있다.
스트림은 단방향이다. (방향에 따라 입력 스트림, 출력 스트림)
스트림은 선입선출, FIFO 구조이다.
스트림은 지연될 수 있다.
. 입력 스트림이 흐르는 통로인 파이프가 비어 있다면, 컴퓨터는 읽어갈 데이터가 없으므로 기다림
. 출력 스트림이 흐르는 통로인 파이프에 데이터가 꽉 차 있다면 컴퓨터는 빈 공간이 생길 때까지 기다린다.
리턴 타입 | 메소드 | 설명 |
---|---|---|
void | write(int b) | 1byte 출력 |
void | write(byte[] b) | 매개값으로 주어진 배열b의 모든 바이트 출력 |
void | write(byte[] b, int off, int len) | 매개값으로 주어진 배열b[off]부터 len개까지의 바이트 출력 |
void | flush() | 출력버퍼에 잔류하는 모든 바이트 출력 |
void | close() | 출력스트림 닫기 |
public abstract void write(int b) throws IOException;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class WriteExample {
public static void main(String[] args) throws Exception {
OutputStream os = new FileOutputStream("C:/Temp/test1.db"); // 데이터 도착지를 .db로 함
// 경로를 지정해주지 않으면 root에 만들어짐!
byte a = 10;
byte b = 20;
byte c = 30;
os.write(a);
os.write(b);
os.write(c);
os.flush(); // 현재 파일 출력 스트림의 버퍼에 보관중인 데이터를 파일로 출력
os.close(); // 모든 스트림 작업이 끝나면 공식적으로 닫아줘야함
// (안 닫을 경우 메모리 누수 발생할 수 있음)
}
}
입출력 스트림은 항상 예외처리를 해줘야 한다
"C:/Temp/" 경로에 test1.db 파일이 생성되었다!
public void write(byte b[]) throws IOException {
write(b, 0, b.length);
}
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class WriteBytesExample {
public static void main(String[] args) throws IOException {
OutputStream os = new FileOutputStream("c:/TEMP/test2.db");
byte[] bytes = {10, 20, 30};
os.write(bytes);
os.flush();
os.close();
}
}
public void write(byte buf[], int off, int len) {
try {
synchronized (this) {
ensureOpen();
out.write(buf, off, len);
if (autoFlush)
out.flush();
}
}
catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
}
catch (IOException x) {
trouble = true;
}
}
import java.io.IOException;
import java.io.PrintStream;
public class PrintStreamExample {
public static void main(String[] args) throws IOException {
PrintStream os = new PrintStream("C:/Temp/test3.db");
byte[] array = {10,20,30,40,50};
os.write(array, 1, 3); // 배열의 1번부터 3개를 출력
os.flush();
os.close();
}
}
리턴 타입 | 메소드 | 설명 |
---|---|---|
int | read() | 1byte 읽고 읽은 바이트 리턴 |
int | read(byte[] b) | 읽은 바이트를 매개값으로 주어진 배열에 저장하고 읽은 바이트 수를 리턴 |
int | read(byte[] b, int off, int len) | len개의 바이트를 읽고 매개값으로 주어진 배열에서 b[off]부터 len개까지 저장 후 읽은 바이트 수를 리턴 |
void | close() | 입력스트림 닫기 |
public abstract int read() throws IOException;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class ReadExample {
public static void main(String[] args) throws IOException {
InputStream is = new FileInputStream("C:/TEMP/test1.db");
while(true) {
int data = is.read(); // read() 메소드는 리턴값이 int라서 int로 선언한다.
if(data==-1) break; // 더 이상 입력 스트림으로부터 바이트를 읽을 수 없을 때
// read() 메소드는 -1을 리턴함
System.out.println(data);
}
is.close();
}
}
"C:/TEMP/test1.db" 파일은 출력스트림 wirte()예제에서 만들었다!
10
20
30
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class ReadExample_1 {
public static void main(String[] args) throws IOException {
InputStream is = new FileInputStream("C:/TEMP/test2.db"); // {10,20,30}이 저장되어 있음
byte[] buffer = new byte[100]; // 크기가 100인 바이트 타입의 배열 생성
while(true) {
// is에 있는 데이터를 버퍼로 읽어 와서 data에 저장한다.
int data = is.read(buffer);
// 더 이상 읽어올 수 없을 때 data는 -1을 리턴한다.
if(data==-1) break;
// 버퍼에 저장된 배열을 읽어오기
for(int i=0; i<data; i++) {
System.out.println(buffer[i]);
}
// 버퍼에 저장된 배열의 길이
System.out.println(data);
}
is.close();
}
}
10
20
30
3 // 버퍼에 저장된 배열의 길이
💡 Buffer(버퍼)란?
임시로 데이터를 담아둘 수있는 일종의 큐이다. 바이트 단위의 데이터가 입력될 때마다 Stream은 즉시 전송하게 되는데 이것은 디스크 접근이나 네트워크 접근같은 오버헤드가 발생하기 때문에 매우 비효율적인 방법이다. Buffer는 중간에서 입력을 모아서 한번에 출력함으로써 I/O 의 성능을 향상시키는 역할을 한다.
public int read(byte b[], int off, int len) throws IOException {
Objects.checkFromIndexSize(off, len, b.length);
if (len == 0) {
return 0;
}
int c = read();
if (c == -1) {
return -1;
}
b[off] = (byte)c;
int i = 1;
try {
for (; i < len ; i++) {
c = read();
if (c == -1) {
break;
}
b[off + i] = (byte)c;
}
} catch (IOException ee) {
}
return i;
}
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class ReadExample_2 {
public static void main(String[] args) throws IOException {
InputStream is = new FileInputStream("C:/Temp/test3.db");
byte[] buffer = new byte[5];
// test.db -> {20,30,40}
// buffer[2], buffer[3], buffer[4]로 저장해라
int len = is.read(buffer, 2, 3);
// 읽은 바이트가 있다면
if(len != -1) {
// 배열 전체를 출력
for(int i=0; i<buffer.length; i++) {
System.out.println(buffer[i]);
}
}
is.close();
}
}
0
0
20
30
40
리턴 타입 | 메소드 | 설명 |
---|---|---|
void | write(int b) | 매개값으로 주어진 한 문자를 보냄 |
void | write(char[] cbuf) | 매개값으로 주어진 배열의 모든 문자 보냄 |
void | write(char[] cbuf, int off, int len) | 매개값으로 주어진 배열에서 char[off]부터 len개까지의 문자를 보냄 |
void | write(String str) | 매개값으로 주어진 문자열을 보냄 |
void | write(String str, int off, int len) | 매개값으로 주어진 문자열에서 off순번부터 len개까지의 문자를 보냄 |
void | flush() | 버퍼에 잔류하는 모든 문자 출력 |
void | close() | 출력스트림 닫기 |
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class WriteExample {
public static void main(String[] args) throws IOException {
Writer writer = new FileWriter("C:/TEMP/test7.txt");
char a = 'A';
char b = 'B';
char c = 'C';
// 한 문자씩 출력
writer.write(a);
writer.write(b);
writer.write(c);
writer.flush();
writer.close();
}
}
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class WriteExample_1 {
public static void main(String[] args) throws IOException {
Writer writer = new FileWriter("C:/TEMP/test8.txt");
char[] array = {'중', '앙', '인','재','개','발','원'};
// 배열의 모든 문자열 출력
writer.write(array);
writer.flush();
writer.close();
}
}
💡 유니코드를 다루는 이유? : 한글로 써도 깨지지 않음(UTF-8)
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class WriteExample_2 {
public static void main(String[] args) throws IOException {
Writer writer = new FileWriter("C:/TEMP/test9.txt");
char[] array = {'중', '앙', '인','재','개','발','원'};
// 배열의 인덱스1번부터 3개를 출력해라
writer.write(array, 1, 3);
writer.flush();
writer.close();
}
}
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class WriteExample_3 {
public static void main(String[] args) throws IOException {
Writer writer = new FileWriter("C:/TEMP/test10.txt");
String str = "만나서 반갑습니다.";
// "반갑습니다."만 출력
writer.write(str, 4, str.length()-4);
writer.flush();
writer.close();
}
}
리턴 타입 | 메소드 | 설명 |
---|---|---|
int | read() | 1개의 문자를 읽고 읽은 리턴 |
int | read(char[] cbuf) | 읽은 문자들을 매개값으로 주어진 문자 배열에 저장하고 읽은 문자 수를 리턴 |
int | read(char[] cbuf, int off, int len) | len개의 문자를 읽고 매개값으로 문자 배열에서 cbuf[off]부터 len개까지 저장 후 읽은 바이트 수를 리턴 |
void | close() | 입력스트림 닫기 |
String 타입을 매개변수로 받지 않는다. why? 데이터를 확인하기 힘들다. character 배열(시퀀스) = String
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public class ReaderExample {
public static void main(String[] args) throws IOException {
Reader reader = new FileReader("C:/TEMP/test7.txt");
while(true) {
int data = reader.read();
if(data == -1) break;
// 아스키코드를 char로 변환해서 출력
System.out.println((char)data);
// 아스키코드 그대로 출력
System.out.println(data);
}
reader.close();
}
}
A
65
B
66
C
67
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public class ReaderExample {
public static void main(String[] args) throws IOException {
Reader reader = new FileReader("C:/TEMP/test8.txt");
char[] buffer = new char[5];
// buffer[2],buffer[3],buffer[4]로 저장해라
int readCharNum = reader.read(buffer, 2, 3);
// 데이터가 있다면
if(readCharNum!=-1) {
// buffer 전체 출력
for(int i=0; i<buffer.length; i++) {
System.out.println(buffer[i]);
}
}
reader.close();
}
}
read(byte[] b, int off, int len) -> off+len = 배열의 크기
중
앙
인
참고 : https://terianp.tistory.com/19
https://bamdule.tistory.com/179
https://yooniron.tistory.com/16