18. 데이터 입출력
파트4
데이터를 어떻게 입력받고 출력받나
18.1 입출력 스트림
대상이 파일일뿐이지 네트워크나 데이터 등과 다르지 않다.
17장에서는 컬렉션이 흘럿고 여기서는 데이터 가 스트림에서 흐른다.
17장은 무조건 입력만 받는데 여기서는 입력스트림과 출력 스트림이 있는것이다.
데이터는 키보드를 통해 입력될수도이속 파일또는 프로그램으로부터 입력될 수도 잇다.
반대로 데이터는 모니터로 출력될수도잇고 파일에 저장되거나 다른 프로그램으로 전송될 수 있다.
프로그램을 기준으로 데이터가 들어오는 것이 입력스트림 나가는것이 출력스트림. 따로 따로 존재한다.
스트림은 단방향으로 데이터가 흐른다.
데이터는 키보드 파일 프로그램에서 읽을 수 잇고 출력은 모니터(콘솔) 파일 프로그램 등이 있다.
항상프로그램입장에서 생각해서 들어오는건 입력 나가는건 출력이다.
두 프로그램이 데이터를 교환한다면? 프로그램 기준에서 생각하면된다.
어떤 데이터를 입출력하느냐에 따라 스트림은 다음 두 종류로 구분가능하다.
바이트 스트림 : 그림, 멀티미디어, 문자 등 모든 종류의 데이터를 입출력할때 사용
문자스트림 : 문자만 입출력할때 사용
그러나 결국 흘러가는 데이터는 모두 바이트이다. 문자또한 바이트배열로 바뀌어서 흘러감.
이는 java.io 패키지에서 제공하고잇다.
InputStream OutputStream / Reader Writer 앞에 접두사가 붙어 특화된 스트림이 있다.
바이트스트림으로도 문자열을 읽을 수 잇으나 바이트로 읽은후 변환이 필요하기 때문에
문자 스트림을 쓰는게 조금더 편리하다.
18.2 바이트 출력 스트림
OutputStream은 바이트 출력 스트림의 최상위 클래스로 추상 크랠스이다. 모든 바이트 출력 스트림클래스는 이 OutputStream를 상속바다 만들어지낟.
따라서 OutputStream을 직접 사용하는 것이 아니라 밑에걸 쓴다.
FileOutputStream, PirntStream BufferedOutputStream DataOutputStream 등 이 있다.
메소드는 다음과 같다.
write()는 바로 출력이 아니라 나갈 준비를 하는 것임. flush()를 사용해야 출력된다.
close()데이터를 다 받고 닫아야한다. 닫지 않으면 불안정해짐.
18.2.1 1 바이트 출력
write(int b) 메소드는 매개값 int(4byte)에서 끝 1byte만 출력한다. 매개변수가 int타입이므로 4byte를 모두 보내는 것은 아니다.
package ch18.sec02.exam01;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class WriteExample {
public static void main(String[] args) {
try
(OutputStream os = new FileOutputStream("C:/Temp/test1.db")) {
// "C:/Temp/test1.db", true 기존파일 뒤에다 저장
// "C:/Temp/test1.db", false 기존파일 덮어쓰기
//파일에 저장하는데 없으면 파일생성해줌. 그러나 폴더가 없으면 예외가 발생함
byte a = 10; //00001010 8비트 = 1바이트
byte b = 20;
byte c = 30;
os.write(a); // byte가 write로 들어가면 int로 자동타입변환 byte는 -128~127이므로 초과하면 원래 그대로가 안됨
os.write(b);
os.write(c);
os.flush(); // write는 '버퍼'에서 준비만 하는 것이고 버퍼에서 바이트를 쏟아내기 위해 flush를 사용해줘야한다.
//os.close();
//위에서 클로즈하는것은 예외발생하면 클로즈가 안되서 좋은 것은 아님..! 그래서 finally에 close해주면 좋다
//FileOutputStream 가 자동리소스닫기를 구현하고있어서 자동닫기를 사용함.
} catch (Exception e) { //fileNotFoundException | IOException 두개발생가능
e.printStackTrace();
}
/*
finally {
os.close();
}
*/
}} 
18.2.2 바이트 배열 출력
writ(byte[] b)사용
일반적으로 1바이트를 출력하는 경우는 드물고 보통 바이트 배열을 통채로 출력하는 경우가 많다.
package ch18.sec02.exam02;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class WriteExample {
public static void main(String[] args) {
try
(OutputStream os = new FileOutputStream("C:/Temp/test2.db")){
//자동닫기사용
byte[] array = {10 , 20 , 30};
os.write(array);
os.flush();
//os.close();
//간단한 프로세스가 끝나는거라 여기서 닫아도되는데
ui만들때 켜져있는 동시에 이런거 할때 여기서 닫는거 좋지않다는 걸 인지하자.
} catch (Exception e) {
e.printStackTrace();
}
/*
finally {
os.close();
}
*/
}}18.2.3 바이트배열의 일부분만 출력하기
바이트배열은똑같고 위치정보를 제공하기
os.write(byte[] b, int off(시작인덱스), int len(몇개까지 할지));
b[off]부터 len개의 바이트 출력
package ch18.sec02.exam03;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class WriteExample {
public static void main(String[] args) {
try (OutputStream os = new FileOutputStream("C:/Temp/test3.db")){
//자동닫기 사용
byte[] array = {10 , 20 , 30, 40 ,50};
os.write(array,1 ,3); //1번인덱스부터 3개까지만 출력
os.flush();
// os.close(); 간단한 프로세스가 끝나는거라 여기서 닫아도되는데
ui만들때 켜져있는 동시에 이런거 할때 여기서 닫는거 좋지않다는 걸 인지하자.
//finally를 쓰거나 자동닫기사용
} catch (Exception e) {
e.printStackTrace();
}
/*
finally {
os.close();
}
*/
}}18.3 바이트 입력 스트림
InputStream은 바이트 입력스트림의 최상위 클래스로 추상클래스이다.
InputStream를 상속받아 FileInputStream BufferedInputStream DataInputStream이 있다.
메소드는 다음과 같다.
read 1바이트읽고 바이트리턴
read(byte[] b) 읽은 바이트를 매개값으로 주어진 배열에 저장후 읽은 바이트 수를 리턴 실제 읽은 데이터는 바이트배열에 저장
18.3.1 1바이트 읽기
입력스트림에서 5개의 바이트가 들어오면 read()메소드를 5번사용해서 읽어야한다.
더이상 입력스트림으로부터 바이트를 읽을 수 없다면 read() 는 -1을 리턴한다.
InputStream is = ...;
while (true) {
int data = is.read(); // 1바이트를 읽고 리턴
if (data== -1) break; //-1을 리턴할 경우 while문 종료
}package ch18.sec03.exam01;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
public class ReadExample {
public static void main(String[] args) {
InputStream is = null;
try {
is = new FileInputStream("C:/temp/test1.db");
while(true) {
int data = is.read();
if(data == -1) break;
System.out.println(data);
}
is.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {}
}}} 
18.3.2 바이트배열로 읽기
read(byte[] b) 메소드는 입력 스트림으로부터 주어진 배열의 길이만큼 바이트를 읽고 배열에 저장한 다음 읽은 바이트 수를 리턴한다.
예를들어 입력스트림에 5개의 바이트가 들어오면 길이 3인배열로 두번읽을수있다.
package ch18.sec03.exam02;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
public class ReadExample {
public static void main(String[] args) {
InputStream is = null;
try {
is = new FileInputStream("C:/temp/test2.db");
//읽은 바이트를 저장할 배열생성
byte[] data = new byte[100];
while(true) {
int num = is.read(data); //최대 읽을수있는 바이트를 읽고 배열에 저장 읽은바이트는 리턴 지금은 num =3
if(num == -1) break;
for(int i =0 ; i<num ; i++) { //num만큼 읽은 만큼 도니가 3번
System.out.println(data[i]);
}
}
is.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {}
}}}read(byte[] b)역시 더이상 읽을수 없다면 -1을 리턴한다.
많은양의 바이트를 읽을때는 read(byte[] b) 메소드를 ㅇ사용하는 것이 좋다.
입력스트림으로부터 100개의 바이트가 들어온다면 read()메소드는 100번반복해야하지만read(byte[] b)메소드는 한번읽을때 배열길이만큼 읽기때문에 읽는 횟수가 현저히 줄어든다.
18.3.3 파일복사
파일복사의 원리는 FileInputStream에서 읽은 바이트를 바로 FileOutputStream으로 출력하는 것이다.
임의의 JPEG 그림파일을 하나 준비해 파일이름을 test.jpg로 변경한다음 C:/Temp폴더에 저장한다.
package ch18.sec03.exam03;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
public class CopyExample {
public static void main(String[] args) {
String originalFileName = "C:/Temp/test.png";
String targetFileName = "C:/Temp/test2.png";
try
(InputStream is = new FileInputStream(originalFileName);
OutputStream os = new FileOutputStream(targetFileName))
{
byte[] data = new byte[1024]; //1kb=1024b 읽은 바이트를 저장할 배열생성
while(true) {
int num = is.read(data); //최대 1024바이트를 읽고 배열에 저장 읽은 바이트는 리턴
if(num == -1) break;
os.write(data , 0 , num);
//읽은 바이트 수만큼 출력 짜투리가 남기때문에 이걸 사용해야함.
//읽고 쓰고 읽고 쓰고 이걸 반복하다가 없으면 -1 리턴하고 종료
}
os.flush(); //내ㅑ부버퍼잔류바이트를 출력하고 버퍼를 지움
//os.close(); 자동닫기함.
//is.close(); 자동닫기함.
System.out.println("복사가 잘되었습니다.");
}catch (Exception e) {}
}}18.4 문자 입출력 스트림
바이트 입출력 스트림인 InputStream과 OutputStream에 대응하는 문자 입출력 스트림으로 Reader 와 Writer가 있다.
입출력 단위가 문자인것을 제외하고는 바이트 입출력 스트림과 사용방법은 동일하다.

