패키지(3) java.io 의 입출력스트림 <InputStream, OutputStream, Reader, Writer>

Yeppi's 개발 일기·2022년 5월 24일
2

JAVA

목록 보기
25/27
post-thumbnail

1. java.io 패키지

1) 입출력(Input/Output)이란?

입력 스트림

  • 데이터 흐름 ⇒ 단방향
    ex. 물 위→아래처럼)

  • 파이프 개념
    사용자의 입력 데이터를 읽어드리는 통로

  • 어떤 파일에 등록된 데이터/메시지를 입력 스트림으로 읽어들임
    ⇒ 입력데이터(키보드)와 파일 2가지를 동시에 읽어들이려면 입력스트림 2개 필요

  • 데이터 출력은 불가(반대방향임)

출력 스트림

  • 프로그램에서 데이터를 출력하기 위한 연결
    ⇒ 입력 스트림이 2개더라도 출력 스트림은 1개면 됨

👉 데이터/파일→ 입력스트림→ Java App→ 출력스트림→ 모니터



2) 구조

Object

File


InputStream

  • FileInputStream
  • FilterInputStream → BufferedInputStream

OutputStream

  • FileOutputStream
  • FilterOutputStream → BufferedOutputStream, PrintStream

Reader

  • BufferedReader
  • InputStreamReader → FileReader

Writer

  • BufferedWriter
  • OutputStreamWriter → FileWriter
  • PrintWriter

추상 클래스

  • inputStream, OutputStream, Reader, Writer

입력 스트림

  • inputStream
    • 바이트 입력 스트림
    • 바이트단위(8bit)로 데이터 읽어들임
    • 이미지/동영상 ⇒ 문자 깨짐
  • Reader
    • 문자 자체로 데이터 읽어들임
    • 2bytes(16bit) ⇒ 문자 안깨짐
    • FileReader

출력 스트림

  • OutputStream
    • 바이트 단위의 출력 스트림
    • PrintStream만 특이하게 OutputSteam 단어가 안붙어있음 ⇒ 표준 출력 스트림
  • Writer
    • 문자 단위의 출력 스트림 ⇒ 문자 안깨짐
    • FileWriter

필터 스트림

  • Buffered 가 붙은 클래스 = 필터 스트림
    • 필수는 아니지만, 기능 향상 목적으로 사용
    • 입출력 작업의 속도를 조금 더 빠르게 하고 싶을 때



3) 스트림 종류 구분

분류 기준

  • 대상 기준 : 입력 스트림 / 출력 스트림
  • 자료의 종류 : 바이트 스트림 / 문자 스트림
  • 기능 : 기반 스트림 / 보조 스트림

입력 스트림과 출력 스트림

  • 입력 스트림
    대상으로부터 자료를 읽어 들이는 스트림

  • 출력 스트림
    대상으로 자료를 출력하는 스트림

  • 스트림의 종류
종류예시
입력 스트림FileInputStream, FileReader, BufferedInputStream, BufferedReader 등
출력 스트림FileOutputStream, FileWriter, BufferedOutputStream, BufferedWriter 등

바이트 단위 스트림과 문자 단위 스트림

  • 바이트 단위 스트림
    동영상, 음악 파일, 실행 파일등의 자료를 읽고 쓸 때 사용

  • 문자 단위 스트림
    바이트 단위로 자료를 처리하면 문자는 깨짐, 인코딩에 맞게 2바이트 이상으로 처리하도록 구현된 스트림

  • 스트림의 종류
종류예시
바이트 스트림FileInputStream, FileOutputStream, BufferedInputStream, BufferedOutputStream 등
문자 스트림FileReader, FileWriter, BufferedReader, BufferedWriter 등

기반 스트림과 보조 스트림

  • 기반 스트림
    대상에 직접 자료를 읽고 쓰는 기능의 스트림

  • 보조 스트림
    직접 읽고 쓰는 기능은 없이 추가적인 기능을 더해주는 스트림

  • 보조 스트림은 직접 읽고 쓰는 기능은 없으므로
    항상 기반 스트림이나 또 다른 보조 스트림을 생성자의 매개 변수로 포함함

  • 스트림의 종류
종류예시
기반 스트림FileInputStream, FileOutputStream, FileReader, FileWriter 등
보조 스트림InputStreamReader, OutputStreamWriter, BufferedInputStream, BufferedOutputStream 등

