5/10, 5/13, 5/16 입출력(I/O)

박세현·2024년 5월 13일

JAVA

목록 보기
21/22
post-thumbnail

입출력(I/O)

  • java.io 패키지
  • Input/Output -> 입력/출력 -> 입출력


1. 입출력이란?

  • Input/Output 입력 / 출력
  • 컴퓨터 내부 또는 외부와 프로그램간의 데이터를 주고받는 것



2. 스트림(stream)

  • 데이터가 이동하는 통로
  • 입력 통로(입력 스트림)
  • 출력 통로(출력 스트림)



1) 바이트기반 스트림(1바이트)

: 데이터 크기가 바이트 단위 / 1바이트씩 읽어오는 스트림



① 입력 스트림 - InputStream

  • InputStream : 추상 클래스, 가장 상위 클래스
    -> 추상메서드 : int read()
    • abstract int read()
      : 1byte를 읽고, 이를 0에서 255 사이의 정수로 반환
      : 읽은 바이트를 반환함 = 읽은 데이터를 반환
    • int read(byte[] b)
      : 읽은바이트 수를 리턴
      : 실제 읽은 데이터는 바이트 배열 안에 저장
    • int read(byte[] b, int off, int len)
    • abstract int read(), int read(byte[] b), int read(byte[] b) : 스트림의 끝에 도달하면 -1을 반환

자바문서_InputStream
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/io/InputStream.html



- 기반 스트림

  • 직접 데이터에 접근해서 1바이트 씩 읽어오는 스트림(int read())

  • FileInputStream (InputStream의 하위 클래스)
    • int read()
      : 1byte를 읽고 이를 0에서 255 사이의 정수로 반환
      : 스트림의 끝에 도달하면 -1을 반환
    • int read(byte[] b)
      : 최대 b.length(배열길이) 바이트를 읽으며, 실제로 읽은 바이트 수를 반환
      : 실제 읽은 데이터는 바이트 배열 안에 저장
      : 스트림의 끝에 도달하면 -1을 반환
    • int available()
      : 입력 스트림에서 읽을 수 있는 바이트 수를 반환 = 파일의 현재 위치부터 끝까지 읽을 수 있는 바이트 수를 나타냄
      • 반환값
        • 읽을 수 있는 바이트 수 : 현재 입력 스트림에서 읽을 수 있는 바이트 수를 정수로 반환
        • 0 : 읽을 수 있는 바이트가 없거나 스트림의 끝에 도달한 경우 0을 반환
  • ByteArrayInputStream (InputStream의 하위 클래스)

참고)자바문서_FileInputStream
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/io/FileInputStream.html

참고)
Unsigned : 양의 정수
Unsigned Byte : 0 ~ 255


입력 스크림의 끝에 도달한 경우 반환값이 -1 / 바이트 범위에서 부족 -> 더 큰 자료형
int read()


예시) FileInputStream_read()

package exam02;

import java.io.FileInputStream;
import java.io.IOException;

public class Ex01 {
    public static void main(String[] args) {
        try(FileInputStream fis = new FileInputStream("test1.txt")){
            int ch = fis.read(); // 1바이트 -> A 아스키코드 : 65
            System.out.println((char)ch);

            ch = fis.read(); // 1바이트
            System.out.println((char)ch);

            ch = fis.read(); // 1바이트
            System.out.println((char)ch);

            ch = fis.read(); // 1바이트
            System.out.println((char)ch);

            ch = fis.read(); // 1바이트
            System.out.println((char)ch);

            ch = fis.read(); // -1 : 파일을 전부 다 읽음
            System.out.println(ch);
            System.out.println((char)ch);


        }catch(IOException e){
            e.printStackTrace();
        };
    }
}

ㄴ 파일 포인터 : 현재 파일 위치 -> read()할때 마다 1바이트씩 움직임
ㄴ 알파벳 한개 = 1바이트
ㄴ read() : 1바이트 씩 읽는 메서드



예시2-1) FileInputStream_int read()



예시2-2) FileInputStream_int read(byte[] b)



예시2-2-1) FileInputStream_int read(byte[] b)

ㄴ data : 실제 데이터가 저장된 곳
ㄴ num : 실제로 읽은 바이트 수 ex) 1024, 1024, 1024 ...



예시) FileInputStream_available()



