[I/O] Stream

포키·2023년 1월 16일
0

국비과정

목록 보기
41/73

앞으로 5~6년 후의 목표를 '자체 서버 만들기'로 두기.
서툴더라도 서버를 만들 수 있다면 충분히 능력있는 것.


  • InputStreamreturn = 읽은 결과 기준
  • OutputStreamparameter = 쓸 대상 기준

System.currentTimeMillis() : 시스템 현재 시간 구하는 메서드 (return : long)


Stream

  • java.io
  • 주어진 data를 읽거나 data에 쓰는 기능을 가진 객체 (프로그램과 data 사이를 연결하는 통로?)

    💥💥 주의!!! java 1.8부터 추가된 함수형의 stream과는 다름!!!!!! 💥💥

특징

  1. 방향 (I/O) - Stream은 단일 방향을 가진다. (=입력과 출력 중 하나만 수행한다)
    (프로그램의) data -> 파일, 콘솔 등 : 쓰기(output) = 출력
    파일, 콘솔 등 -> (프로그램의) data : 읽기(input) = 입력
  2. 순차 - 순차적 수행
  3. 이름이 중요!
    클래스 뒷부분을 보면 연산 단위 byte/char와 방향 Input/Output을 알 수 있다.
    클래스 앞부분을 보면 대상 File 혹은 특징 Buffered을 알 수 있다.

종류

  1. byte 단위 연산 (byte 단위 입출력)
  • Input 최상위 클래스 : InputStream - 대표 메서드 read()
  • Output 최상위 클래스 : OutputStream - 대표 메서드 write()
  1. char 단위 연산 (char 단위 입출력)
  • Input 최상위 클래스 : Reader - 대표 메서드 read()
  • Output 최상위 클래스 : Writer - 대표 메서드 write()
  • char 단위 연산의 목적 = '영어 이외의 언어를 처리하기 위해'
    영어 알파벳은 byte 단위 연산으로 충분했지만, 영어 외의 언어는 (ex. 한글) byte 단위로 한 글자를 처리할 수 없는 경우가 발생.
    이로 인해 오류가 생기면서, char 단위 연산 = 글자 단위의 연산이 필요했던 것.
    (char 연산도 기반은 물론 byte 단위 연산이다)
  • 사용 빈도는 압도적으로 byte 단위 >>>> char 단위
    char 단위 연산은 글자로만 구성된 파일(java, txt) 정도이며,
    글자가 아닌 데이터가 포함될 경우는 byte 단위 연산을 사용한다.

ex)
FileOutputStream : 파일을 byte 단위 출력 연산
InputStreamReader : InputStream(byte 단위로 들어온 입력)에 char 단위 입력 연산

메서드

read() : 읽기 메서드 = input 클래스 대표 메서드
write() : 쓰기 메서드 = output 클래스 대표 메서드

flush() : 읽은 데이터를 남김없이 털어내는 메서드. write()와 세트로 사용.

  • 읽기, 쓰기 연산은 느리다. 읽고 쓰는 횟수를 줄이면 성능을 올릴 수 있다.

read(byte[] buffer, int offset, int length)
: inputStream에서 offset(시작점)부터 length(개수)만큼 읽어 buffer에 담는다. (return : 읽은 개수)

write(byte[] buffer, int offset, int length)
: outputStream에서 offset(시작점)부터 length(개수)만큼 buffer에 담아 쓴다. (return : 쓴 개수)

available() : 읽을 수 있는 남은 byte 개수를 반환 (return : int)

기타 메서드 참고

  • 테스트를 통해 성능과 버퍼 크기 사이의 최적점 찾기
    버퍼가 커질수록 읽고 쓰는 속도는 높아지지만, 그만큼 다른 부분에서 느려질 수 있다.
  • 버퍼는 heap 메모리에 저장된다. 지역변수로 만들어 사용이 끝나면 바로 삭제해야 한다.
  • char연산도 같은 방식을 사용할 수 있으나, char연산으로 이용하는 데이터는 보통 크기가 작으므로 굳이 buffer를 사용할 필요가 없다.

