본문 바로가기

BackEnd/Java

[java] 이것이 자바다 ch18 데이터 입출력 1 (Writer, Reader)

728x90
반응형

1. 입력 스트림과 출력 스트림

   ▷ 프로그램을 기준으로 데이터가 들어오면 입력 스트림, 데이터가 나가면 출력 스트림

   ▷ 프로그램이 다른 프로그램과 데이터를 교환하려면 양쪽 모두 입력 스트림과 출력 스트림이 필요

 

   ▷ 바이트 스트림 : 그림, 멀티미디어, 문자 등 모든 종류의 데이터를 입출력할 때 사용

   ▷ 문자 스트림 : 문자만 입출력할 때 사용

   ▷ 자바는 데이터 입출력과 관련된 라이브러리를 java.io 패키지에서 제공

 

◎ 스트림 입출력

NO 구분 바이트 스트림 문자 스트림
입력 스트림 출력 스트림 입력 스트림 출력스트림
1 최상위클래스 InputStream OutputStream Reader Writer
2 하위 클래스
(예)
XXXInputStream
(FileInputStream)
XXXOutputStream
(FileOutputStream)
XXXReader
(FileWriter)
XXXWriter
(FileWriter)

 

   ▷ 바이트 입출력 스트림의 최상위 클래스는 InputStream과 OutputStream

   ▷ 문자 입출력 스트림의 최상위 클래스는 Reader와 Writer

 


스트림이란 단방향으로 데이터가 흐르는 것을 말합니다.

  

