JAVA - I/O

이상해씨·2022년 7월 31일
0

웹 풀스택(JAVA)

목록 보기
15/54

✔I/O

데이터의 입력(input)과 출력(output)

  • 한쪽에서 주고 한쪽에서 받는 구조.
  • 입력과 출력의 끝단 : 노드(Node)
    • 두 노드를 연결하고 데이터를 전송할 수 있는 개념 : 스트림(Stream)
      • 이전에 작성한 스트림과는 다른 개념
      • 데이터를 받아 들이는 경우 : 입력 스트림(Input Stream)
      • 데이터를 내보내는 경우 : 출력 스트림(Output Stream)
    • 단방향 통신. (입력과 출력을 같이 처리할 수 없음.)

1. 노드 스트림

  • 노드 스트림(Node Stream) : 노드에 연결되는 스트림. 직접적으로 데이터를 입력 받거나, 출력하는 역할.
데이터 타입에 따라
byte or char
방향에 따라
입력 또는 출력
노드 타입에 따라최종 노드 스트림
XXStream(Byte)InputStream키보드InputStream
OutputStream모니터OutputStream
InputStream
OutputStream
FileFileInputStream,FileOutputStream
ByteArrayByteArrayInputStream, ByteArrayOutputStream
PipePipeInputStream, PipeOutputStream
XXer(char)Reader키보드Reader
Writer모니터Writer
Reader
Writer
FileFileReader, FileWriter
CharArrayCharArrayReader, CharArrayWriter
StringStringReader, StringWriter
PipePipeReader, PipeWriter
  • InputStream의 주요 메서드
    • read() : 데이터를 byte 단위로 읽음.
      • read() : byte를 읽어 int 반환. 값이 없다면 -1 반환
      • read(byte b[]) : 데이터를 일겅 b를 채우고 바이트의 개수 반환. 값이 없다면 0 반환. b의 크기 즉, buffer만큼 읽음.
      • read(byte b[], int offset, int len) : 최대 len만큼 데이터를 읽어 b의 offset부터 저장 후 읽은 바이트 반환. len+offset은 b의 크기 이하여야 함.
    • close() : 스트림 종료해서 자원 반납.
    • UTF-8에서 한글은 3bytes이므로 기본 read()로 읽을 수 없음.
      - 버퍼를 사용하면 되지만, 버퍼가 작다면 손상 발생 가능.
      - char형을 읽고 쓰는 Reader, Writer 사용하여 해결.

  • Reader의 주요 메서드
    • read() : 데이터를 char 단위로 읽음.
      • read() : char를 읽어 int 반환. 값이 없다면 -1 반환
      • read(char cbuf[]) : 데이터를 읽어 cbuf를 채우고 읽은 문자 개수 반환. 값이 없다면 0 반환.
      • read(char cbuf[], int off, int lne) : 최대 len 만큼 읽어 cbuf의 off부터 저장하고 읽은 문자 개수 반환. len+off는 cbuf의 크기 이하여야 함.
      • read(java.nio.CharBuffer target) : 데이터를 읽어 target에 저장. target이 cbuf 대체.
    • close()
    • Reader는 유니코드에 대해 안전.

  • OutputStream의 주요 메서드
    • write() : 데이터를 byte로 출력.
      • write(int b) : b의 내용 출력.
      • write(byte b[]) : b의 내용 문자열로 변환해 출력.
      • write(byte b[], int off, int len) : b의 off부터 off+len+1만큼을 문자열로 변환해 출력.
    • close() : 스트림 종료. 내부적으로 flush() 호출
    • flush() : 버퍼가 있는 스트림에서 버퍼의 내용 출력 후 비움.

  • Writer의 주요 메서드
    • write() : 데이터를 문자열로 출력.
      • write(int c) : c의 내용 출력.
      • write(char cbuff[]) : cbuf를 문자열로 변환해 출력.
      • write(char cbuff[], int off, int len) : cbuff의 off부터 off+len+1만큼을 문자열로 변환해 출력.
      • write(String str) : str 출력.
      • write(String str, int off, int len) : str의 off부터 off+len+1만큼 출력.
    • append() : 출력 함수.
      • append(CharSequence csq) : csq 출력 후 Writer 반환.
      • append(CharSequence csq, int start, int end) : csq의 start부터 end까지 출력하고 Writer 반환.
    • close() : 스트림 종료. 내부적으로 flush() 호출.
    • flush() : 버퍼가 있는 스트림에서 버퍼의 내용 출력 후 비움.

  • File : 가장 기본적인 입출력 장치 중 하나로 파일과 디렉터리를 다루는 클래스.(내용에는 관여하지 못함!! 입력, 출력 스트림을 이용한다.)
    • 주요 메서드가 너무 많아 링크로 대체..헤헤
    • 파일 경로 입력시 운영체제마다 구분자가 다르므로 File.separator를 사용하여 대체할 수 있다.
    • File XXStream : byte로 데이터 처리.
      • FileInputStream(String name | File file) : 문자열, 파일 객체를 매개변수로 입력 스트림 생성.
      • FileOutputStream([String name | File file], boolean append) : 입력 스트림과 동일하게 출력 스트림 생성. append 옵션으로 기존 파일 뒤에 쓰거나 새로 생성할 수 있음.
      • buffer의 크기를 조절해 속도를 조절할 수 있다.(일반적으로 버퍼가 클수록 속도가 빨라짐. 하지만 메모리가 많이 필요해짐.)
    • File XXXer : 문자(char)로 데이터 처리.
      • FileReader : 파일 읽기
      • FileWriter : 파일 쓰기

