Stream : Data의 흐름(통로)
- [도착지] [출발지]
Program <--- InputStream <--- Source(Keyboard, Mouse, File, Network)
- [출발지] [도착지]
Program ---> OutputStream ---> Destination(Monitor, Beam, File, Network)
Java.io 패키지의 주요 클래스
- 바이트(byte) 단위 입출력 스트림 클래스
- java.io.InputStream : 프로그램이 바이트 단위 데이터를 읽어들이는(read) 통로
- java.io.FileInputeStream
- java.io.OutputStream : 프로그램이 바이트 단위 데이터를 쓰는(write) 통로
- java.io.FileOutputStream
- => 위 두개 클래스는 추상클래스
- java.io.InputStream : 프로그램이 바이트 단위 데이터를 읽어들이는(read) 통로
- 문자(character) 단위 입출력 스트림 클래스
- java.io.Reader : 프로그램이 문자 단위 데이터를 읽어들이는 통로
- java.io.Writer : 프로그램이 문자 단위 데이터를 쓰는 통로
- 파일 시스템의 파일정보를 얻기 위한 클래스
- java.io.File
- 콘솔로부터 문자를 입출력하기 위한 클래스
- java.io.Console
1. 바이트(byte) 단위 입출력 스트림 클래스
FileInputStream, FileOutputStream
package file02;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class File02Main {
public static void main(String[] args) {
System.out.println("File IO");
InputStream in = null; // 바이트 단위로 데이터를 읽고 쓰는 클래스
OutputStream out = null;
try{
in = new FileInputStream("temp/big_text.txt"); // 업캐스팅
out = new FileOutputStream("temp/copy_big_text.txt");
// 해당 파일이 없으면, 새로 생성.
// .. 있었으면, 지우고 새로 생성.
int dataRead;
// 파일 복사 - 한 byte씩 읽어서 복사한다(쓴다)
while(true) {
// 데이터 읽기: InputStream에 있는 read() 메소드 사용
// read()는 InputStream 으로부터
// 1byte 씩 읽어서 int(4byte) 에 담아 리턴한다 - 그래서 dataRead의 자료형이 int
// [ ... ][ ... ][ ... ][ 1byte ]
dataRead = in.read();
if(dataRead == -1) break; // 더이상 읽을 것이 없으면 read() 는 -1 을 리턴한다.
// 데이터 쓰기: OutputStream에 있는 write() 메소드 사용
// write() 는
// int(4byte)에 1byte씩 담아 OutputStream에 쓴다
// [ ... ][ ... ][ ... ][ 1byte ]
out.write(dataRead);
}
}catch(FileNotFoundException e){
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
// 리소스 해제, 반납
try {
if(out!=null) out.close();
if(in!=null) in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("\n프로그램 종료");
} // end main()
} // end class
- try - with - resource : Java 7 부터 도입
=> try(리소스 생성){ . . .}catch(exception ){ . . . } : 리소스를 close하는 코드가 없어도 자동으로 close가 실행
- 조건 :
java.lang.AutoCloseable 나
ㄴ> java.io.Closeable 을 상속받은 객체
- InputStream, OutputStream 둘 다 Closeable을 상속(Implements)한다.
package file03;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class File03Main {
public static void main(String[] args) {
System.out.println("File IO 2");
// try-with-resource
try(
InputStream in = new FileInputStream("temp1/big_text.txt");
OutputStream out = new FileOutputStream("temp1/copy_big_text.txt");
)
{
byte [] buff = new byte[1024]; // 버퍼 준비
int lengthRead =0;
long startTime = System.currentTimeMillis();
while(true) {
// 매개변수로 주어진 byte[] 배열의 길이 만큼 read한다.
// 실제 읽어 들인 데이터는 매개변수 byte[] 에 담김.
// 읽어들인 바이트 개수 리턴, 읽어들인게 없으면 -1 리턴.
lengthRead = in.read(buff);
if(lengthRead==-1) break;
// 데이터 쓰기
out.write(buff, 0, lengthRead); // 직전에 읽어들인 데이터만큼 write
}
long endTime = System.currentTimeMillis();
long elapsedTime = endTime-startTime;
System.out.println();
System.out.println(elapsedTime);
// 입출력 스트림으로부터 한번에 1024 바이트씩 read/write 하니까 빨라짐
}catch(FileNotFoundException e){
e.printStackTrace();
}catch(IOException e) {
e.printStackTrace();
}
System.out.println("\n프로그램 종료");
} // end main()
} // end class
보조스트림(filter stream)
: 다른 스트림과 연결되어 여러가지 편리한 기능을 제공해주는 스트림
Program <=== FilterInputStream <=== InputStream <=== Source
Program <=== BufferedInputStream <=== FileInputStream <=== File
Program ===> FilterOutputStream ===> OutputStream ===> Source
Program ===> BufferedOutputStream ===> FileOutputStream ===> File
Program <=== DataInputStream <=== FileInputStream <=== File
Program ===> DataOutputStream ===> FileOutputStream ===> File
package file04;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class File04Main {
public static void main(String[] args) {
System.out.println("BufferedInputStream, BufferedOutputStream");
InputStream in = null;
BufferedInputStream bin = null;
OutputStream out = null;
BufferedOutputStream bout = null;
try{
in = new FileInputStream("temp1/big_text.txt");
bin = new BufferedInputStream(in); // 장착!
out = new FileOutputStream("temp1/copy_big_text.txt");
bout = new BufferedOutputStream(out); // 장착!
int dataRead;
long startTime = System.currentTimeMillis();
// 파일 복사
while(true) {
dataRead = bin.read();
if(dataRead == -1) break; // 더이상 읽을 것이 없으면 read() 는 -1 을 리턴한다.
// 데이터 쓰기: OutputStream에 있는 write() 메소드 사용
bout.write(dataRead);
bytesCopied++;
}
long endTime = System.currentTimeMillis();
System.out.println(endTime - startTime);
// Buffered I/O Stream 을 기존의 I/O Stream에 장착하면, 자체적으로 버퍼링하여, 입출력의
// 속도가 향상
// -> byte[] buff = new byte[1024](=buffer)가 했던 역할과 비슷하게 어느정도 데이터가 쌓일때까지
// 자체적으로 버퍼링 ==> 버퍼의 장점을 스트림에 적용
}catch(FileNotFoundException e){
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
// 리소스 해제, 반납
try {
if(bout!=null) bout.close(); // bout 을 close 하면 bout을 만든 out 도 자동 close 됨
if(bin!=null) bin.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("\n프로그램 종료");
} // end main()
} // end class
+ 여기에 버퍼까지 제공하면 비약적으로 I/O 속도 향상
- byte [] buff = new byte[1024];
- lengthRead = bin.read(buff);
- bout.write(buff, 0, lengthRead);
- Data filter stream
package file06;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class File06Main {
public static void main(String[] args) {
System.out.println("Data Filter Stream");
try(
OutputStream out = new FileOutputStream("temp1/data.bin");
DataOutputStream dout = new DataOutputStream(out);
InputStream in = new FileInputStream("temp1/data.bin");
DataInputStream din= new DataInputStream(in);
)
{
dout.writeBoolean(true); //1byte
dout.writeInt(100); // 4byte
dout.writeDouble(3.14); // 8byte
dout.writeChar('a'); // 2byte
boolean b = din.readBoolean();
System.out.println("boolean: "+b);
System.out.println("int: "+din.readInt());
System.out.println("double: "+din.readDouble());
System.out.println("char: "+din.readChar());
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("\n프로그램 종료");
} // end main()
} // end class
Object Filter Stream
-> 객체의 입출력을 위한 스트림
Program <=== ObjectInputStream <=== FileInputStream <=== File
Program ===> ObjectOutputStream ===> FileOutputStream ===> File
- Object stream의 입출력 대상이 되는 클래스는 Serializable 인터페이스를 구현
- 클래스의 일부 멤버 변수를 직렬화(Serialization)의 대상에서 제외시키려면 transient 키워드를 사용
// File08Main.java
package file08;
// import문 생략
public class File08Main {
public static final String FILEPATH = "temp1/member.dat";
public static void main(String[] args) {
System.out.println("Object Filter Stream");
try( // try-with-resource
OutputStream out = new FileOutputStream(FILEPATH);
ObjectOutputStream oout = new ObjectOutputStream(out);
InputStream in = new FileInputStream(FILEPATH);
ObjectInputStream oin = new ObjectInputStream(in);
){
Member m1 = new Member("root", "root1234");
Member m2 = new Member("guest", "guest");
Member m3 = new Member("admin", "admin123456");
oout.writeObject(m1); // 저장하기
oout.writeObject(m2);
oout.writeObject(m3);
Member dataRead; // 읽어오기
// EOFException 으로 끝까지 read한것을 체크
// EOF : End Of File
while(true) {
dataRead = (Member)oin.readObject();
dataRead.displayInfo();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch(EOFException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println("\n프로그램 종료");
} // end main()
} // end class
// Member.java
package file08;
import java.io.Serializable;
public class Member implements Serializable{
private static final long serialVersionUID = 3596187354707645991L;
private String id;
private String pw;
transient private int num;
transient private boolean isExist;
// transient로 선언된 변수는 serialization(직렬화) 대상에서 제외됨.
// (파일에 write되지 않는다)
// de-serializtion(역직렬화, 파일에서 읽기)를 할 때는
// 해당 타입의 기본값(0, false, null)으로 초기화됨
public Member() {}
public Member(String id, String pw) {
this.id = id;
this.pw = pw;
this.num = 123;
this.isExist = true;
}
public void displayInfo() {
System.out.println("--- 회원 정보 ---");
System.out.println("아이디: " + id);
System.out.println("비밀번호: " + pw);
System.out.println("번호: " + num);
System.out.println("Exist? " + isExist);
}
} // end class Member
결과 : transient로 선언된 변수는 기본값(0, false, null)으로 초기화
+ AraayList<> 와 같은 Collection 에서, 모든 데이터들이 Serializable 되어 있으면 ObjectInputStream / ObjectOutputStream 으로 read/write 가능.
- ArrayList<Member> list = new ArrayList<Member>();
- list.add(new Member("root", "root1234"));
- list.add(new Member("guest", "guest"));
- oout.wirteObject(list);
- list = null;
- list = (ArrayList<Member>)oin.readObject();
2. 문자(character) 단위 입출력 스트림 클래스
- java.io.Reader
- java.io.InputStreamReader
- java.io.FileReader
- java.io.InputStreamReader
- java.io.Writer
- java.io.OutputStreamWriter
- java.io.FileWriter
- java.io.OutputStreamWriter
[!] 문자기반 출력시에 꼭 끝에 flush() 해주기
package file11;
// import 생략
public class File11Main {
public static void main(String[] args) {
System.out.println("FileReader / FileWriter");
String src = "temp1/FileData.txt";
String dst = "temp1/FileData.txt";
try(
FileWriter fw = new FileWriter(dst);
FileReader fr = new FileReader(src);
){
String str = "안녕하세요";
char [] charArr = {'J','V','A','A'};
// utf-8 인코딩의 경우 한글 한글자당 3바이트
fw.write(str);
fw.write(charArr);
fw.flush(); // write() 메소드를 호출한 후에는 flush() 메소드로 출력버퍼의 데이터를 완전히 출력(비움)
// 읽기(read)
char [] buff = new char[100];
int charsRead = 0; // 읽어드린 문자의 개수
charsRead = fr.read(buff);
for(int i=0;i<charsRead;i++) {
System.out.print(buff[i]);
}
System.out.println();
System.out.println("읽은 문자 개수 : "+ charsRead);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("\n프로그램 종료");
} // end main()
} // end class
- 버퍼사용 문자입출력(BufferedReader, BufferedWriter)
package file12;
// import 생략
/*
* txt 는 utf-8 로 인코딩 , 영문 텍스트
*/
public class File12Main {
private static final String BIG_TEXT = "temp1/big_eng.txt";
public static void main(String[] args) {
System.out.println("FileReader / FileWriter");
FileWriter fw = null;
FileReader fr = null;
BufferedReader br = null;
BufferedWriter bw = null;
int charRead = 0;
try {
System.out.println("BufferedReader / Writer + 버퍼 사용");
fr = new FileReader(BIG_TEXT);
fw = new FileWriter("temp1/big_eng_1");
br = new BufferedReader(fr); // 장착
bw = new BufferedWriter(fw); // 장착
char [] buf = new char[1024]; // 버퍼
while((charRead = fr.read(buf))!= -1) {
fw.write(buf, 0, charRead);
}
}catch(FileNotFoundException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (br != null)
br.close();
if (bw != null)
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("\n프로그램 종료");
} // end main()
} // end class
- PrintWriter / 인코딩
- java.lang.Object
- java.io.Writer
- java.io.PrintWriter
- java.io.Writer
* 텍스트 파일 작성시는 PrintWriter 객체 편리
println(), print(), printf() ..
* 텍스트 파일 읽을시는 BufferedReader 객체 편리
read(), read(버퍼), readLine()..
* PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("파일명" 혹은 File)));
* PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream("파일명" 혹은 File))));
*
* BufferedReader br = new BufferedReader(new FileReader("파일이름" 혹은 File));
* BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(new File("파일이름" 혹은 File))));
* BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("파일이름" 혹은 File)));
package file13;
// import 생략
* 인코딩 문제
* FIleReader, FileWriter 는 파일의 인코딩을 무조건 file.encoding 값으로 간주한다.
* (ex: LINUX 는 UTF-8, MacOS 는 한글상위의 경우 euc-kr, 윈도우즈는 Java 소스코드 인코딩 영향)
*
* 인코딩 설정하기
* InputStreamReader, OutputStreamWriter 를 사용해서 인코딩 변경을 해야 한다.
*
* BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("파일이름" 혹은 File),"인코딩"));
* BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("파일이름" 혹은 File), "인코딩"));
*
*/
public class File13Main {
private static final String FILE1 = "temp1/PrintData.txt";
private static final String FILE2 = "temp1/PrintData_euckr.txt";
public static void main(String[] args) {
System.out.println("PrintWriter / 인코딩 ");
FileWriter fw = null;
FileReader fr = null;
PrintWriter out = null;
BufferedReader br = null;
BufferedWriter bw = null;
try {
// fw = new FileWriter(FILE1);
// bw = new BufferedWriter(fw);
// out = new PrintWriter(bw);
// ㄴ> 보통 한줄로 작성
out = new PrintWriter(new BufferedWriter(new FileWriter(FILE1)));
test_write(out);
br = new BufferedReader(new FileReader(FILE1));
test_read(br);
System.out.println("현재 OS 인코딩 "+ System.getProperty("file.encoding"));
// ecu-kr로 인코딩하여 저장
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(FILE2),"euckr")));
test_write(out);
br = new BufferedReader(new InputStreamReader(new FileInputStream(FILE2),"euckr"));
test_read(br);
}catch(FileNotFoundException e) {
e.printStackTrace();
}catch(IOException e) {
e.printStackTrace();
}finally {
out.close();
try {
if(br!=null) br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("\n프로그램 종료");
} // end main()
private static void test_read(BufferedReader br) throws IOException {
String line;
StringBuffer sb = new StringBuffer();
while((line = br.readLine())!=null) {
sb.append(line+"\n");
}
System.out.println(sb);
}
private static void test_write(PrintWriter out) {
out.println("안녕하세요 Java 한글");
out.print((2000+20)+ " "+ 3.14);
out.println();
out.printf("%d",3);
out.flush();
}
} // end class
3. 파일 시스템의 파일 정보를 얻기 위한 클래스
// 데이터
private List<PhonebookModel> pbList = new ArrayList<>();
// 저장할 파일에 대한 변수
private static final String DATA_DIR = "data";
private static final String DATA_FILE = "phonebook.dat";
private File pbDir;
private File pbFile;
private void initFile() {
// 1. 데이터 저장 폴더 생성(없었다면!)
pbDir = new File(DATA_DIR);
if(!pbDir.exists()) {
if(pbDir.mkdir()) {
System.out.println("폴더 생성 성공!");
} else {
System.out.println("폴더 생성 실패!");
}
}
// 2. 데이터 저장 파일 생성(없었다면!)
File pbFile = new File(pbDir, DATA_FILE);
if(!pbFile.exists()) {
System.out.println("데이터 파일 새로 생성");
}else{
System.out.println("데이터 파일 존재 "+ pbFile.getAbsolutePath());
}
try(
InputStream in = new FileInputStream(pbFile.getAbsolutePath());
ObjectInputStream oin = new ObjectInputStream(in);
) {
PhonebookModel dataRead;
// 파일의 내용을 읽어와서 --> pbList에 담기
while(true) {
dataRead = (PhonebookModel)oin.readObject();
pbList.add(dataRead);
}
//ㄴ> pbList = (ArrayList<PhonebookModel>)oin.readObject(); 도 가능
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch(EOFException e) {
System.out.println("데이터 로딩 완료!");
}catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
@Override
public void close() throws IOException {
// TODO : pbList -> 파일로 저장
OutputStream out = new FileOutputStream(pbFile);
ObjectOutputStream oout = new ObjectOutputStream(out);
for(PhonebookModel m : pbList) {
oout.writeObject(m);
}
// ㄴ> oout.writeObject(pbList); 도 가능
}
'웹개발 > JAVA' 카테고리의 다른 글
싱글톤 클래스 (0) | 2022.02.14 |
---|---|
Java EE vs. Java SE (0) | 2021.10.31 |
[JAVA] Comparator<>, Comparable<> (0) | 2021.09.04 |
[JAVA] MAP - HashMap, TreeMap (0) | 2021.09.04 |
[JAVA] Collection - Set(HashSet, TreeSet) (0) | 2021.09.04 |