→ InputStreamReader : 입력용 바이트스트림을 문자로!



2. 표준 입출력

1) 개념

  • 표준 입출력 장치

    • 표준 입력 장치 → 키보드
    • 표준 출력 장치 → 모니터
  • System 클래스의 멤버변수(in, out) 사용

  • outputStream의 타입은 PrintStream
    ex. PrintStream output = System.out;

  • inputStream의 타입은 InputStream
    ex. InputStream input = System.in;



2) System 클래스의 표준 입출력 멤버

public class System { 
	public static PrintStream out; 
	public static InputStream in; 
	public static PrintStream err; 
}

System.out

  • 표준 출력(모니터) 스트림
  • ex. System.out.println("출력 메세지");

System.in

  • 표준 입력(키보드) 스트림
  • ex. int d = System.in.read() // 한 바이트 읽기

System.err

  • 표준 에러 출력(모니터) 스트림
  • ex. System.err.println("에러 메세지");


📌예시📌

  • System.in,System.out

  • 한글 깨짐 현상

System.out.println("알파벳 하나를 쓰고 [Enter]를 누르세요");
		int i;
		try {
			while((i = System.in.read()) != '\n') { // read() 반환값은 integer
			
				// System.out.println(i);
				System.out.print((char)i);
			}
			
		} catch (IOException e) {
			e.printStackTrace();
		}

출력결과

알파벳 하나를 쓰고 [Enter]를 누르세요
안녕하세요
??@$%*
  • 보조스트림으로 감싸서 해결
    • InputStreamReader
    • 보조스트림으로 감싸면 한글이 처리됨
System.out.println("알파벳 하나를 쓰고 [Enter]를 누르세요");
		int i;
		try {
			
			InputStreamReader irs = new InputStreamReader(System.in); // 보조스트림으로 byte를 문자로
			while((i = irs.read()) != '\n') { 
				System.out.print((char)i);	
			}
			
		} catch (IOException e) {
			e.printStackTrace();
		}

출력결과

알파벳 하나를 쓰고 [Enter]를 누르세요
안녕하세요
안녕하세요


3. 파일 입출력

👉 파일 입력 처리

1) InputStream

바이트 단위 입력 스트림, 최상위 추상 클래스

하위 클래스

스트림 클래스설명
FileInputStream파일에서 바이트 단위로 자료를 읽습니다.
ByteArrayInputStreambyte 배열 메모리에서 바이트 단위로 자료를 읽습니다.
FilterInputStream기반 스트림에서 자료를 읽을 때 추가 기능을 제공하는 보조 스트림의 상위 클래스

주요 메서드

메서드설명
int read()입력 스트림으로부터 한 바이트의 자료를 읽습니다. 읽은 자료의 바이트 수를 반환합니다.
int read(byte b[])입력 스트림으로 부터 b[] 크기의 자료를 b[]에 읽습니다. 읽은 자료의 바이트 수를 반환합니다.
int read(byte b[], int off, int len)입력 스트림으로 부터 b[] 크기의 자료를 b[]의 off변수 위치부터 저장하며 len 만큼 읽습니다. 읽은 자료의 바이트 수를 반환합니다.
void close()입력 스트림과 연결된 대상 리소스를 닫습니다.


📌 한글 깨짐 📌

  • data.txt
안녕 난 Yeppi
  • main
// 특정 파일과 연결된 입력스트림 생성
FileInputStream file = new FileInputStream("./data.txt");

int data = 0;
// 더 이상 읽을 데이터가 없을 때까지 데이터를 읽고 출력하는 작업 반복
while ((data = file.read()) != -1) {
	System.out.print((char) data);
}

// 입력 스트림 종료
file.close();

출력결과

  • 한글이 깨진다. . .
  • 안깨지려면? FileReader 를 사용해야 함
??!@?# Yeppi


📌 byte 자료 읽기 📌

파일에서 한 바이트씩 자료 읽기

  • input.txt
ABC
  • main
			fis = new FileInputStream("input.txt");
			System.out.println((char)fis.read()); 
			System.out.println((char)fis.read()); 
			System.out.println((char)fis.read());

출력결과

A
B
C

