[210511화] FileIO, InputStream, OutputStream
[1교시]
[IO란?] java.io
정보를 메모리 안에 넣는 것(Input, 키보드를 통해 Scanner)
정보를 화면에 출력하는 것(Output)을 일컬어 IO라고 칭한다.
하드디스크 안에 있는 데이터를 읽어 메모리로 보내서 모니터로 출력하거나 다른 하드디스크로 내보낼 수 있다.
키워드로부터 입력받은 것을 모니터, 하드디스크 혹은 둘 다로 등등 어디로든 내보낼 수 있다.(개발자 마음)
[하드디스크에 있는 데이터, 파일을 Input(불러오려면)하려면?]
- 파일이 존재하는지 여부 확인, 없으면 오류(Exception 처리)
- 참조 변수를 만들어 읽어들이는 작업을 한다.
- 파일을 저장해 Output, 저장할 때와 읽어들일 때 이름은 다르다.
- 파일 객체를 생성하는 것을 Open이라고 한다. Open한 파일에 들어있는 데이터를 사용한 후 하드디스크 저장이 완료되면 반드시 close를 해야 한다. (안하면 파일 손상, 마치 냉동고를 열어둔 것과 같다.)
java.io.* : 우리가 사용한 클래스들이 들어있는 파일
input : 데이터를 끌어들일 때, 불러올 때
input -> output 가는 과정이 시냇물과 같다고 InputStream, OutputStream으로 표현한다.
★InputStream, OutputStream는 최상위 클래스이며, byte 단위로 처리(문자로 읽어들일 수 없는 것들, 그림, 확장명이 exe인 파일), byte로 된 파일은 InputStream, OutputStream으로 처리하고 밑에 하위 클래스가 많다.
Stream이 있으면 무조건 byte로 된 파일이라는 것!
[데이터의 흐름]
Stream은 입력과 출력 두 가지로 나누는데, 현재의 프로그램 쪽으로 입력이 되는 InputStream, 현재의 프로그램에서 출력이 되는 Stream을 OutputStream이라고 한다.
★Reader/Writer : 문자단위로 처리
Fiteness는 메모리에 저장한 것, 데이터를 불러들일 때, 읽을 때 Stream 무슨 말이지?
[FileIO의 큰 카테고리]
① InputStream, OutputStream(Object)
② Reader/Writer
③ File
File은 기본 생성자가 생성되지 않는다.
.exists()
.isFile()
.isDirectory()
→ 용도: 파일이 존재하는지 물어볼 수 있다.
"Test.java"라는 파일은 실제로 존재하지 않기 때문에 false가 출력된다.
c:\temp에서 \를 탭키로 인식 ↓
위의 작업은 하드디스크에 접근하려는 준비였음
→ [하드디스크를 Input하려면?] - 파일이 존재하는지 여부 확인, 없으면 오류(Exception 처리)
[파일 생성] .createNewFile();
파일을 만들려했는데 에러가 났다?
오류 : Unhandled exception type IOException
하드디스크에서 일어나는 모든 일은 exception을 처리해줘야 하고 thows exception을 사용, 던지면 자바가상머신이 처리한다. Surround with try/catch를 눌러주면 알아서 만들어 준다.
파일을 만들었을때 확인을 성공 여부를 if문으로 해준다.
파일이 생성되었을 경우 위의 사진과 같이 확인할 수 있다.
[디렉토리 생성] .mkdir();
파일 sub, abc.txt를 확인하려면 해당 자바 프로젝트 누르고 F5(새로고침)해주세요.
File f1 = new File("Test.java");
File f2 = new File("c: \\ttemp");
File f3 = new File("abc.txt");
File f4 = new File("./sub");
File f1, f2와 다르게 f3, f4는 f3.createNewFile(), f4.mkdir()과 같이 파일이나 디렉토리를 생성하는 작업을 했다는 것이 차이이다!
net.scit41.io 이름의 패키지를 만들어 주세요.
[2교시]
InputStream | 상위 | 하위 |
FileInputStream PipedInputStream |
BufferedInputStream |
InputStream 위에 적혀있는 것보다 종류가 훨씬 많지만 자주 사용하는 것으로 가져와보았다.
FileInputStream
BufferedInputStream
하위로 갈수록 성능이 좋아 BufferedInputStream이 FileInputStream 보다 성능이좋다.
char 변수 ← 'a', 'b', 'c' .....'\r','\n' ← 키보드 입력
입력 버퍼 동작에서 엔터는 '\r','\n'
Stream은 데이터가 흘러들어왔다가 흘러나가는데 Input이니까 흘러들어온 것
InputStreamTest
resource에 접근하는 것은 throw catch로 exception 처리
에러남 다시 해보기 10시 15분
아 원래 에러가 났던 곳이구나
위에 이어서 "abc.txt"을 이용해 계속 진행,,
다른 것(kbs)을 넣으면 "파일 오픈 실패" 출력
파일 오픈 실패하게 되면 null이 들어간다. 파일을 열고 나면 반드시 close를 해야 한다.
finally는 try~catch에서 마지막에 한번만 사용할 수 있다. 어떤 경우에 사용하냐하면 try에서 작업하던 것을 뒷처리할 경우 사용한다.
close는 파일을 열었을 때(open을 해야지만) close도 할 수 있는 것이다. fis가 열렸니? => if(fis != null)
null일 경우 아예 close 자체를 못한다.
kbs는 abc와 비교하는 용도로 사용되었다. 여기가 왜 이렇게 들어가 있는지 모르겠네 계속 오류처리해서 이렇게 된 것이다.
FileInputStream는 파일의 데이터를 읽어들이기 위해서 사용하지만 abc와 kbs는 아무것도 없기 때문에 열기는 하지만 아무것도 읽을 수가 없다.
InputStream은 1byte처리하기 때문에 영문의 경우는 괜찮지만, 한글은 기본적으로 2byte 이상 필요하다.
그렇기 때문에 1byte로 처리할 수 있는 영문으로된 노래 가사 가져와서 abc.txt로 가져오기
byte로 된 파일은 InputStream, OutputStream으로 처리하기이기 때문에 영문가사를 읽어들이는 InputStream의 메소드를 사용할 것!
메소드 .read() 사용할 것이다. 메소드 .read()는 int 정수를 반환하고, 즉 노래가사 한 글자 한 글자를 읽어들여서 정수 변환을 해당 범위 끝까지 돈다. 그때 더 이상 돌 수 없다는 것을 표현해줘야 한다. "더 이상 읽을 수 없다, 더 이상은 읽을 문자가 없다."는 의미로 -1를 return한다.(약속을 한 것 )
데이터를 읽을 변수 data를 선언하고 데이터를 읽은 것을 화면에 출력한다.
이 때 data의 값은 정수이기 때문에 형 변환으로(char) 문자로 변환한다.
Exception은 하위 먼저 잡는다.
출력하면 딱 1개의 글자가 출력된다. 그러면 몇 번을 출력해야하는가? 글자 수만큼!
반복문을 사용해야하는데 글자 수만큼 루프를 돌아야해서 몇 번 반복해야 할지 모른다. 이런 경우 우리가 사용하는 while 반복문
그렇다면 언제 while문에서 빠져나갈 수 있는가?
값이 없어 더 이상 입력할 수 없다를 의미하는 -1이 return되는 경우 while문을 종료시킬 수 있다.
도대체 몇 번 반복을 해야하는지 궁금하다면 변수 int count를 사용해 총 글자수와 몇 번을 반복해야하는지 확인한다.
성능은 안좋아 보인다^^
catch때문에 정신없지만 main은 간단함 ↓
try {
fis = new FileInputStream("abc.txt");
int data;
int count = 0;
while(true) {
data = fis.read(); // 데이터를 읽음
if(data == -1) break;
count++;
System.out.print((char)data); // 메소드 read를 이용해 파일의 문자 1개를 읽어온 값, 정수를 문자열로 형변환을 해서 화면에 출력
}
<수업시간 반복 2번 보세요~!>
InputStream는 1 byte
글자 수만큼 돌고, 읽어 들여서 정수 변환
몇 번 루프를 돌지 몰라 while
-1이 되면 while이 끝남
InputStream을 복사해 OutputStream으로 만들기
[OutputStream]
지저분한 try~catch를 지워주고 에러가 나도 정리해주세요. try~catch를 지움으로써 try~catch로 잡았던 것들이 사라져서 그렇다.
에러가 총 3군데에 발생했는데 잡지말고 밖으로 던집시다.
data = fis.read();에 마우스를 가져다 놓고 add throw declaration 선택!
왜냐하면 read()에서 발생시키는 것이 가장 상위이기 때문이다.
그러면 코드가 비교적 깔끔해진다.
abc.txt로 입력한 것을 모니터에 보내지 않고, abcCopy.txt라는 파일로 보냄
abc.txt(read()) -->>>> abcCopy.txt(write)는 꼭 close()해주기, 언제까지 데이터가 들어오는지 모르기 때문에 꼭 close를 해줘야 한다.
abc.txt은 파일을 읽어들이는 파일이기 때문에 파일이 있으면 열고, 없으면 에러, 오류를 터트린다.
abcCopy.txt는 있으면 기존 삭제, 없으면 새로 생성
fis에서 읽어서 fos에 복사한다.
System.out.print((char)data); 화면에 출력을 나타내는 것을 잠시 주석처리 해주세요.
if(fos != null) fos.close();
닫아주는 작업을 꼭 해줘야 한다!
똑같이 복사된 것을 확인할 수 있다.
abcCopy.txt는 abc.txt를 복사한 것이기 때문에 내용이 같아야 한다.
영문의 경우는 글자 1개가 1 byte이지만 한국어, 일본어 등등은 1byte이상은 Stream에서는 읽지 못한다.
Stream을 사용하기 전에 처리할 값이 byte로 처리되는지 아닌지 확인해야 한다.
복사는 되지만 출력하지 못한다.
사진의 경우
C:\workspace\Day0511_FileIO
해당 주소 안에 들어가 있어야 한다.
[3교시]
byte는 그림, exe, 1byte인 영어만 출력 가능하다.
[한글 넣어보기]
class ReaderTest 만들어주세요.
open을 못하면 null, close도 못하기 때문에 if문을 걸어줌
아직 song이라는 파일이 없기 때문에 FileNotFoundException이라는 Exception이 뜬다.
복사해보기
아까 2교시에 놓친 부분인데 잘보자!
FileReader, FileWriter는 이해하기는 좋지만 성능이 좋지는 않다.
score 파일을 만들어 주세요.
Stream은 byte 단위로 정수를 문자 하나로 변환해 출력했다.
문자 하나를 읽는 것은 의미가 없다. read, write와 다르게 input보다 성능이 좋은 class가 필요함!
데이터를 의미있는 한 줄 단위로 사용할 때
=> bufferedReader
=> bufferedWriter
Buffered는 기존의 있던 것을 확장한 기능이 개선된 개념
데코레이션 패턴 : 호스가 짧아 다른 호스와 연결해 사용하는 것처럼 자바에서도 다른 기능과 연결해서 사용한다. 성능이 낮은 클래스와 연결해서 사용한다. BufferedReader를 쓸 것이고 FileReader와 연결한다.
BufferedReader에서 FileReader를 사용하고 싶을 때 직접 연결할 수 없으니까 br = new BufferedReader(new FileReader("score.txt"));을 이용해 FileReader을 통해 파일을 읽어오고, BufferedReader를 통해 한 줄로
.readLine() : 한 줄을 읽는 것, 한 줄을 읽어 String으로 리턴한다.
score에서는 딱 5번만 읽으면 된다.
한 줄씩 읽음. ex) 홍길동 100 98 67
정수가 리턴되는 것이 아니라 문자열이 리턴됨
효율적으로 데이터를 읽어주는 문자열일뿐이지 계산할 수 없음
만약 계산을 하고 싶다면 Spilt(Spilt(" "))으로 잘라서 분해를 하고 문자열 배열로 리턴, 1번, 2번, 3번방 안에 들어있는 데이터를 Integer.parseInt()한 후에 합계와 평균을 구한다.
String hong = "홍길동 100 98 67" => (Spilt(" ") => "100" parseInt
이것을 과제로!