자바 입출력 Process
자바라는 언어를 통해서 외부의 데이터를 입출력할 수 있는 방법이 있다.
Input/Output Stream 클래스를 활용하는것이다.
읽거나 쓰기위한 클래스의 메서드를 이용하는데 그 과정에서는 당연한 우리의 리모콘인 객체가 선언되어 사용될 것이다.
그리고 파일안에 데이터를 읽거나 쓰고나서는 반드시 닫아주는 작업까지 해줘야 한다는 사실.
STEP1) 사용할 리모콘 객체 선언하기
package edu.java.file01;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileMain01 {
public static void main(String[] args) {
FileInputStream in = null;
FileOutputStream out = null;
파일에서 데이터를 읽어오는 FileInputStream 클래스의 객체 in을 선언하고 null로 초기화해주고!
또 데이터를 내보내서 쓰게하는 기능이 있는 FileOutputStream 클래스의 객체 out을 선언하고 null로 초기화해준다.
try {
// data 폴더에 있는 test.txt 파일을 읽기 위한 스트림 객체 생성
in = new FileInputStream("data/test.txt");
// data 폴더에 test_copy.txt 파일을 쓰기 위한 스트림 객체 생성
out = new FileOutputStream("data/test_copy.txt");
// 파일 복사 시작 시간 측정.
long startTime = System.currentTimeMillis();
while (true) {
int read = in.read(); // 읽기 - 파일에서 1 바이트씩 읽고, 읽은 내용은 리턴.
// System.out.println(read + ":" + (char) read);
if (read == -1) { // read() 메서드는 파일 끝(EOF:end of file)에 도달했을 때 -1을 리턴
break; // 무한 루프 종료
}
out.write(read); // 쓰기 - 파일에 1바이트씩 쓰기(write)
}
System.out.println("파일 복사 성공");
// 파일 복사 종료 시간 측정.
long endTime = System.currentTimeMillis();
long elapsedTime = endTime - startTime; // 복사하는 데 걸린 시간 측정
} catch (IOException e) {
e.printStackTrace();
} finally {
// 예외가 발생하지 않아도(try 블록이 정상적으로 끝났을 때),
// 예외가 발생하더라도 (catch 블록이
// 열려져 있는 FIS, FOS 객체는 닫아야 함!
try {
in.close(); // FileInputStream 객체 close
out.close(); // FileOutputStream 객체 close
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
객체에 각각의 생성자의 경로를 저장해줄때에 try-catch 구문안에 넣어주는데 그 이유는 FileInput/Output 클래스가 FileNotFoundException, 즉 예외구문을 throws 하기 때문이다. 하여 그 처리를 위해 사용한 것인데,
굳이 하나씩 코딩하지말고 자동완성 기능을 이용하면 편리하다. 그리고 catch () 괄호안에는 최상위 클래스인 Exception으로 표기해도 상관은없다.
파일안의 데이터를 읽는데 얼마나 시간이 걸리는지 알기위해서
long startTime = System.currentTimeMillis(); 이란 변수도 선언해주고
무한 반복문 while(true) 을 통해서 1byte씩 데이터를 읽고 끝에 도달하면 read() 메서드가 -1을 리턴하므로 이를 이용해서 break문을 완성한다.
그리고 finally에서는 객체들을 닫아주는걸로 마무리한다.
package edu.java.file02;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class FileMain02 {
public static void main(String[] args) {
FileInputStream in = null;
FileOutputStream out = null;
try {
in = new FileInputStream("data/test.txt");
out = new FileOutputStream("data/test_copy2.txt");
long startTime = System.currentTimeMillis(); // 복사 시작 시간.
while (true) {
// 파일에서 읽은 데이터(바이트)를 저장하기 위한 배열
byte[] buffer = new byte[20]; // 20바이트를 저장할 수 있는 배열
int result = in.read(buffer); // 파일에서 읽은 데이터 개수(바이트 수)를 리턴.
if (result == -1) { // 파일 끝(EOF)에 도달하면
break; // while 종료
}
// out.write(buffer);
// -> write(byte[] b) : 바이트 배열의 내용을 그대로 파일에 write.
out.write(buffer, 0, result);
// -> write(byte[], int off, int len):
// byte 배열 b에서 인덱스 off부터 len개까지를 파일에 write.
}
long endTime = System.currentTimeMillis();
long elapsedTime = endTime - startTime;
System.out.println("파일 복사 종료 - " + elapsedTime + "ms");
} catch (Exception e) {
e.printStackTrace(); // 에러발생지점 추적 메서드
} finally {
try {
in.close();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
근데 외부 파일의 데이터를 읽어올때 만약 용량이 크고 데이터의 양이 크다면 1byte씩 읽어서는 끝이 나지 않을 것이다. 그래서 byte를 배열타입으로 읽어 한번에 얼마나 데이터를 읽을지 정해줄 수 도 있다.
위에서는 20byte씩 읽어오는걸로 결정했다.
package edu.java.file04;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
/*
* 프로그램 <== BufferedInputStream <== FileInputStream <== 파일(하드디스크)
* FileInputStream : 하드디스크에 저장된 파일을 읽고 메모리(RAM)에 적재.
* BufferedInputStream : 메모리(RAM)에 있는 파일에서 데이터를 읽는 메서드(read)를 제공.
*
*
* 프로그램 ==> BufferedOutputStream ==> FileOutputStream ==> 파일(하드디스크)
* FileOutputStream: 하드디스크에 파일을 씀.
* BufferedOutputStream: 메모리(RAM)에 데이터를 쓰는 메서드(write)를 제공.
*/
public class FileMain04 {
public static void main(String[] args) {
FileInputStream in = null; // 하드디스크 파일에서 데이터를 읽기 위한 통로
BufferedInputStream bin = null; // 메모리 파일에서 데이터를 읽기 위한 통로
FileOutputStream out = null; // 하드디스크 파일에 데이터를 쓰기 위한 통로
BufferedOutputStream bout = null; // 메모리 파일에 데이터를 쓰기 위한 통로
try {
in = new FileInputStream("data/ratings.dat");
bin = new BufferedInputStream(in);
out = new FileOutputStream("data/ratings_copy.dat");
bout = new BufferedOutputStream(out);
long startTime = System.currentTimeMillis();
while (true) {
byte[] buffer = new byte[4 * 1024];
int result = bin.read(buffer);
if (result == -1) {
break;
}
bout.write(buffer, 0, result);
}
long endTime = System.currentTimeMillis();
long elapsedTime = endTime - startTime;
System.out.println("복사 완료 - " + elapsedTime + "ms");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
// 가장 마지막에 생성된 InputStream과 OutputStream만 close를 하면
// 다른 Stream 객체들은 자동으로 close가 됨.
bin.close(); // BIS를 close를 하면, BIS이 사용하는 FIS은 자동으로 close.
// in.close();
bout.close(); // BOS을 close를 하면, BOS이 사용하는 FOS도 자동으로 close.
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
그 동안 했던 작업들은 모두 하드디스크에서 그 데이터를 불러왔었다. 하지만 하드디스크는 RPM이라고 해서 하드내부에 원판이 회전하면서 데이터를 이동시키기 때문에 그 처리속도가 SSD보다 현저히 느리다.
그러므로 우리가 이용할 데이터를 SSD를 통해 불러온다고 가정했을때 코드는 어떻게 처리할 것인지 코딩을 해보았다.
프로그램 - SSD - 하드디스크 의 관계에서 읽어올때에는 하드디스크 -> SSD -> 프로그램 순서로
데이터를 입력할때에는 프로그램 -> SSD -> 하드디스크 순서로 데이터가 전달된다.
내일 강의에서는 연락처프로그램에서 오늘 배운내용을 어떻게 적용시킬 수 있는지 공부할 예정이다~.
그럼 내일 또 공부하고 글을 올려보겠다~

빠잉