예시) 버퍼
한글자씩 읽어오는거 비효율적이지 않닝
한꺼번에 가져오자

ㄴ 효율성을 위해 기존꺼를 지우지 않아 반복됨
ㄴ 예시2-2) FileInputStream_int read(byte[] b) 참조하기

ㄴ 근데 이렇게 많이 안쓴다
-> BufferedInputStream 요거를 많이 씀



- 보조 스트림

  • 다른 입력스트림에 추가적인 기능을 부여
  • 생성자 매개변수 : InputStream / 데코레이터 패턴
    -> 기반스트림인지 보조스트림인지 구분하는 법

  • FilterInputStream(InputStream의 하위 클래스) : 보조스트림의 체계를 정리하기 위한 클래스 : 매개변수가 InputStream
    • BufferedInputStream(FilterInputStream의 하위 클래스) : 버퍼 기능 추가 - 기본 버퍼 8kb
    • DataInputStream(FilterInputStream의 하위 클래스) : 기본 자료형으로 데이터를 읽을 수 있는 기능 추가
      - 한가지 자료형으로 사용하는 것
      - 끝가지 다 읽은 후에 읽으면 EOFException(EOF) 발생

  • ObjectInputStream : 객체 형태로 변환하여 읽어 오는 기능 추가

참고)
InputStream System.in : 표준 입력(1바이트 단위)



참고) 데코레이터 패턴

class BufferedInputStream extends InputStream {
	
	private InputStream in;
	
	public BufferedInputStream(InputStream in) {  
		this.in = in;
	}
	
	
	// read 메서드의 기능은 추가적인 기능과 함께 다른 스트림의 기능을 대신 수행
	public int read() {
		
		// 버퍼 기능에 대한 코드 ...  // 추가 기능 
		
		int byte = in.read(); // 다른 스트림의 읽기 기능을 대신 수행 
		
		// 버퍼 기능에 대한 코드 ... // 추가 기능
		
		return byte;
	}
}
  • AOP(Aspect Oriented Programming) : 관점 지향 프로그래밍
  • 관점 : 공통 관심사



② 출력 스트림 - OutputStream

  • OutputStream : 추상 클래스 , 가장 상위 클래스
    -> 추상메서드 : void write(int...)

    • write() : 버퍼에 바이트를 저장 = 파일에 데이터를 작성 ≠ 파일에 저장❌

      • void write(int b) : 1바이트를 출력
        -> int = 4byte 에서 끝에 1byte만 출력한다

      • int = 4byte

      • byte : -128 ~ 127

      • ex) void write(int b) : 1바이트를 출력

        OuteputStream os = new FileOutputStream("파일경로")
         byte a = 200;
         os.write(a); 
        // 200은 1byte의 범위를 넘어가기 때문에 온전한 200이 출력되지 않는다
        // int = 

    • flush() : 버퍼를 비우면서 데이터를 파일에 찐 저장⭕

      • write()만 하면 파일에 데이터가 찐 저장 되지 않음
    • close() : file을 열었으면 무조건 닫아야함

      • close() 하지 않으면 불완전한 파일임
      • close() 메서드가 실행되면 close()가 버퍼에있는 데이터를 다 flush()하고 file을 닫음

참고) 자바문서_OutputStream
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/io/OutputStream.html



- 기반스트림

  • 직접 데이터에 접근해서 1바이트 씩 출력하는 스트림(void write(int ...))

  • ByteArrayOutputStream
  • FileOutputStream
    • FileOutputStream(String name) ↔ FileOutputStream(String name, boolean append)
      • FileOutputStream(String name)
        파일에 데이터를 추가하는 경우 기존 파일에 덮어씌우면서 데이터 추가
        = 기존파일 버리고 새로 파일 생성
      • FileOutputStream(String name, boolean append) :
        • true : 기존파일데이터 유지하면서 데이터 추가

Class FileOutputStream
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/io/FileOutputStream.html


예시1) FileOutputStream_ write(int b)_autoClosable❌

ㄴ C드라이브에 Temp라는 파일안에 있는 test1.db파일에 데이터를 저장하겠다
ㄴ test1.db파일이 없으면 생성 / 단, 최소한 C드라이브에 Temp라는 파일은 있어야 함

ㄴ FileNotFiundException 예외처리하라고 오류 뜸
-> try catch로 예외처리 할거임