2. 보조 스트림

  • 보조 스트림(Filter Stream, Processing Stream) : 다른 스트림에 부가적인 기능을 제공하는 스트림.
    • 스트림 체이닝(Stream Chaining) : 필요에 따라 보조 스트림을 연결하여 사용 가능.

진행 과정

  • 노드(입력) -> 노드 스트림 -> 보조 스트림 -> 프로그램 -> 보조 스트림 -> 노드 스트림 -> 노드(출력)
  • 보조 스트림의 종류

    기능byte 기반char 기반
    byte 스트림 -> char 스트림 변환InputStreamReader
    OutputStreamReader
    버퍼링을 통한 속도 향상BufferedInputStreamBufferedReader
    BufferedOutputStreamBufferedWriter
    객체 전송ObjectInputStream
    ObjectOutputStream
  • 생성 : 이전 스트림을 생성자의 파라미터에 연결.
    • 노드 스트림은 언제나 필수.
// 보조n(...(보조1(노드))) : 나중에 사용하는 스트림으로 이전 스트림 결과를 감싸는 형식.
new BufferedReader(new InputStreamReader(System.in))
  • 종료 : 보조 스트림의 close() 호출시 노드 스트림의 close()까지 호출.
  • 사용할 스트림의 결정 과정
    1. 노드가 무엇인가?
    2. 타입은 문자열인가? 바이트인가?
    3. 방향이 무엇인가? (노드 스트림 구성.)
    4. 추가 기능이 필요한가? (보조 스트림 구성.)
  • 노드 구성 예시
    • 파일 이동 : File -> byte -> (읽기/쓰기) -> File(Input/Output)Stream -> Buffered(Input/Output)Stream
    • 키보드에서 유니코드 읽기 : Keyboard -> byte -> 읽기 -> System.in(InputStream) -> InputStreamReader -> BufferedReader
    • 객체 파일로 저장 : File -> byte -> 쓰기 -> FileOutputStream -> ObjectOutputStream

