입출력 프로그램

hyunn·2021년 8월 8일
0

Java-basic

목록 보기
23/26
post-thumbnail

I/O

In -> read => InputStream

Out -> write => OutputStream

=> 둘 다 1 byte단위로 읽고 씀

=> 앞으로 읽고 쓰는 과정과 흐름을 빨대로 표현

스트림을 위한 빨대 구하기

  • 클래스로 제공 -> FileInputStream

  • 클래스X 특정 메소드의 리턴타입 -> socket.getInputStream

입출력 프로그램 작성 시 순서와 주의 사항

  1. 빨대꽂기

  2. 읽고쓰기

  3. 빨대뽑기 -> close

    빨대를 뽑지않으면 안됨

    반드시 finally 처리

모든 Stream은 닫아줘야함!!!



In/ Out 이용해 데이터를 주고받는 방법

1. 키보드에서 입력받아서 Data 읽어서 file에 쓰기

​ 키보드 =IN=> data 빨아들임 =OUT=> File에 쓰기


KeyInOut.java 생성

public class KeyInOut {
    public static void main(String[] args) {

        InputStream in = System.in;
        OutputStream out = null;
        //FileOutputStream은 try catch로 묶어줘야함 
        //내부에서 OutputStream 선언하면 밖에서 닫을 수 없음
        //그래서 밖에서 선언하고 try내부에서 new 따로 해주는 것
        
        try {
            out = new FileOutputStream("C:\\zzz\\test.txt");
            //만약 여기서 에러 발생 시 finally에 의해 그냥 스킵됨

            for (int i = 0; i < 10; i++) {
                int data = in.read();  
                //1byte씩의 내용을 읽어들임
                out.write(data);
            }//end for
        } catch (Exception e) {  
            //범용적인 예외캐치위해 그냥 Exception사용
            e.printStackTrace();
        } finally {  
            //Stream은 반드시 finally로 닫아줘야함
            if (out != null) {
                try { out.close(); } catch (Exception e) { }
                //뒤에 catch가 비어있는 이유?
                // -여기선 더이상 개발자가 책임질 부분이 아니기때문 = 예외가 아닌 에러의 영역
                //close를 하고나면 더이상 건드릴 수 있는게 없음
                //예외 = 개발자가 커버 가능한 부분
            }//end if
            if (in != null) {
                try { in.close(); } catch (Exception e) { }
                //close는 반드시 따로따로 만들어줘야함
                //예외는 내려오다가 걸리면 바로 나가지기때문에!
            }//end if
        }//end try
    }
}
image

콘솔에 작성한 내용을 읽어들여서 txt 파일로 저장함

글자가 짤린 이유는 코드에서 1byte씩 잘라서 10번만 읽도록 설계했기때문에 10글자까지만 나오고 잘린것


2. 서로 다른 사람끼리 서버소켓을 사이에 두고 소켓으로 연결

​ 누군가 나에게 보내는 data를 받아서 파일에 쓰기

​ 나 =OUT=> 서버소켓 =IN=> =OUT=> File

3. 채팅시스템

​ 누군가 나에게 메세지를 보내고(=OUT=>) 내가 읽어들임(=IN=>)

​ 그리고 그 메세지를 다시 보내서(=OUT=>) 상대편이 다시 읽어들임(=IN=>)

​ = 채팅시스템



I/O 이용한 파일 복사 프로그램

public class FileFastCopy {
    public static void main(String[] args) {
    
        //입출력에서 가장 중요한 것 = 입출력의 횟수!

        //try with resource -> try(){  }
        //괄호 내에 변수 선언 = 제약조건
        //자동 close해주는 역할
        try( InputStream fin = new FileInputStream("C:\\zzz\\aaa.jpg");
             OutputStream fos = new FileOutputStream("C:\\zzz\\copy22.jpg");
        ) {
            //read -> 현재 읽어들인 data의미
            //read(byte[]) -> 숫자를의미
            byte[] arr = new byte[1024*8];  //8kb

            while(true) {
                int count = fin.read(arr);  //몇 개나 새로운 데이터를 읽었는지

                System.out.println("COUNT : " + count);
                System.out.println(Arrays.toString(arr));

                if (count == -1) { break; }
                fos.write(arr, 0, count);
            }//while end

        } catch (Exception e) {
            e.printStackTrace();  
            //예외출력 맨날 sout(e)하던거 대체
        }//catch end
    }
}

이전에 만든 FileCopy.java와 비교

public class FileCopy2 {
    //bad code
    public static void main(String[] args) throws IOException {
        File file = new File("C:\\zzz\\aaa.jpg");

        Path filePath = file.toPath();

        OutputStream out = new FileOutputStream("C:\\zzz\\copy.jpg");

        Files.copy(filePath, out);
    }
}

일일히 조금씩 옮기는게 아닌 한번에 빨아들여 뱉어내는 형식으로 훨씬 빠르고 간단한 코드가됨

image

aaa.jpg =fin=> [ | | | | | | | ] byte[] buffer =fos=> copy22.jpg

cursor = 현재위치

읽어들인 만큼 커서 이동

fin.read(buffer) -> int count 몇개나 새로운 data 읽어들였는지 -> fos.write(buffer, 0, count) 맨 앞부터 count만큼 써

만약 원래 내용이 있는 파일이었으면? 원래의 내용물은 덮어씌워짐



file buffer 읽기 테스트

13 byte 짜리 sample.txt 작성

abcdefghijklm

FileFastCopy2.java 작성

public class FileFastCopy2 {
    public static void main(String[] args) {

        try( InputStream fin = new FileInputStream("C:\\zzz\\sample.txt");
             OutputStream fos = new FileOutputStream("C:\\zzz\\copy.txt");
        ) {
            //버퍼 (arr)의 크기 지정 = 5
            byte[] arr = new byte[5];
            while(true) {
                int count = fin.read(arr);
                if (count == -1) { break; }
                fos.write(arr);
            }//while end

        } catch (Exception e) {
            e.printStackTrace();
        }//catch end
    }
}

결과

image

왜??4?

원래 파일에 빨대 꽂힘 =fin=> buffer (= data 복사해 옮겨놓는 계란판)

abcde fghij klm =fin=> buffer [ | | | | ] (5칸짜리 버퍼)

[ | | | | ] a b c d e count = 5

[ | | | | ] f g h i j count = 5

[ | | | | ] k l m i j count = 3

새로 읽어들인 data는 기존의 data를 덮어씌워버리지만 아닌 부분은 data가 그대로 남아있게됨

for.write(buffer) => 현재 버퍼 내에 있는 data 전부 다 읽어버림

=> 그래서 새로 읽어들인 data의 count는 13이지만 copy 파일에 써진 data는 15byte가 되는것

그래서 새로 읽어들인 파일만 쓸 수 있도록 코드를 아래처럼 수정해주는 것

fos.write(buffer, 0, count)



0개의 댓글

관련 채용 정보