◎ 스트림 예시

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class WriteExample {

	public static void main(String[] args) {
		try {
			OutputStream os = new FileOutputStream("C:/Temp/test1.db");
			
			byte a = 10;
			byte b = 20;
			byte c = 30;
			
			os.write(a);		// 1byte씩 출력
			os.write(b);
			os.write(c);
			
			// 버퍼를 비워둠
			os.flush();
			
			// 사용하는 메모리를 더이상 사용하지 않음(메모리 해제)
			// 메모리를 닫지 않으면 초기화 되지 않고 남습니다.
			os.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

// C드라이버의 Temp 폴더에 test1.db 파일이 생성됩니다.
// 해당 내용은 깨지기 때문에 변환이 따로 필요합니다.
// 모든 데이터 형태가 outputstream 형태로 저장 가능합니다.


write를 사용하면 새로운 폴더를 생성하면서 해당 폴더에 값을 넣어줍니다.
겉으로 보기에는 눈에 보이는 출력값이 없기때문에 컴퓨터에 입력한다고 생각할수도 있지만
실제로는 컴퓨터에서 출력되는 것입니다.

 

 

2. 바이트 출력 스트림

◎ OutputStream

   ▷ OutputStream은 바이트 출력 스트림의 최상위 클래스로 추상 클래스

   ▷ 모든 바이트 출력 스트림 클래스는 이 OutputStream 클래스를 상속받아서 만들어집니다.

   ▷ OutputStream 클래스에는 모든 바이트 출력 스트림이 기본적으로 가져야할 메소드가 정의됩니다.

 

NO 리턴 타입 메소드 설명
1 void write(int b) 1byte를 출력
2 void write(byte[] b) 매개값으로 주어진 배열 b의 모든 바이트를 출력
3 void write(byte[] b, int off, int len) 매개값으로 주어진 배열 b[off]부터 len개의 바이트를 출력
4 void flush() 출력 버퍼에 잔류하는 모든 바이트를 출력
5 void close() 출력 스트림을 닫고 사용 메모리 해제

 

◎ 1바이트 출력

   ▷ write(int b) 메소드 : 매개값 int(4byte)에서 끝 1byte만 출력. 매개변수는 int 타입

 

◎ 바이트 배열 출력

   ▷ write(byte[] b) 메소드 : 매개값으로 주어진 배열의 모든 바이트를 출력

   ▷ 배열의 일부분을 출력하려면 write(byte[] b, int off, int len) 메소드를 사용

 

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class WriteExample {

	public static void main(String[] args) {
		try {
			OutputStream os = new FileOutputStream("C:/Temp/test2.db");
			
			byte array[] = {10, 20, 30};
			
			os.write(array);

			
			// 버퍼를 비워둠
			os.flush();
			
			// 사용하는 메모리를 더이상 사용하지 않음(메모리 해제)
			// 메모리를 닫지 않으면 초기화 되지 않고 남습니다.
			os.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

 

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class WriteExample {

	public static void main(String[] args) {
		try {
			OutputStream os = new FileOutputStream("C:/Temp/test3.db");
			
			byte array[] = {10, 20, 30, 40, 50};
			
			// 인덱스 1~3까지만 출력
			os.write(array, 1, 3);

			os.flush();
			os.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

 

3. 바이트 입력 스트림

◎ InputStream

   ▷ InputStream은 바이트 입력 스트림의 최상위 클래스로, 추상 클래스

   ▷ 모든 바이트 입력 스트림은 InputStream 클래스를 상속받아 만들어집니다.

 

   ▷ InputStream 클래스에는 바이트 입력 스트림이 기본적으로 가져야할 메소드가 정의됩니다.

NO 리턴 타입 메소드 설명
1 int read() 1 byte를 읽은 후 읽은 바이트를 리턴
2 int read(byte[] b) 읽은 바이트를 매개값으로 주어진 배열에 저장 후 읽은 바이트 수를 리턴
3 void close() 입력 스트림을 닫고 사용 메모리 해제

 

◎ 1바이트 입력

   ▷ read() 메소드 : 입력 스트림으로부터 1byte를 읽고 int(4byte) 타입으로 리턴.

       리턴된 4byte 중 끝 1byte에만 데이터가 들어 있습니다.

 

   ▷ 더 이상 입력 스트림으로부터 바이트를 읽을 수 없다면 read() 메소드는 -1을 리턴합니다.

       읽을 수 있는 마지막 바이트까지 반복해서 한 바이트씩 읽을 수 있습니다.

 

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

public class ReadExample {
	public static void main(String[] args) {
		try {
			InputStream is = new FileInputStream("C:/Temp/test1.db");
			
			while(true) {
				int data = is.read();
				if(data == -1) break;
				System.out.println(data);
			}
			is.close();
		} catch(FileNotFoundException e) {
			e.printStackTrace();
		} catch(IOException e) {
			e.printStackTrace();
		}
	}
}

//	출력 : 
//	10
//	20
//	30


read()는 1byte 씩 입력을 받으므로 데이터를 하나씩 저장하고 출력합니다.
만약 값이 없으면 -1이 출력됩니다.

 

◎ 바이트 배열로 읽기

   ▷ read(byte[] b) 메소드 : 입력 스트림으로부터 주어진 배열의 길이만큼 바이트를 읽고 배열에 저장한 다음 읽은 바이트 수를 리턴합니다.

   ▷ read(byte[] b)도 입력 스트림으로부터 바이트를 더 이상 읽을 수 없다면 -1을 리턴합니다.

       읽을 수 있는 마지막 바이트까지 반복해서 읽을 수 있습니다.

 

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

public class ReadExample {
	public static void main(String[] args) {
		try {
			InputStream is = new FileInputStream("C:/Temp/test2.db");
			
			byte[] data = new byte[100];
			
			while(true) {
				int num = is.read(data);
				if(num == -1) break;
				
				for(int i=0; i<num; i++) {
					System.out.println(data[i]);					
				}
			}
			is.close();
		} catch(FileNotFoundException e) {
			e.printStackTrace();
		} catch(IOException e) {
			e.printStackTrace();
		}
	}
}

//	출력 : 
//	10
//	20
//	30


read(배열)이면 num의 값은 최대 배열 크기의 길이와 동일합니다.
예를 들어 data[100] 이라면 num은 우선 100이 지정이 되지만 만약 읽을 값이 100보다 작다면 해당 개수만큼 값이 저장됩니다.

 

 

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

public class CopyExample {
	public static void main(String[] args) throws Exception {
		String originalFileName = "C:/Temp/test.jpg";
		String targetFileName = "C:/Temp/test2.jpg";
		
		InputStream is = new FileInputStream(originalFileName);
		OutputStream os = new FileOutputStream(targetFileName);
		
		
		byte[] data = new byte[1024];
		long startTime = System.nanoTime();
		
		while(true) {
			int num = is.read(data);
			if(num == -1) break;
			os.write(data, 0, num);
		}
		long endTime = System.nanoTime();
		
		System.out.println(endTime - startTime);
		
		os.flush();
		os.close();
		is.close();
		
		System.out.println("복사가 잘 되었습니다.");
	}
}

//	1byte : 418250500
//	복사가 잘 되었습니다.

//	1024byte : 546300
//	복사가 잘 되었습니다.


66KB의 사진(test)을 복사해서 test2로 만들어줍니다.
byte[1024]로 지정하면 약 66번 반복을해서 출력시켜줍니다.
byte[1]로 지정하면 약 66000번 반복을해서 출력시켜줍니다.

따라서 1024로 지정을 했을때 1로 지정했을 때보다 훨씬 빠르게 출력되는 것을 확인할 수 있습니다.

하지만 방의 크기가 크다고 무조건 빠른 것은 아니고 최적의 출력을 낼 수 있는 방의 개수가 있습니다.
   → 너무 방의 크기가 크면 누락되는 부분이 발생할 수 있습니다.

Java9 부터는 is.transferTo(os); 를 사용하면 최적화된 시간으로 값을 읽을 수 있습니다.

 

 

4. 문자 입출력 스트림

◎ 문자 출력

   ▷ Writer는 문자 출력 스트림의 최상위 클래스로, 추상 클래스입니다.

      모든 문자 출력 스트림 클래스는 Writer 클래스를 상속받아서 만들어집니다.

   ▷ Writer 클래스에는 모든 문자 출력 스트림이 기본적으로 가져야할 메소드가 정의됩니다.

NO 리턴 타입 메소드  설명
1 void write(int c) 매개값으로 주어진 한 문자를 출력
2 void write(char[] cbuf) 매개값으로 주어진 배열의 모든 문자를 출력
3 void write(char[] cbuf, int off, int len) 매개값으로 주어진 배열에서 cbuf[off]부터 len 개까지의 문자를 출력
4 void write(String str) 매개값으로 주어진 문자열을 출력
5 void write(String str, int off, int len) 매개값으로 주어진 문자열에서 off 순번부터 len개까지의 문자를 출력
6 void flush() 버퍼에 잔류하는 모든 문자를 출력
7 void close() 출력 스트림을 닫고 사용 메모리를 해제

 

import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;

public class WriteExample {

	public static void main(String[] args) {
		try {
			// 문자 기반 출력 스트림 생성
			Writer writer = new FileWriter("C:/Temp/test.txt");
			
			// 1문자씩 출력
			char a = 'A';
			writer.write(a);
			char b = 'B';
			writer.write(b);
			
			// char 배열 출력
			char[] arr = { 'C', 'D', 'E' };
			writer.write(arr);
			
			// 문자열 출력
			writer.write("FGH");
			
			// 버퍼에 잔류하고 있는 문자들을 출력하고, 버퍼를 비움
			writer.flush();
			
			// 출력 스트림을 닫고 메모리 해제
			writer.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

//	txt 파일 내용 : 
//	ABCDEFGH

 

◎ Reader

   ▷ Reader는 문자 입력 스트림의 최상위 클래스로, 추상 클래스입니다.

   ▷ 모든 문자 입력 클래스는 Reader 클래스를 상속받아서 만들어집니다.

   ▷ Reader 클래스에는 문자 입력 스트림이 기본적으로 가져야할 메소드가 정의됩니다.

 

NO 메소드 설명
1 int read() 1개의 문자를 읽고 리턴
2 int read(char[] cbyf) 읽은 문자들을 매개값으로 주어진 문자 배열에 저장하고 읽은 문자 수를 리턴
3 void close() 입력 스트림을 닫고, 사용 메로리 해제

 

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;

public class ReadExample {

	public static void main(String[] args) {
		try {
			Reader reader = null;
			
			// 1문자씩 읽기
			reader = new FileReader("C:/Temp/test.txt");
			while(true) {
				int data = reader.read();
				if(data == -1) break;
				System.out.print((char)data);
			}
			reader.close();
			System.out.println();

			// 문자로 배열 읽기
			reader = new FileReader("C:/Temp/test.txt");
			char[] data = new char[100];
			while(true) {
				int num = reader.read(data);
				if(num == -1) break;
				for(int i=0; i<num; i++) {
					System.out.print(data[i]);					
				}
			}
			reader.close();
			System.out.println();

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

//	출력 : 
//	ABCDEFGH
//	ABCDEFGH

 

입력과 출력에 대해서 시작해보았는데요!

 

실제로 어떻게 적용되는지 알고나니 좀 더 흥미가 생기네요!!

 

좀 더 도전해볼게요~!!!

 

많은 분들의 피드백은 언제나 환영합니다! 많은 댓글 부탁드려요~~

 

728x90
반응형