18.4.1 문자출력
Writer는 문자 출력 스트림의 최상위 클래스로 추상크랠스이다.
FileWriter BufferedWriter PirntWriter OutputStreamWriter가 있다.
write(int c) 매개값으로 주어진 한 문자를 출력 write(char[] cbuf)char 배열 모든 문자 출력
write(String str) 문자열 전체를 출력
package ch18.sec04.exam01;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class WriteExample {
public static void main(String[] args) {
try //문자기반 출력 스트림 생성 + 자동닫기
(Writer writer = new FileWriter("C:/Temp/test.txt")) //확장명 중요 x
{
//1문자씩 출력
char a = 'A';
writer.write(a);
char b = 'B';
writer.write(b);
//char배열출력
char[] arr = { 'C', 'D', 'E' };
writer.write(arr);
//문자열출력
writer.write("FGH");
//버퍼에 잔류한 문자열 출력 버퍼를 비움
writer.flush();
} catch (IOException e) {
e.printStackTrace();
}}}18.4.2 문자읽기
Reader는 문자 입력 스트림의 최상위 클래스로 추상클래스이다.
FileReader BufferdReader InputStreamReader가 있다.
Reader가 가진 메소드는 다음과같다.
같은데 차이점은 바이트가 아닌 한 문자를 읽은것임.
package ch18.sec04.exam02;
import java.io.FileReader;
import java.io.Reader;
public class ReadExample {
public static void main(String[] args) {
try{
Reader reader = null;
//1문자씩 읽기
reader = new FileReader("C:/Temp/test.txt");
while (true) {
int data = reader.read();
if(data == -1 ) break;
System.out.print((char) data + " "); //data int니까 강제변환
}
reader.close();
System.out.println();
//문자 배열로 읽기
reader = new FileReader("C:/Temp/test.txt");
char[] data = new char[100];
while (true) {
int num = reader.read(data);
if(num == -1 ) break;
for(int i =0; i< num ; i++) {
System.out.print(data[i] + " ");
}
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
}}}
18.5 보조스트림
바이트스트림은 바이트를 다루는데 애플리케이션은 바이트를 다루지않아서 변환하는 작업이 필요하다.
보조스트림을 보통 결합해서 사용한다. 좀 더 편리하게 애플리케이션에서 데이터를 입출력하기 위해, 성능을 향상시키기위해 사용
대부분 같이쓰기 때문에 잘사용해야함.
보조스트림이란 다른스트림과 연결되어 여러가지 편리한 기능을 제공해주는 스트림을 말한다.
혼자서는 사용하지 못하기때문에 주 스트림이 있어야한다. 단독으로는 사용불가 결합해야함.
1.애플리케이션에서 다루는 데이터와 실제로 입출력하는 데이터 형태가 다를 수있기때문
애플리케이션은 int double 등을 다루는데 InputStream과 OutputStream은 byte를 사용하기 때문이다.
int double을 byte로 변환하는게 불편한데 보조스트림이 있으면 바로 int double값들을 입출력할수 있다.
2.성능이 좀 더 빠르다.

입출력스트림에 보조스트림을 연결하려면 보조스트림을 생성할때 생성자 매개값으로 입출력 스트림을 제공하면된다.
보조스트림 변수 = new 보조스트림(입출력스트림);
InputStream is = new FileInputStream("...");
InputStreamReader reader = new InputStreamReader(is);
보조스트림은 또 다른 보조스트림과 연결되어 스트림 체인으로 구성할 수도 있다.
보조스트림1 성능향상용 보조스트림2 편리하게 데이터 입출력받기위한 용
InputStream is = new FileInputStream("...");
InputStreamReader reader = new InputStreamReader(is);
BufferedReader br = new BufferedReader(reader);
자주사용하는 보조스트림은 다음과 같다.
2022.12.06 리뷰
국비지원학원 면접 합격하였다. 남은 기간 동안 자바와 더 친숙해지고자 한다.
중요한 것은 꺾이지 않는 마음
'기초단계 > JAVA' 카테고리의 다른 글
| 2022.12.09 JAVA 네트워크 입출력 (0) | 2022.12.10 |
|---|---|
| 2022.12.07 JAVA 데이터 입출력 (1) | 2022.12.07 |
| 2022.12.05 JAVA 스트림요소처리 (1) | 2022.12.05 |
| 2022.12.03 JAVA 스트림요소처리 (1) | 2022.12.03 |
| 2022.12.02 JAVA 람다식 (0) | 2022.12.02 |