I/O와 Stream
I/O
- 데이터의 입력(input)과 출력(output)
노드(Node)
입력과 출력의 끝단
키보드, 모니터, 메모리, 파일, 데이터베이스, 네트워크 등
스트림(Stream)
두 노드를 연결하고 데이터를 전송할 수 있는 개념
단방향으로만 통신이 가능하며 하나의 스트림으로 입력과 출력을 같이 처리할 수 없음
바이트 스트림( Byte Stream )
binary 데이터를 입출력하는 스트림입니다.
이미지, 동영상 등을 송수신할 때 주로 사용합니다.
InputStream / OutputStream
- byte 기반 input / output stream의 최고 조상
ByteArrayInputStream / ByteArrayOutputStream
- byte array( byte[] )에 대한 데이터를 입출력 하는 클래스
FileInputStream / FileOutputStream
- 파일( File )에 대한 데이터를 입출력 하는 클래스
문자 스트림( Character Stream )
말 그대로 text 데이터를 입출력하는데 사용하는 스트림입니다.
HTML 문서, 텍스트 파일을 송수신할 때 주로 사용합니다.
Reader / Writer
- Character 기반 input / output stream의 최고 조상
FileReader / FileWriter
- 문자 기반의 파일을 입출력 하는 클래스
스트림(Stream) 주요 메서드
InputStream의 주요 메서드
read()
바이트 한 개씩 읽음
Buffer만큼 씩 읽음
close()
System.out.println("입력하세요"); byte[] buffer = new byte[10]; try(InputStream input = System.in){ int read = -1; while((read = input.read(buffer)) > 0){ System.out.println("읽은 값: "+read+", 문자열로: "+ new String(buffer, 0, read)); } }catch(IOException e){ e.printStackTrace(); } //입력값 자바는 객체지향 언어입니다 //출력값 읽은 값: 10, 문자열로: 자바는 객? 읽은 값: 10, 문자열로: 셉置? 언어 읽은 값: 8, 문자열로: 입니다
buffer : 데이터를 한 번에 읽을 수 있기위해 생성한 배열.
read(byte[]), read(byte[], int, int) : 버퍼단위로 데이터를 읽음.
한계 : InputStream은 byte단위의 전송때문에 한글자가 2byte이상인 한글은 깨짐 => Reader사용
OutputStream의 주요 메서드
write()
close()
- 내부적으로 flush()를 호출한다
flush()
- 버퍼가 있는 스트림에서 버퍼의 내용을 출력하고 버퍼를 비운다
try(Writer wr = new OutputStreamWriter(System.out)){ String msg = "안녕"; wr.write(msg); wr.append("피곤한").append("월요일"); }catch(IOException e){ e.printStackTrace(); } //출력값 안녕피곤한월요일
InputStream / OutputStream - ByteArrayStream
public class IOExample { public static void main(String[] args) { byte[] src = {0, 1, 2, 3}; byte[] dest = null; try{ InputStream is = new ByteArrayInputStream(src); OutputStream os = new ByteArrayOutputStream(); int data = -1; while( (data = is.read()) != -1 ){ os.write(data); } dest = ((ByteArrayOutputStream)os).toByteArray(); System.out.println(Arrays.toString(dest)); // [0, 1, 2, 3] } catch (IOException e){ e.printStackTrace(); } } }
InputStream / OutputStream - FileStream
public class FileCopy { public static void main(String[] args) { InputStream is = null; OutputStream os = null; try{ // ./는 현재경로를 의미합니다. is = new FileInputStream("./asd.jpg"); os = new FileOutputStream("./sad.jpg"); int data = -1; while( (data = is.read()) != -1 ){ os.write(data); } } catch (FileNotFoundException e){ System.out.println("파일 없음"); e.printStackTrace(); } catch (IOException e){ System.out.println("I/O 에러"); e.printStackTrace(); } finally { // 예외가 발생했을 때도 스트림을 닫아야 하므로 finally에서 스트림을 닫아줍니다. try { if( is != null ){ is.close(); } if( os != null ){ os.close(); } } catch ( IOException e){ e.printStackTrace(); } } } }
Reader의 주요 메서드
read()
char 한 개씩 읽음
Buffer만큼 씩 읽음
close()
char[] buffer = new char[10]; try(Reader rd = new InputStreamReader(System.in)){ int read =-1; while((read = rd.read(buffer)) > 0){ System.out.println("읽은 값: "+read+", 문자열로: "+ new String(buffer, 0, read)); } }catch(IOException e){ e.printStackTrace(); } //입력값 자바는 객체지향 언어입니다 //출력값 읽은 값: 10, 문자열로: 자바는 객체지향 언 읽은 값: 6, 문자열로: 어입니다
Writer의 주요 메서드
write()
append()
close()
flush()
try(Writer wr = new OutputStreamWriter(System.out)){ String msg = "안녕"; wr.write(msg); wr.append("피곤한").append("월요일"); }catch(IOException e){ e.printStackTrace(); } //출력값 안녕피곤한월요일
File의 주요 메서드
파일의 수정 불가
File()
createNewFile()
mkdir()
mkdirs()
delete()
getName()
getPath()
getAbsolutePath()
isDirectory()
isFile()
length()
listFiles()
import java.io.File; public class MainClass07 { public static void main(String[] args) { //new File("새로 만들거나 제어하고 싶은 파일이나 폴더의 경로") File f = new File("c:/"); String[] names = f.list(); //배열에 있는 내용을 반복문 돌면서 콘솔창에 모두 출력할 수 있을까요? for(int i=0;i<names.length;i++) { String tmp = names[i]; System.out.println(tmp); } System.out.println("확장 for 문을 이용하면"); for(String tmp:names) { System.out.println(tmp); } } }
import java.io.File; public class MainClass08 { public static void main(String[] args) { File cDrive = new File("c:/"); //c 드라이브에 각각의 폴도나 파일을 제어 할 수 있는 객체의 참조값을 배열로 얻어내기 File[] files = cDrive.listFiles(); for(File tmp:files) { //만일 디렉토리라면 if(tmp.isDirectory()) { System.out.println("<DIR>\t"+tmp.getName()); }else { System.out.println(" \t"+tmp.getName()); } } } }
FileReader
import java.io.File; import java.io.FileReader; import java.io.IOException; public class MainClass10 { public static void main(String[] args) { File memoFile = new File("c:/developer/myFolder/memo.txt"); try { if(!memoFile.exists()) { System.out.println("파일이 존재하지 않습니다."); return; //메소드 끝내기 } //파일에서 문자열을 읽어들일 객체 FileReader fr = new FileReader(memoFile); //무한 루프 돌면서 while(true) { //글자의 코드값을 하나씩 읽어온다. int code = fr.read(); //더이상 읽을게 없다면 반복문 탈출 if(code==-1) break; //코드값에 해당하는 char 값 얻어내기 char ch = (char) code; //콘솔에 한글자씩 출력하기 System.out.print((char)code); } }catch(IOException ie) { ie.printStackTrace(); } } }
FileWriter
import java.io.File; import java.io.FileWriter; import java.io.IOException; public class MainClass09 { public static void main(String[] args) { //문자열을 저장할 파일을 만들기 위한 File 객체 File memoFile=new File("c:/developer/myFolder/memo.txt"); try { //파일이 이미 만들어 졌는지 여부 boolean isExist=memoFile.exists(); if(!isExist) { //파일을 만들어준다. memoFile.createNewFile(); System.out.println("memo.txt 파일을 만들었습니다."); } //파일에 문자열을 출력할 수 있는 객체 생성 FileWriter fw = new FileWriter(memoFile); fw.write("이00\n"); fw.write("\t김00\n"); fw.write("\t\t박00"); fw.flush();//방출하기 fw.close();//닫아주기(마무리) System.out.println("파일에 문자열을 저장했습니다."); }catch(IOException ie) { ie.printStackTrace(); } } }
보조 스트림(FilterStream)
다른 스트림에 부가적인 기능을 제공하는 스트림
"프로그램에서" 파일을 읽기/쓰기 할 수 있도록 해준다
스트림 체이닝
- 필요에 따라 여러 보조 스트림을 연결해서 사용 가능
FilterInputStream / FilterOutputStream
- byte 기반 보조 스트림의 최고 조상
InputStreamReader / OutputStreamReader
byte 기반 스트림을 character 기반 스트림처럼 쓸 수 있도록 함
인코딩 변환 가능
문자열을 관리하기 위해서는 byte 단위보다 char 단위가 유리
키보드에서 입력(byte stream) 받은 데이터를 처리할 경우 등
BufferedInputStream / BufferedOutputStream
- 입출력 효율을 높이기 위해 버퍼( byte[] )를 사용하는 보조스트림
BufferedReader / BufferedWriter
입출력 효율을 높이기 위해 버퍼( char[] )를 사용하는 보조스트림
라인 단위의 입출력에 용이
ObjectInputStream / ObjectOutputStream
객체 전송 보조 스트림
객체 직렬화
implements Serializable
직렬화 제외하려는 멤버는 transient 선언
직렬화 할 때의 UID와 역 직렬화 할 때의 UID가 다를 경우 예외 발생
- UID가 설정되지 않았을 경우 컴파일러가 자동 생성
자바 직렬화의 what, how, why, when, where
직렬화 방법 개선
참고 자료