파일의 끝까지 한 바이트씩 자료 읽기

  • input.txt
ABC
  • main
		int i;
		try(FileInputStream fis = new FileInputStream("input.txt")) {
			
			while((i=fis.read()) != -1) {
				System.out.println((char)i);
			}
			
		} catch (IOException e) {
			System.out.println(e);
		}

출력결과

A
B
C


📌 byte 배열 자료 읽기 📌

파일에서 바이트 배열로 한꺼번에 자료 읽기

  • 배열에 남아 있는 자료가 있을 수 있음에 유의
  • input2.txt
ABCDEFGHIJKLMNOPQRSTUVWXYZ
  • main
int i;
		try(FileInputStream fis = new FileInputStream("input2.txt")) {
			
			byte[] bs = new byte[10];
			
			// byte 수를 반환
			while( (i = fis.read(bs)) != -1 ) {
				for(int ch : bs) {
					System.out.print((char)ch);
				}
				System.out.println(" : " + i + "바이트 읽음"); // byte 개수
			}
			
		} catch (IOException e) {
			System.out.println(e);
		}

출력결과

  • 마지막 QRST은 남아있는 자료
ABCDEFGHIJ : 10바이트 읽음
KLMNOPQRST : 10바이트 읽음
UVWXYZQRST : 6바이트 읽음

남아있는 자료(가비지) 없애기

  • 향상된 for문 말고, 원하는 배열까지만 출력하도록 변경
  • input2.txt
ABCDEFGHIJKLMNOPQRSTUVWXYZ
  • main
		int i;
		try(FileInputStream fis = new FileInputStream("input2.txt")) {
			
			byte[] bs = new byte[10];
			
			// byte 수를 반환
			while( (i = fis.read(bs)) != -1 ) {
				for(int j = 0; j < i; j++) {
					System.out.print((char)bs[j]); // 읽은 자료만 반환
				}
				System.out.println(" : " + i + "바이트 읽음"); // byte 개수
			}
			
		} catch (IOException e) {
			System.out.println(e);
		}

출력결과

ABCDEFGHIJ : 10바이트 읽음
KLMNOPQRST : 10바이트 읽음
UVWXYZ : 6바이트 읽음


2) FileReader

문자 단위 입력 스트림, 최상위 추상 클래스

하위 클래스

클래스설명
FileReader파일에서 문자 단위로 읽는 스트림 클래스입니다.
InputStreamReader바이트 단위로 읽은 자료를 문자로 변환해주는 보조 스트림 클래스 입니다.
BufferedReader문자로 읽을 때 배열을 제공하여 한꺼번에 읽을 수 있는 기능을 제공하는 보조 스트림입니다.

주요 메서드

메서드설명
int read()파일로부터 한 문자를 읽습니다. 읽은 문자를 반환합니다.
int read(char[] buf)파일로부터 buf 배열에 문자를 읽습니다.
int read(char[] buf, int off, int len)파일로부터 buf 배열의 off 위치로부터 len 개수만큼의 문자를 읽습니다.
void close()입력 스트림과 연결된 대상 리소스를 닫습니다.


📌 한글 깨짐 해결 📌

  • data.txt
안녕 난 Yeppi
  • main
// 특정 파일과 연결된 입력스트림 생성
FileReader  file = new FileReader ("./data.txt");

int data = 0;
// 더 이상 읽을 데이터가 없을 때까지 데이터를 읽고 출력하는 작업 반복
while ((data = reader.read()) != -1) {
	System.out.print((char) data);
}

// 입력 스트림 종료
reader.close();

출력결과

  • 한글 안깨짐
안녕 난 Yeppi


👉 파일 출력 처리

1) OutputStream

바이트 단위 출력 스트림, 최상위 추상 클래스

하위 클래스

스트림 클래스설명
FileOutputStream파일에서 바이트 단위로 자료를 씁니다.
ByteArrayOutputStreambyte 배열 메모리에서 바이트 단위로 자료를 씁니다.
FilterOutputStream기반 스트림에서 자료를 쓸 때 추가 기능을 제공하는 보조 스트림의 상위 클래스

주요 메서드