os.write(a); : test1.db 파일에 바이트 타입 a 데이터를 저장하겠다
-> IOException 예외 발생
-> 예외처리 try-catch로 해줄 거임

예외처리방법 1) ⭕



예외처리방법 2) ❌

-> 에러 뜸

ㄴ FileNotFiundException이 IOException을 상속받고 있기 때문에 에러 뜸


예외처리방법3) ⭕

ㄴ flush() : 버퍼를 비우면서 데이터를 찐 저장
-> write()만 하면 파일에 데이터가 찐 저장 되지 않음

ㄴ close() : file을 열었으면 무조건 닫아야함
-> close() 하지 않으면 불완전한 파일임
-> close() 메서드가 실행되면 close()가 버퍼에있는 데이터를 다 flush()하고 file을 닫음

ㄴ close()에 finally로 감싼이유
-> file은 열었으면 부조건 close()해줘야 하는데 만약 예외가 발생하면 강제로 catch()구문으로 가버리니까 close()가 실행되지 않을 수 도 있음
-> 그래서 무조건 실행될 수 있도록 finally로 감쌈

ㄴ 근데 위 예시를 보면 os.close()에서 에러 발생함
-> 자바는 블록단위 변수
-> 현재 코드에서 os변수는 try{}안에서만 유효
-> 그럼 어떻게?
-> 밖으로 빼주자 = 블록 범위를 넓혀주자

ㄴ os변수를 밖으로 빼 줌
ㄴ os.close() 에서 예외처리하라고 에러 뜸

ㄴ os.close() 에서 예외처리함

ㄴ 10이라는 1byte가 저장되어 있는 모습



예시1-1) FileOutputStream_ write(int b)_autoClosable⭕

ㄴ try-with-resources 블록에 FileOutputStream을 넣어 자동으로 닫히도록 함
ㄴ 이렇게 하면 자동으로 autoClosable이 구현되어서 안보이지만 close()가 자동으로 실행
ㄴ 예외가 발생하든 안하든 autoClosable이 close() 실행함



예시2) FileOutputStream_void write(byte[] b)



예시3) FileOutputStream_void write(byte[] b, int off, int len)



예시4) FileOutputStream



- 보조스트림

  • 출력 스트림에 추가적인 기능을 제공
  • 생성자 매개변수 : OutputStream
    -> 기반스트림인지 보조스트림인지 구분하는 법

  • FilterOutputStream : 보조스트림의 체계를 정의하기 위한 클래스
    • BufferedOutputStream : 출력 스트림 + 버퍼기능
    • DataOutputStream : 기본 자료형으로 쓰기 기능 제공

  • ObjectOutputStream : 객체 형태로 데이터를 출력하는 기능 추가



2) 문자기반 스트림(2~3바이트)

  • 데이터 크기가 문자 단위(유니코드 - 2, 3 바이트)


① 입력 스트림 - Reader

  • Reader : 추상 클래스

참고) 자바문서_Reader
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/io/Reader.html



- 기반 스트림

  • 데이터에 직접 접근하는 스트림

  • FileReader
  • CharArrayReader
  • StringReader


- 보조 스트림

  • 입력스트림 + 추가 기능

  • 생성자 매개변수 : Reader
    -> 기반스트림인지 보조스트림인지 구분하는 법

  • FilterReader

    • BufferedReader : 버퍼 기능

  • InputStreamReader : 바이트 단위 스트림 -> 문자 단위 스트림으로 변환 기능
    : Reader로 사용이 불가한 InputStream인 경우 변환
    : 생성자 매개변수 String charSetName, Charset cs : 변환하려고 하는 문자표(유니코드...)
    2바이트 유니코드 : ISO8859_1 / EUC-KR, CPC949
    3바이트 유니코드 : UTF-8

    • String getEncoding() : 문자표의 종류



② 출력 스트림 - Writer

  • Writer : 추상 클래스


- 기반 스트림

  • 데이터에 직접 접근하는 스트림

  • FileWriter
  • CharArrayWriter
  • StringWriter


- 보조 스트림

  • 출력스트림 + 추가 기능
  • 생성자 매개변수 : Writer
    -> 기반스트림인지 보조스트림인지 구분하는 법

  • FilterWriter
    • BufferedWriter : 버퍼 기능

  • OutputStreamWriter : 바이트 단위 스트림 -> 문자 단위 스트림으로 변환 기능



