프로세서->하드디스크
write stream ,read stream이라는 다리를 놓아야 한다.
둘 다 동시에 하고싶으면 두개의 다리를 놓아야 한다.
그래서 우리는 입출력을 하기 위해서 스트림을 만들어달라고 요청해야한다.
다리 중간에는 버퍼라는 저장소(메모리)가 있고, 그것은 큐라는 자료구조를 가지고있다.(순서를 가지는 배열형태로 되어있다) 또한 전기신호로 작동하기 때문에 빠르다.
하드가 느려서 프로세서와 속도차이가 너무 난다. ->하나씩 전달하기엔 비효율적, 그러므로 버퍼에 저장해놓고 한번에 보낸다.
모든 통신은 버퍼가 존재한다. 한번에 모아서 처리해야 속도가 빠르기 때문이다.
InputStream,OutputStream클래스는 다리연결을 해준다. - 파일과 연결역할
(파일은 프로젝트 폴더 안에 있어야 한다)
package ex00.fileio.copy;
import java.io.*;
public class ByteFileCopy throws FileNotFoundException{
public static void main(String[] args) {
// 1번 파일을 읽고 2번 파일에 기록하자(파일 복사)
// 1번 파일은 read(input) stream을 열고
// 2번 파일은 write(output) stream을 연다
InputStream in=new FileInputStream("putty.exe");
//파일을 발견하지 못하여 오류 - throws ->메인에서 던지면 jdk로 간다.
//jdk로 던지면 콘솔창에 에러를 안내.
OutputStream out = new FileOutputStream("푸티.exe");
}
}
1바이트씩 읽어오도록.
package ex00.fileio.copy;
import java.io.*;
public class ByteFileCopy {
public static void main(String[] args) throws IOException {
// 1번 파일을 읽고 2번 파일에 기록하자(파일 복사)
// 1번 파일은 read(input) stream을 열고
// 2번 파일은 write(output) stream을 연다
// 1)Stream이 생성되어 파일과 연결됨
InputStream in=new FileInputStream("putty.exe");
OutputStream out = new FileOutputStream("푸티.exe");
// 2) putty.exe를 읽어서 푸티.exe에 저장 (1바이트씩 읽는다)
int copyByte = 0; // 몇바이트 읽어서 전송했는지
int bData = 0 ; // 1byte를 저장할 공간
while(true){
bData = in.read(); //putty.exe로부터 1byte 읽었다.
if(bData == -1)
break;
else {
out.write(bData); //푸티.exe에 1byte 저장
copyByte++; //읽은 크기를 기록
}
}
in.close(); // 스트림이 닫힌다(putty.exe 파일과의 연결이 끊어진다)
out.close(); // 스트림이 닫힌다(푸티.exe 파일과의 연결이 끊어진다)
System.out.println("복사된 바이트 크기 : "+ copyByte);
}
}
파일을 한번에 더 많이 읽어올 수 있도록 배열을 이용한다. (최대 1024까지) - 읽어들이는 속도가 빨라진다.
public class ArrayFileCopy {
public static void main(String[] args) throws IOException {
InputStream in = new FileInputStream("putty.exe");
OutputStream out = new FileOutputStream("푸푸티.exe");
byte buf[] = new byte[1024]; //한번에 많이 읽어서 저장할 공간 1024
int copyByte = 0 ; //전체 읽고 복사한 크기
int readLen = 0 ; //한번에 읽어들인 크기
while(true){
// putty.exe로부터 파일을 한번에 읽어서 buf에 저장해라
// 실제 읽어들인 크기는 readLen으로 반환한다
readLen = in.read(buf);
if(readLen == -1) //파일의 끝. 더이상 읽을 것이 없다
break;
else {
// 푸푸티.exe에 buf의 처음위치부터 readLen의 크기만큼 복사해라
out.write(buf, 0, readLen);
copyByte += readLen; //읽어들인 크기를 readLen만큼 증가
}
}
in.close();
out.close();
System.out.println("복사한 파일 크기 : " + copyByte);
}
}
Filter class
Filter 클래스를 사용하지 않으면 모든 변수를 바이트로 변환해야 한다.
Filter클래스를 쓰면 굳이 바이트배열로 만들지 않아도 편리하게 사용할 수 있다.
package ex00.fileio.filter;
import java.io.*;
public class DataFilterStream { // int,double 등을 쉽게 읽어 올 수 있게하는 클래스
public static void main(String[] args) throws IOException {
// 1) 스트림 생성 -> 원하는 변수 저장을 위한 기능을 가진 Filter클래스를 결합
OutputStream out = new FileOutputStream("data.bin"); //실제동작
DataOutputStream fOut = new DataOutputStream(out); //이 클래스를 통해 입출력을 할 수 있도록 실제객체를 매개변수에 넣어준다.
fOut.writeInt(999);
fOut.writeDouble(3.14);
String s = "안녕하세요";
byte[] sBuf = s.getBytes(); //String -> byte[]로 변환(일반적으로 바이트로 주고받기 때문에)
fOut.write(sBuf);
fOut.close(); //스트림 닫기
// 2) input 스트림 생성 -> 원하는 값을 읽어오기 위한 기능을 가진 Filter클래스를 결합
InputStream in = new FileInputStream("data.bin");
DataInputStream fIn = new DataInputStream(in);
int num = fIn.readInt();
double dNum = fIn.readDouble();
byte[] buf = new byte[1024]; //byte[] 저장공간 확보
int len = fIn.read(buf); //byte[]로 읽는다, len은 읽은 크기
String str = new String(buf,0,len); //byte[] -> String으로 변환 buf의 index0부터 len크기만큼 String으로 바꿔라
fIn.close(); //스트림 닫기
System.out.println("int : " + num);
System.out.println("double : " + dNum);
System.out.println("String : " + str);
}
}
많이 읽어올 수 있도록 하는 Filter 클래스를 이용 (Buffered~ 클래스 : 저장소 역할)
-> 필터클래스 내부에 버퍼가 존재하여 많이씩 읽어들일 수 있다.
한번에 왕창 읽어서 메모리에 보관하여 1바이트씩 저장한다.
프로세서 안에 버퍼라는 메모리를 두었다.
하드에서 읽어들일 때 한번에 2메가(default) 정도의 크기를 버퍼에 저장한다.
파일로부터 직접 읽어들이는 것이 아니라 메모리상에서 1바이트씩 읽어들인다.
그리고 저장시 버퍼에 1바이트씩 저장.
(택배 보관소 하나 만들어서 모두 가져온 뒤 거기서 하나씩 배달.)
그러므로 똑같은 1바이트이지만 파일로부터 가져온 것과 버퍼에서 가져온 것은 속도가 차이난다.
public class BufferedFileCopy {
public static void main(String[] args) throws IOException {
// 1.in/out 스트림 생성
InputStream in = new FileInputStream("putty.exe");
OutputStream out= new FileOutputStream("푸티티.exe");
// 2. 버퍼 필터 클래스와 결합 (파일로부터 한번에 많이 읽어서 메모리에 보관 / 속도 향상 기능)
BufferedInputStream bIn = new BufferedInputStream(in);
BufferedOutputStream bOut = new BufferedOutputStream(out);
// 3. 파일 읽고 복사 (속도 향상을 확인)
int copyByte = 0 ; //읽고 기록한 크기
int bData; // 1byte씩 저장할 공간
while(true){
bData = bIn.read(); //버퍼로부터 1byte씩 읽어들인다.
if(bData == -1)
break;
else {
bOut.write(bData); //버퍼에 1byte씩 저장한다
copyByte++;
}
}
// 4. 파일 스트림 닫기
bIn.close();
bOut.close();
// 5. 결과 출력
System.out.println("복사된 바이트 크기 : "+ copyByte);
}
}
버퍼도쓰고, 바이트배열도 쓰면 속도가 훨씬 빨라진다.
public class BufferedFileCopy2 {
public static void main(String[] args) throws IOException {
// 1.in/out 스트림 생성
InputStream in = new FileInputStream("eclipse.zip");
OutputStream out= new FileOutputStream("이클립스.zip");
// 2. 버퍼 필터 클래스와 결합 (파일로부터 한번에 많이 읽어서 메모리에 보관 / 속도 향상 기능)
BufferedInputStream bIn = new BufferedInputStream(in);
BufferedOutputStream bOut = new BufferedOutputStream(out);
// 3. 파일 읽고 복사 (속도 향상을 확인)
byte[] buf = new byte[1024*1024];
int copyByte = 0 ; //읽고 기록한 크기
int len; // 버퍼로부터 읽어들인 크기
while(true){
len = bIn.read(buf); //버퍼로부터 len만큼 읽어들인다.
if(len == -1)
break;
else {
bOut.write(buf, 0, len); //버퍼에 len만큼 저장한다
copyByte += len;
}
}
// 4. 파일 스트림 닫기
bIn.close();
bOut.close();
// 5. 결과 출력
System.out.println("복사된 바이트 크기 : "+ copyByte);
}
}
비교하기
시간측정 : Buffered 클래스를 이용하여 byte로 가져올때와 byte 배열로 가져올 때의 속도를 시간으로 측정해 보았다.
package ex00.fileio.filter;
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 BufferedFileCopy {
public static void main(String[] args) throws IOException {
// 1.in/out 스트림 생성
InputStream in = new FileInputStream("eclipse.zip");
OutputStream out= new FileOutputStream("이클립스.zip");
// 2. 버퍼 필터 클래스와 결합 (파일로부터 한번에 많이 읽어서 메모리에 보관 / 속도 향상 기능)
BufferedInputStream bIn = new BufferedInputStream(in);
BufferedOutputStream bOut = new BufferedOutputStream(out);
// 3. 파일 읽고 복사 (속도 향상을 확인)
int copyByte = 0 ; //읽고 기록한 크기
int bData; // 1byte씩 저장할 공간
// 3.1 시작 시간
long startTime = System.currentTimeMillis(); //cpu로부터 현재 시간 얻기
while(true){
bData = bIn.read(); //버퍼로부터 1byte씩 읽어들인다.
if(bData == -1)
break;
else {
bOut.write(bData); //버퍼에 1byte씩 저장한다
copyByte++;
}
}
// 3.2 종료 시간
long endTime = System.currentTimeMillis(); //cpu로부터 현재 시간 얻기
// 4. 파일 스트림 닫기
bIn.close();
bOut.close();
// 5. 결과 출력
System.out.println("복사된 바이트 크기 : "+ copyByte);
System.out.println("경과 시간 : " + (endTime - startTime) + " ms"); //ms= 1/1000초
}
}
복사된 바이트 크기 : 400348966
경과 시간 : 10674 ms (약 10초정도)
public class BufferedFileCopy2 {
public static void main(String[] args) throws IOException {
// 1.in/out 스트림 생성
InputStream in = new FileInputStream("eclipse.zip");
OutputStream out= new FileOutputStream("이클립스.zip");
// 2. 버퍼 필터 클래스와 결합 (파일로부터 한번에 많이 읽어서 메모리에 보관 / 속도 향상 기능)
BufferedInputStream bIn = new BufferedInputStream(in);
BufferedOutputStream bOut = new BufferedOutputStream(out);
// 3. 파일 읽고 복사 (속도 향상을 확인)
byte[] buf = new byte[1024*1024];
int copyByte = 0 ; //읽고 기록한 크기
int len; // 버퍼로부터 읽어들인 크기
// 3.1 시작 시간
long startTime = System.currentTimeMillis(); //cpu로부터 현재 시간 얻기
while(true){
len = bIn.read(buf); //버퍼로부터 len만큼 읽어들인다.
if(len == -1)
break;
else {
bOut.write(buf, 0, len); //버퍼에 len만큼 저장한다
copyByte += len;
}
}
// 3.2 종료 시간
long endTime = System.currentTimeMillis(); //cpu로부터 현재 시간 얻기
// 4. 파일 스트림 닫기
bIn.close();
bOut.close();
// 5. 결과 출력
System.out.println("복사된 바이트 크기 : "+ copyByte);
System.out.println("경과 시간 : " + (endTime - startTime) + " ms"); //ms= 1/1000초
}
}
복사된 바이트 크기 : 400348966
경과 시간 : 391 ms - 훨씬 빠른 것을 알 수 있다.
정리
package ex00.fileio.filter;
import java.io.*;
public class DataBufferFilterStream {
public static void main(String[] args) throws IOException {
// 1) 스트림(파일과의 다리역할)
OutputStream out=new FileOutputStream("data.bin");
// 2)버퍼필터 (복사 속도 향상)
BufferedOutputStream bOut= new BufferedOutputStream(out);
// 3) 데이터 필터 (쉽게 변수 쓰기/읽기)
DataOutputStream dOut=new DataOutputStream(bOut); //결국 이것을 통해서 데이터를 주고받을 수 있도록.
// 4) 데이터 저장
dOut.writeInt(275);
dOut.writeDouble(3.14);
dOut.close();
InputStream in=new FileInputStream("data.bin"); // 저장했던 데이터 읽어들인다.
BufferedInputStream bIn = new BufferedInputStream(in);
DataInputStream dIn=new DataInputStream(bIn);
int num = dIn.readInt();
double dNum = dIn.readDouble();
dIn.close();
System.out.println("정수 : " + num);
System.out.println("실수 : " + dNum);
}
}