메서드설명
int write()한 바이트를 출력합니다.
int write(byte b[])b[] 크기의 자료를 출력합니다.
int write(byte b[], int off, int len)b[] 배열에 있는 자료의 off 위치부터 len 개수만큼 자료를 출력합니다.
void flush()출력을 위해 잠시 자료가 머무르는 출력 버퍼를 강제로 비워 자료를 출력합니다.
void close()출력 스트림과 연결된 대상 리소스를 닫습니다. 자동으로 출력 버퍼가 비워집니다.


📌 파일에 한 바이트씩 쓰기 📌

  • 파일이 없다면 파일을 자동으로 만들어줌
try(FileOutputStream fos = new FileOutputStream("output.txt")) { // 파일 자동 생성
			fos.write(65); // A 입력
			fos.write(66); // B 입력
			fos.write(67); // C 입력
		
		} catch(IOException e) {
			System.out.println(e);
		}
		System.out.println("end");
  • 파일에 써지는 내용
ABC

📌 배열을 한꺼번에 파일에 쓰기 📌

  • byte[] 배열에 A-Z 까지 넣고 배열을 한꺼번에 파일에 쓰기
FileOutputStream fos = new FileOutputStream("output2.txt");
		
		try(fos) {
			byte[] bs = new byte[26];
			byte data = 65;
			for(int i = 0; i < bs.length; i++) {
				bs[i] = data++;
			}
			fos.write(bs);
		
		} catch(IOException e) {
			System.out.println(e);
		}
		System.out.println("end");
  • 파일에 써지는 내용
ABCDEFGHIJKLMNOPQRSTUVWXYZ

📌 배열 특정 위치부터 파일에 쓰기 📌

  • byte[] 배열의 특정 위치에서 부터 정해진 길이 만큼 쓰기
		FileOutputStream fos = new FileOutputStream("output3.txt");
		
		try(fos) {
			byte[] bs = new byte[26];
			byte data = 65;
			for(int i = 0; i < bs.length; i++) {
				bs[i] = data++;
			}
			fos.write(bs, 2, 10); // buffer의 Offset 2, C부터 출력
		
		} catch(IOException e) {
			System.out.println(e);
		}
		System.out.println("end");
  • 파일에 써지는 내용
CDEFGHIJK

  • 위 코드를 다시 실행하면, overwriting 해서 출력 결과가 같지만
    FileOutputStream fos = new FileOutputStream("output3.txt", true);
    하면 덧붙여서 데이터가 추가됨

  • CDEFGHIJK 가 반복되어 추가

  • 파일에 써지는 내용

CDEFGHIJKCDEFGHIJK


2) FileWriter

문자 단위 출력 스트림, 최상위 추상 클래스

하위 클래스

클래스설명
FileWriter파일에서 문자 단위로 출력하는 스트림 클래스입니다.
OutputStreamWriter바이트 단위의 자료를 문자로 변환해 출력해주는 보조 스트림 클래스 입니다.
BufferedWriter문자로 쓸 때 배열을 제공하여 한꺼번에 쓸 수 있는 기능을 제공하는 보조 스트림입니다.

주요 메서드

메서드설명
int write(int c)한 문자를 파일에 합니다.
int write(char[] buf)문자 배열 buf의 내용을 출력합니다.
int write(char[] buf, int off, int len)문자 배열 buf의 off위치에서부터 len 개수의 문자를 출력합니다.
int write(String str)문자열 str을 출력합니다.
int write(String str, int off, int len)문자열 str의 off번째 문자로부터 len 개수만큼 출력합니다.
int flush()출력하기 전에 자료가 있는 공간(출력 버퍼)을 비워 출력하도록 합니다
void close()스트림과 연결된 리소스를 닫습니다. 출력 버퍼도 비워집니다.


📌 한글 깨짐 해결 📌

// 특정 파일과 연결된 출력스트림 생성
FileWriter writer = new FileWriter("./data.txt");

// byte 
writer.write(65);
writer.write("\n");

// 한글 
writer.write("예");
writer.write('삐');

// 문자열(String)
writer.write("예삐 기술 블로그 경 축 \n");

// 문자 하나 출력
writer.write('A' + " \n");   

char buf[] = {'B','C','D','E','F','G'};
// 문자 배열 출력
writer.write(buf); 
writer.write("\n");

// 문자 배열의 일부 출력
writer.write(buf, 1, 2); 
writer.write("\n");