close() : 자원해제 메서드 = 모든 Stream 클래스 공통 사용

  • close()의 중요성
    : 자원 관리는 운영체제의 역할, 자원을 사용하겠다 선언하고 (에러 등으로 인해) 해제 선언을 하지 않으면 그 자원을 이후에 사용할 수 없게 됨.
    외부 자원을 사용할 때면 try~ catch문finally를 통해 close() 실행해주기
  • read(), write() : 대상에 따라 읽고 쓰는 방법이 다르므로, 내용이 정해지지 않은 abstract 메서드
  • 대상 data의 next byte를 받아온다. 단 정수 데이터의 대표값은 int이므로 형변환을 줄이기 위해 return에 int를 사용한다. (실제로는 byte = 범위는 0~255) 끝에 도달하면 끝났다는 의미로 -1이 돌아온다.
    (Reads the next byte of data from the input stream. ... Returns : the next byte of data, or -1 if the end of thestream is reached.)
  • 패러미터로 들어온 byte를 출력한다. 단 정수 데이터의 대표값은 int이므로 형변환을 줄이기 위해 parameter로 int를 사용한다. (실제로는 byte = 범위는 0~255)
    (Writes the specified byte to this output stream. ... Parameters: b - the byte.)

System.in / System.out의 의미

  • System.in : 표준입력장치 (static InputStream 객체)
  • System.out : 표준출력장치 (static OutputStream[PrintStream] 객체)
  • ctrl + z : 표준입력장치 입력 중 '입력 끝'을 나타내는 키
  • `\

코드 - OutputStream

  • OutputStream은 대상이 물리적으로 존재하지 않을 경우 알아서 파일을 생성하고 입력함
  • OutputStream(File f, boolean append) : '데이터 추가' 기능 on/off. 기본값 false (=덮어쓰기)
  • <try ~ resource> : 1.7부터 가능. 자원 사용시 권한 해제finally~ close() 코드 생략 가능. (비추천)
package kr.ac.green;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class IOEx2 {
	public static void main(String[] args) {
		FileOutputStream fos = null; 
		// try에서 에러나더라도 finally에서 close()가 실행되어야 하기 때문에 처음에 null로 초기화해둠.
		// 1.7~ <try ~ resource >로 finally close() 생략 가능, 여러 객체 한 번에 닫기 가능
		/*
		 * 	try(
		 * 		FileOutputStream fos1 = new FileOutputStream(f, true),
		 * 		FileOutputStream fos2 = new FileOutputStream(f, true)
		 * 	) {
		 * 		fos.write('A');
		 * 		fos.write('B');
		 * 		fos.write('C');
		 *	}
		 */
		// 1.7부터 사용 가능하고, 닫다가 실패할 경우를 대비할 수 없으며, autoCloseable을 구현하는 객체일 때만 사용 가능
		
		File f = new File("first.txt");
		try {
			fos = new FileOutputStream(f, true);
			// path or file 중 하나를 넣으면 됨
			// 만약 물리적 파일이 없다면, 생성 후 작성함.
			// FileOutputStream에 두번째 패러미터 boolean append에 true를 넣으면 기존 입력값이 저장됨.
			// boolean append의 기본값은 false - append true 해주지 않으면 내용은 덮어쓰기된다. 만약 이미 있는 파일이라면 잘못 덮어쓰기 될 수도!
			// 실행 전 exists()로 확인하고 사용하기
			
			// 물리적으로는 package 아래에 있으나, 
			// first.txt는 상대위치로 입력됨 - 프로젝트 아래라는 현재위치에 작성됨
			fos.write('I');
			fos.write(' ');
			fos.write('a');
			fos.write('m');
			fos.write(' ');
			fos.write('h');
			fos.write('u');
			fos.write('n');
			fos.write('g');
			fos.write('r');
			fos.write('y');
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				fos.close();
			} catch(Exception e) {} // 어떤 에러가 나도 그냥 무시할 때
		}
	}
}

코드 - SimplePad

  • class Document
    : 텍스트 내용을 관장하는 객체 (컴포넌트 x)
  • 메서드
    getDocument() : (return : Document)
    addDocumentListener : Document 변화를 감지하는 리스너 객체
profile
welcome

0개의 댓글