3. 보조 스트림 활용(1)

  • InputStreamReader & OutputStreamWriter
    • byte 기반 스트림을 char 기반으로 변경해주는 스트림.
      • 문자열 관리를 위해서는 char 단위가 유리.
      • 키보드 입력(byte stream)을 처리하는 경우 주로 사용.
    • 변환시 encoding 지정 가능
    • InputStreamReader(InputStream in, [String charsetName/Charset cs]) : 캐릭터 셋 생략시 기본(설정값), 입력시 해당 캐릭터 셋으로 InputStreamReader 생성.
    • OutputStreamWriter(OutputStream out, [String charsetName/Charset cs]) : 캐릭터 셋 생략시 기본(설정값), 입력시 해당 캐릭터 셋으로 OutputStreamWriter 생성.

  • Buffered 계열
    • 일반적인 버퍼의 역할 : 데이터를 한 곳에서 다른 한 곳으로 전송하는 동안 일시적으로 그 데이터를 보관하는 메모리의 영역. 버퍼에 저장하여 필요한 처리를 거친 뒤 전송. [전송 -> 처리]로 진행할 경우 성능 문제가 발생하여 버퍼로 데이터를 임시 저장한 뒤 처리 진행.
    • Buffered 계열 스트림 : 스트림의 입/출력 효율을 높이기 위해 버퍼를 사용.
    • BufferedInputStream(InputStream in), BufferedOutputStream(OutputStream out) : byte 계열
      • 기본적으로 8192 bytes 크기의 버퍼 사용.
      • size를 매개변수로 전달하면 해당 size만큼의 버퍼 사용.
    • BufferedReader(Reader in), BufferedWriter(Writer out) : 문자 계열
      - 기본적으로 8192 char (16384 bytes) 크기의 버퍼 사용.
      - size를 매개변수로 전달하면 해당 size만큼의 버퍼 사용.
      - BufferedReader-readLine() : 줄 단위로 데이터를 읽어 들임.(개행 문자로 줄 인식.)

  • Scanner와 BufferedReader
    • char 형태의 데이터를 읽기위한 클래스들
    • Scanner : 자동 형변환을 지원하는 등 간편함. 속도가 느림.
    • BufferedReader : 직접 스트림을 구성해야 하는 등 번거로움. 속도가 빠름.

4. 보조 스트림 활용(2) - 객체 직렬화

  • 객체 직렬화(Serialization) : 객체를 파일 등에 저장하거나 네트워크로 전송하기 위해 연속적인 데이터로 변환하는 것.(반대의 경우 역직렬화(Deserialization))

  • serialVersionUID : 클래스의 변경 여부를 파악하기 위한 유일키.
    • 직렬화, 역질화의 UID가 다를 경우 예외 발생.
    • UID 미설정시 컴파일러가 자동 생성
      • 멤버 변경(추가 혹은 삭제)으로 인한 컴파일 시마다 변경 -> InvalidClassException 초래.
    • 직렬화되는 객체에 대해 serialVersionUID 설정 권장.
  • 직렬화되기 위한 조건
    1. Serializable 인터페이스 구현.
    2. 클래스의 모든 멤버가 Serializable 인터페이스를 구현해야함.
    3. 직렬화에서 제외하려는 멤버는 transient 선언.
  • 객체 저장
    • ObjectOutputStream(OutputStream out) : out을 이용해 ObjectOutputStream 객체 생성.
    • writeObject(Object obj) : obj 직렬화 후 출력(저장).
// Test 객체 생성 후  target 파일에 저장.
ClassName Test = new ClassName();
File target = new File();
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(target))){
	oos.writeObject(Test);
}catch(IOException e){}
  • 객체 읽기
    • ObjectInputStream(InputStream int) : int을 이용해 ObjectInputStream 객체 생성.
    • writeObject() : 직렬화된 데이터를 역직렬화하여 Object 반환.
// target 파일을 읽어 Object 입력.
File target = new File();
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(target))){
	Object readed = ois.readObject();
    if (readed != null && readed instanceof Person){
    	Person casted = (Person) readed;
    }
}catch(IOException e){}
profile
후라이드 치킨

0개의 댓글