// 숫자를 그대로 출력
writer.write("65");  

// 출력 스트림 종료
writer.close();
  • 파일에 써지는 내용
A
예삐예삐 기술 블로그 경 축 
A 
BCDEFG
CD
65


🧐flush()close()🧐

  • output 에 있는 메서드

flush()

  • 네트워크의 소켓 등에서 사용
  • 출력 버퍼를 비울때

close()

  • close() 메서드 내부에서 flush()가 호출
  • close() 메서드가 호출되면? 출력 버퍼가 비워짐




4. 필터 스트림

파일로부터 데이터 읽고 쓸 때, 성능 향상을 위한 버퍼를 사용

1) BufferedReader

  • 데이터를 한번에 읽고 출력
  • 속도가 훨씬 빠름
  • FileReader 를 통해 데이터를 읽는 경우
    메모리 상에 버퍼 생성하여 버퍼 단위로 데이터 읽을 때 사용

  • 기본 생성자
    new char[8192] 크기의 문자 버퍼
    생성자로 변경 가능

👉 BufferedReaderFileReader는 무조건 결합해서 사용한다고 생각하기
👉 속도 빠르기 때문


📌 소요 시간 📌

  • System.currentTimeMillis();
    • 시간 정보를 long 타입으로 호출 → 엄청 긴 정수 리턴
    • 해당 파일을 while 문이 돌아가는데 얼마나 걸렸는지 구할 수 있음
// 특정 파일과 연결된 스트림 생성 
FileReader reader = new FileReader("./src/buffer.java");
BufferedReader buffReader = new BufferedReader(reader);

int data = 0;
// 더 이상 읽을 데이터가 없을 때까지 데이터 읽고 출력하기를 반복
// 시작 시간
long start = System.currentTimeMillis();
while ((data = buffReader.read()) != -1) {
	System.out.print((char)data);
}
// 종료 시간
long end = System.currentTimeMillis();

// 스트림 종료
reader.close();
buffReader.close();

System.out.println("소요 시간 -> " + (end - start) + "(ms)초");

출력 결과

public class buffer {

}
소요 시간 -> 1(ms)초

📌 소켓 활용 📌

  • socket의 getInputStream() 을 얻어오고
    InputStreamReader() 형태로 감싼 다음
    BufferReader() 도 추가로 감싸면?

  • 한글로 소켓 보내기 가능

  • 보조스트림은 계속해서 감쌀 수 있음
    마지막 스트림이 최종 스트림으로(기반 스트림)

		Socket socket = new Socket();
        
		// 한글로 소켓을 보낼 수 있음
		BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		br.readLine(); // BufferedReader만 있음, readLine() 한 줄씩 읽기


2) BufferedWriter

  • 데이터를 한 번에 씀
  • 속도 빠름
  • Reader 와 특징이 동일
FileWriter writer = new FileWriter("./a.txt");
BufferedWriter buffWriter = new BufferedWriter(writer);

자세한 예제는
BufferedReader 와 함께 아래 예제에서 살펴보자



📌 최종 정리 예시📌

  • FileReader, BufferedReader, FileWriter, BufferedWriter 사용
  • a.txt 파일을 읽어들인 후, b.txt 파일에 출력
  • a.txt
10,20,30
11,22,33
  • main
FileReader reader = new FileReader("./a.txt");
BufferedReader buffReader = new BufferedReader(reader);

FileWriter writer = new FileWriter("./b.txt");
BufferedWriter buffWriter = new BufferedWriter(writer);

String data = null;
int totalCount = 0;

while ((data = buffReader.readLine()) != null) {
	String[] scoreList = data.split(",");
	int sum = 0;
	for(String score : scoreList) {
		sum += Integer.parseInt(score);
		totalCount++;
	}
	buffWriter.write(data + ",\t 총점 : " + sum + "\n");
}
buffWriter.write("시험에 응시자 : " + totalCount + "명");
buffWriter.flush();

reader.close();
buffReader.close();		

writer.close();
buffReader.close();
  • b.txt
10,20,30,	 총점 = 60
11,22,33,	 총점 = 66
시험에 응시한 학생 수 : 6
profile
imaginative and free developer. 백엔드 / UX / DATA / 기획에 관심있지만 고양이는 없는 예비 개발자👋

0개의 댓글