본문 바로가기
카테고리 없음

22-09-19 자바이야기(ft.ITwill 국비지원학원)

by Hunihu 2022. 9. 19.

자바 입출력 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 -> 하드디스크 순서로 데이터가 전달된다.

 

내일 강의에서는 연락처프로그램에서 오늘 배운내용을 어떻게 적용시킬 수 있는지 공부할 예정이다~.

그럼 내일 또 공부하고 글을 올려보겠다~

 

빠잉