1. 입출력(IO)
: Input & Output의 약자로, 컴퓨터 내외부 장치와 프로그램 사이에 데이터를 주고 받는 것을 뜻한다.
입출력을 위해 스트림을 이용한다.
2. 스트림(Stream)
: 데이터를 입출력 장치에서 읽고 쓰기 위해 Java에서 제공하는 클래스
모든 스트림은 단방향이고, 하나의 스트림으로 입출력을 동시에 할 수 없어 2개의 스트림으로 동시에 수행해야 한다.
(1) 분류
① 최상위 클래스
ⓐ 바이트 스트림
- 입력 스트림: InputStream
- 출력 스트림: OutputStream
ⓑ 문자 스트림
- 입력 스트림: Reader
- 출력 스트림: Writer
② 하위 클래스
ⓐ 바이트 스트림
- 입력 스트림: XXXInputStream
- 출력 스트림: XXXOutputStream
ⓑ 문자 스트림
- 입력 스트림: XXXReader
- 출력 스트림: XXXWriter
(2) 종류
① Reader
ⓐ 기반 스트림: FileReader
ⓑ 보조 스트림: InputStreamReader, BufferedReader
② Writer
ⓐ 기반 스트림: FileWriter
ⓑ 보조 스트림: OutputStreamWriter, BufferedWriter
③ InputStream
ⓐ 기반 스트림: FileInputStream
ⓑ 보조 스트림: BufferedInputStream, ObjectInputStream, DataInputStream
④ OutputStream
ⓐ 기반 스트림: FileOutputStream
ⓑ 보조 스트림: BufferedOutputStream, ObjectOutputStream, DataOutputStream
⇒ 기반 스트림이 Input / Output 계열일 경우 보조 스트림도 같은 계열이고,
기반 스트림이 Reader / Writer 계열일 경우 보조 스트림도 같은 계열이다.
(3) File 클래스
① 바이트 스트림
import java.io.FileInputStream;
public class FileByteDao{
// 프로그램을 외부매체(파일)로 내보내기(출력) = 파일로 기록한다.
public void fileOut() {
// FileOutputStream : 1byte 단위로 파일을 출력한다.
// FileOutputStream 객체를 생성한다.
// - 파일과 직접 연결하는 통로를 생성하며, 해당 파일이 존재할 땐 통로만 연결하고
// 해당 파일이 존재하지 않을 땐 파일을 생성하면서 통로를 연결한다.
FileOutputStream fos = null;
// try문 안에 생성하면 finally 블록 내에서 사용이 불가하므로 밖에 적는다.(지역변수)
try {
fos = new FileOutputStream("ByteStream.txt", true);
// 기존 파일이 있으면 false는 덮어쓰기를 하고, true는 이어쓰기를 한다.
// 연결한 통로로 데이터를 전송한다. 이때, write() 메소드로 작성한다.
// 음수를 제외한 1byte 짜리의 숫자를 출력할 수 있으며,
// 파일에는 해당 숫자의 고유 문자(아스키 코드)가 기록된다.
fos.write(65); // 대문자 A (아스키 코드)
fos.write(66); // 대문자 B
// 배열
byte[] arr = {65, 80, 80, 76, 69}; // APPLE(아스키 코드)
fos.write(arr); // APPLE
fos.write(arr, 0, 2); // APP, arr 배열의 0번 인덱스부터 2번 인덱스까지 출력
// char타입 영어
fos.write('A'); // A
// char타입 한글
fos.write('산'); // 한글은 2byte여서 깨져서 출력된다. 문자 스트림을 사용해야 한다.
// 스트림을 다 쓴 후 반드시 자원을 반납한다.
// 하지만 중간에 예외가 발생하면 자원 반납이 안된다.
// fos.close();
}
catch(Exception e) {
e.printStackTrace(); // 예외 발생 추적
}
finally { // finally {}: 어떤 예외가 발생해도 반드시 실행하는 구문
try {
fos.close(); // 자원 반납(통로 닫기)
}
catch(IOException e) {
e.printStackTrace();
}
}
}
// 외부매체(파일)을 프로그램으로 가져오기(입력)
public void fileIn() {
// FileInputStream : 파일로부터 1byte 단위로 데이터를 가져온다.
FileInputStream fis = null;
// try문 안에 생성하면 finally 블록 내에서 사용이 불가하므로 밖에 적는다.(지역변수)
try {
// 반드시 존재하는 파일을 적어야 한다.
fis = new FileInputStream("ByteStream.txt");
// 1byte씩 데이터를 읽어온다. 이때, read() 메소드를 작성한다.
// 방법1
System.out.println(fis.read());
System.out.println(fis.read());
System.out.println(fis.read());
System.out.println(fis.read());
System.out.println(fis.read());
System.out.println(fis.read());
// 위 출력 메소드에서 6단어를 작성했으므로 가져올 문자도 6개이다.
// 파일의 마지막을 읽어올 때 read() 메소드를 호출하면 -1을 반환한다.
int value = 0;
// fis.read() 메소드를 호출하는 순간 데이터를 읽어오기 때문에
// value라는 변수에 데이터를 담아서 한번에 출력해야 한다.
while((value = fis.read()) != -1) {
System.out.println(value);
}
// 방법2 - 방법1이나 방법2 둘 중 하나의 방법으로 하면 된다.
while(true) {
int value = fis.read();
if(value == -1) {
break;
}
System.out.println(value);
}
}
catch(Exception e) {
e.printStackTrace();
}
finally {
try {
fis.close(); // 자원 반납
}
catch(IOException e) {
e.printStackTrace();
}
}
}
}
② 문자 스트림
public class FileCharDao {
// 출력
public void fileSave() {
// FileWriter : 2byte 단위로 데이터를 파일로 출력하는 스트림
FileWriter fw = null; // finally 블록에서 사용하기 위해 위에 뺴놓는다.(지역변수)
try {
// FileWriter 객체를 생성하여 파일과 연결된 통로를 만든다.
fw = new FileWriter("CharStream.txt");
// write() 메소드로 파일에 데이터 출력
fw.write("맑은 날씨"); // 맑은 날씨
fw.write('A'); // A
// int 타입(1byte)을 입력하면 글자가 깨져서 나온다.
fw.write(12);
// 배열
char[] ch = {'q', 'u', 'i', 'z'};
fw.write(ch); // quiz
}
catch(IOException e) {
e.printStackTrace(); // 예외 발생 추적
}
finally {
try {
fw.close(); // 자원 반납
}
catch(IOException e) {
e.printStackTrace();
}
}
}
// 입력
public void fileRead() {
// FileReader : 파일로부터 2byte 단위로 데이터를 가져오는 스트림
FileReader fr = null;
try {
// FileReader 객체를 생성하여 연결 통로를 만든다.
fr = new FileReader("CharStream.txt"); // 기존에 있는 파일을 작성해야 한다.
System.out.println(fr.read());
int value = 0;
while((value = fr.read()) != -1) {
System.out.println((char)value);
// char로 형변환 않고 value로만 데이터를 가져오면 아스키코드로 들어온다.
}
}
catch(FileNotFoundException e) {
e.printStackTrace();
}
catch(IOException e) {
e.printStackTrace();
}
finally {
try {
fr.close(); // 자원 반납
}
catch (IOException e) {
e.printStackTrace();
}
}
}
}
③ 새로 파일 생성하기
public class FileRun {
public static void main(String[] args) {
// File 클래스로 작업한다. ( java.io 패키지 )
// File 클래스에서 객체를 생성한다.
try { // 전체를 감싸기
File file1 = new File("OneFile.txt");
try {
file1.createNewFile(); // createNewFile() : 새로운 파일 생성
}
catch(IOException e) {
e.printStackTrace(); // 예외 발생 추적
}
// File 객체 생성 경로를 지정하여 파일명을 적고 생성한다.
File file2 = new File("C:\\Users\\FileClass\\TwoFile.txt");
// C드라이브에 있는 Users 폴더 -> FileClass 폴더 -> 'TwoFile'라는 파일의 경로를 지정
// 보통 경로 지정할 때 '/'를 사용하는데 여기에선 역슬래쉬(\)를 사용한다.
try {
file2.createNewFile(); // 새로운 파일 생성
}
catch(IOException e) {
e.printStackTrace();
}
// 폴더를 생성한 후 그 안에 파일을 생성한다.
File Folder = new File("C:\\Users\\FileClass\\TwoFile");
Folder.mkdir(); // mkdir() : 새로운 디렉토리 생성
File file3 = new File("C:\\Users\\FileClass\\TwoFile\\Hello World!");
file3.createNewFile();
// 별도의 경로를 지정하지 않고 폴더를 생성한 후 파일을 생성한다.
File Folder2 = new File("newFolder");
Folder2.mkdir(); // 새로운 디렉토리 생성
File file4 = new File("newFolder\\text.txt");
file4.createNewFile(); // 새로운 파일 생성
// File 클래스에서 제공하는 메소드
// isFile() : 파일이면 true, 폴더면 false를 반환한다.
System.out.println("This is " + file1.isFile()); // true
System.out.println("This is " + Folder.isFile()); // false
// getName() : 파일명만 추출해서 반환한다.
System.out.println("파일명: " + file1.getName()); // OneFile.txt
// getParent() : 상위 폴더명만 추출해서 반환한다.
System.out.println("상위 폴더: " + file1.getParent()); // null
// length() : 파일의 크기를 반환한다.
System.out.println("파일 용량: " + file1.length()); // 6
// getAbsolutePath() : 시작점에서부터의 전체 경로를 반환한다.
System.out.println("절대 경로: " + file1.getAbsolutePath());
// C:\Users\FileClass\OneFile.txt
}
}
}
(4) Buffered 보조 스트림
: 버퍼 공간을 제공하여 데이터를 모아뒀다가 한번에 입출력한다.
→ 속도 향상을 목적으로 하는 보조 스트림이다.
* 보조 스트림은 단독으로 존재할 수 없다.
→ 기반 스트림 객체를 생성한 후 보조 스트림 객체를 생성할 수 있다.
* 표현: 보조스트림클래스명 객체명 = new 보조스트림클래스명(기반스트림객체);
① BufferedReader
: 버퍼 공간을 제공하여 한번에 가져오는 스트림
② BufferedWriter
: 버퍼 공간을 제공하여 한번에 출력하는 스트림
③ 예시
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class BufferedDao {
// 출력(프로그램을 외부매체(파일)로 보내기)
public void fileSave() {
FileWriter fw = null; // finally 구문에서 사용해야 하므로 밖으로 빼놓는다.
BufferedWriter bw = null;
try {
fw = new FileWriter("buffered.txt"); // 기반스트림 객체 생성
bw = new BufferedWriter(fw); // 보조스트림은 단독생성 불가
bw.write("누구세요?");
bw.write("홍길동입니다.");
bw.newLine(); // newLine() : 개행 메소드
bw.write("아, 그렇군요.");
bw.flush(); // flush() : 버퍼에 남아있는 모든 문자열을 출력해준다.
}
catch (IOException e) {
e.printStackTrace();
}
finally {
try {
bw.close();
fw.close(); // 자원 반납시엔 생성된 자원 역순으로 반납
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 입력(외부매체(파일)로부터 프로그램으로 가져오기)
public void fileRead() {
FileReader fr = null;
BufferedReader br = null;
try {
fr = new FileReader("buffered.txt"); // 존재하는 파일과 동일하게 작성
br = new BufferedReader(fr);
System.out.println(br.read());
// read로 1개씩 읽어오기
int value = 0;
while((value = br.read()) != -1) { // 마지막을 만나면 -1을 출력
System.out.println((char)value);
}
//readLine으로 한줄씩 읽어오기
String value = null;
while((value = br.readLine()) != null) {
System.out.println(value);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch(IOException e) {
e.printStackTrace();
} finally {
try {
br.close(); // 역순으로 자원 반납
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// try with resource 구문: 자동으로 자원 반납해주는 구문(jdk 1.7 이상부터 사용 가능)
/*
* [표현법]
* try(스트림 객체 생성;) {
* 예외발생구문
* } catch(예외클래스명 변수) {
* 예외처리구문
* }
*
* 스트림 객체를 생성하고 해당 블록이 실행 완료되면 자원 반납이 자동으로 이루어진다.
*/
// try(FileReader fr = new FileReader("buffered.txt");
// BufferedReader br = new BufferedReader(fr)){
//
// } catch(Exception e) {
// System.out.println("야호!");
// }
public void method3() {
// 기반 스트림과 보조 스트림 생성 구문을 하나로 합치기
// try(BufferedReader bis = new BufferedReader(new FileReader("buffered.txt"))){
// String value = null;
// while((value = bis.read()) != -1) {
// System.out.println(value);
// }
// } catch(Exception e) {
// e.printStackTrace();
// }
try(FileInputStream fis = new FileInputStream("C:\\Users\\newFolder\\img.png")){
int value = 0;
while((value = fis.read()) != -1) {
System.out.println(value);
}
} catch(Exception e) {
e.printStackTrace();
}
}
}
// 실행할 클래스
import com.cd.assist.buffered.model.vo.BufferedDao;
public class BufferedRun {
public static void main(String[] args) {
BufferedDao bd = new BufferedDao();
bd.fileSave();
bd.fileRead();
bd.method3();
}
}
(5) 객체 보조 스트림
: 객체는 문자가 아니여서 바이트 기반 스트림으로 데이터를 변경해주는 직렬화(Serializable)가 필수이다.
- 직렬화(Serializable)
: implements Serializable 로 구현한다. private 필드를 포함하여 모든 필드를 바이트로 변환하는데,
transient 키워드를 사용한 필드는 제외이다.
// Phone 객체
import java.io.Serializable;
// 객체를 스트림에 보내려면 직렬화를 해주어야 한다.(Serializable)
public class Phone implements Serializable {
private String name;
private int price;
public Phone() {
}
public Phone(String name, int price) {
super();
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public String toString() {
return "Phone [name=" + name + ", price=" + price + "]";
}
}
// 객체 dao
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import com.cd.assist.object.model.vo.Phone;
public class ObjectDao {
// 프로그램 -> 외부매체(파일)
//출력
public void fileSave(String fileName) {
Phone p = new Phone("아이폰", 1520000);
// 나눠서 쓰기(finally 구문을 작성하기 위해)
// FileOutputStream fos = null;
// ObjectOutputStream oos = null;
//
// fos = new FileOutputStream(fileName);
// oos = new ObjectOutputStream(fos);
// try with resource 구문에 나눠 쓰기
try(FileOutputStream fos = new FileOutputStream(fileName);
ObjectOutputStream oos = new ObjectOutputStream){
}
// 위에를 한번에 쓰기
try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(fileName))){
// 보조스트림에 기반스트림객체를 넣어 생성 완료
oos.writeObject(p); // writeObject로 Phone 객체 보내기
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
// 입력
// 읽어오는 메소드 readObject 사용
public void fileRead(String fileName) {
try(ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName))) {
System.out.println(ois.readObject());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
// 실행할 클래스
import com.cd.assist.object.model.dao.ObjectDao;
public class ObjectRun {
public static void main(String[] args) {
ObjectDao od = new ObjectDao();
od.fileSave("Object.txt"); // 여기서 파일명 입력
od.fileRead("Object.txt");
}
}