3. 표준입출력 : 콘솔에 입력, 출력

  • JVM이 생성해 주는 객체

  • PrintStream : 문자기반스트림, 기반 스트림, 버퍼
    • print(), printf(), println() 편의 메서드 포함
      참고) PrintWriter


1) System.in : InputStream

  • 터미널에서 입력, 바이트 단위 스트림
  • 문자 단위 스트림으로 변경(InoutStreamReader)


2) System.out : PrintStream

  • 문자 단위 출력 스트림
  • print(..), printf(..), println(..) + 버퍼(8kb)


3) System.err : PrintStream

  • 표준 에러 스트림, 글자 색이 빨간색

참고)
PrintWriter : 문자 단위 출력 스트림 + 버퍼(8kb)
print(..), printf(..), println(..)


예시)

ㄴ 글자색이 빨간색으로 출력



예시) setErr(PrintStream err)




4. File

  • 파일, 디렉토리를 파일 객체로 생성해서 관리
  • 파일, 디렉토리에 유용한 기능...
  • 파일구분문자
    • 윈도우즈 : D:\경로명\파일명.확장자 -> \
      -> 지금은 윈도우즈도 / 로 파일구분문자 써도 ㅇㅋ
    • 리눅스(맥) : /home/project/파일명 -> /
  • 환경 변수(OS내에서 사용가능한 변수) 구분문자
    • 윈도우즈 : ;(세미콜론)
    • 리눅스(맥) : :(콜론)
  • 쓰기, 읽기, 실행 권한
    • boolean canRead() : 읽기 권한 여부
    • boolean canWrite() : 쓰기 권한
    • boolean canExecute() : 실행 권한

    • void setReadable(...)
    • void setWritable(...)
    • void setExecutable(...)

    • void setReadOnly(..) : 읽기 전용

    • String getAbsolutePath() : 파일 전체 경로
    • String getCanonicalPath() : 정규화된 파일 경로(상대경로 -> 전체경로변경)

    • String getName() : 파일명
    • String getPath() : 파일경로

참고) 자바문서_java.io.File
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/io/File.html


예시)



예시) 빈 파일 만들기



예시) 디렉토리 생성



예시) 디렉토리가 없는 경우 디렉토리 생성



예시) 하위폴더들 생성

예시) 판별

ㄴ 디렉토리인지안닌지
ㄴ 파일인지아닌지

참고) is : ~인지아닌지



예시) 임시파일 생성



예시) 임시파일 삭제

ㄴ 5초 뒤 삭제



예시) 파일경로

ㄴ String getAbsolutePath(); : 파일 전체 경로
ㄴ String getCanonicalPath(); : 정규화된 파일 경로(상대경로 -> 전체경로변경)



예시) getName(), getPath()




5. 직렬화(Serialization)

  • 객체에 저장된 데이터를 스트림에 쓰기(write)위해 연속적인(serial) 데이터로 변환하는 것을 말한다.
  • 직렬화 -> 데이터 노출 -> 위험한 작업 -> 의사 표현(Serialable 인터페이스 추가 -> 진행 하겠음을 표현)
  • Serialization 인터페이스 구현(구현내용x - 마커 인터페이스)
    -> 변환 값 : 다시 객체로 복구할 때 필요한 항목 직렬화
    -> 객체마다 변경될 수 있는 값(인스턴스 변수)


1) ObjectInputStream

  • 객체 형태로 읽어 오는 것
    -> 객체를 복구 (새로 생성 <- 객체마다 다른 데이터(인스턴스 변수 값)를 주입)
    -> 저장한 순서대로 객체를 복구 가능 -> 불편함
    -> 객체 저장 시 컬렉션 프레임워크의 List, Set, Map을 활용하면 편하다
  • 보조 스트림
    -> 기반스트림이 필요하다


2) ObjectOutputStream

  • 객체 형태로 저장
    • 객체를 복구할 때 필요한 항목 저장
    • 복구가 필요한 데이터?
      -> 객체마다 다른 데이터 = 인스턴스 변수 : 직렬화
  • 보조 스트림
    -> 기반스트림이 필요하다
profile
귤귤

0개의 댓글