지난 시간 스트림에 대해 배웠다.

 

스트림 : 데이터를 처리하기 위한 연산 방식의 표준화

중간연산자 : map(), filter(), distinct(). forEach()

최종연산자 : sum(), average(), max(), min()

정렬 : .sorted()

 

람다와 스트림은 자바를 하는 동안 아주 중요하다.

 

IO 입출력과 스트림

 

다른 공간에 있는 데이터를 서로 주고 받는다.

어제 배웠던 스트림과는 다른 의미의 스트림

여기서 스트림이란, 데이터를 운반하는데 사용되는 연결 통로

// Input(입력) / Output (출력)
// 컴퓨터 내부 또는 외부의 장치간 데이터 교환

// Stream : 데이터가 전송되는 통로
// 통로의 In, Out은 상대적 개념

// 바이트 기반 스트림 (사진, 동영상, 음성)
// 문자 기반 스트림
// 보조 스트림 (효율적으로 데이터를 주고 받기 위해 제공)
// 보조 스트림은 바이트 기반 보조 스트림과 문자 기반 보조 스트림이 있다.
// FIFO 구조

 

🍀 바이트 기반 스트림
// InputStream, OutputStream -> 인터페이스
// 상속받은 표준화된 기능들 오버라이딩

// InputStream
read(), read(byte[], b), read(byte[] b, int off, int len) 세 가지 형태로 데이터를 읽어올 수 있다.

// OutputStream
write(int b), write(byte[] b), write(byte[] b, int off, int len)
세 가지 형태로 데이터를 받아올 수 있다.

// 바이트 기반 보조 스트림
BufferedInputStream, BufferedOutputStream DataInputStream, DataOutputStream

 

🍀 문자 기반 스트림
// Reader, Writer -> 인터페이스

// Reader
// 데이터를 읽어온다
read(), read(char[] c), read(char[] c, int off, int len)

// Writer
writer(int c), writer(char[] c), writer(char[] c, int off, int len)
writer(String srt), writer(String str, int off, int len)


🍀 문자 기반 보조 스트림
BufferedReader, BufferWriter

 

 

배열을 이용해 입출력

toByteArray() : 스트림된 내용을 byte 배열로 반환 해 준다.

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.Arrays;

public class IOTest1 {

	public static void main(String[] args) {
		byte[] inSrc = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
		byte[] outSrc = null;

		ByteArrayInputStream input = null;
		ByteArrayOutputStream output = null;

		input = new ByteArrayInputStream(inSrc); // 어느 대상으로부터 Input을 할지 대상을 정해야 한다
		output = new ByteArrayOutputStream();

		// input 에서 데이터를 받아 저장하는 곳
		// 읽어오는 데이터는 1byte, int의 기본단위는 4byte
		// 데이터의 크기와는 상관없이 읽어온다
		int data = 0;

		// -1 이 아닐 때까지 데이터를 읽어온다
		while ((data = input.read()) != -1) {
			output.write(data);
		}

		outSrc = output.toByteArray(); // 스트림된 내용을 byte 배열로 반환 해 준다.

		System.out.println("input source : " + Arrays.toString(inSrc)); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
		System.out.println("output source : " + Arrays.toString(outSrc)); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

	}

}

한번에 1byte 만 불러오기 때문에 성능이 떨어진다.

 

한번에 많은 양의 데이터를 보낼 수 있도록 처리할 수 있다.

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.Arrays;

public class IOTest2 {

	public static void main(String[] args) {
		byte[] inSrc = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
		byte[] outSrc = null;
		byte[] temp = new byte[10];

		ByteArrayInputStream input = null;
		ByteArrayOutputStream output = null;

		input = new ByteArrayInputStream(inSrc); // 어느 대상으로부터 Input을 할지 대상을 정해야 한다
		output = new ByteArrayOutputStream();

		// 읽어온 데이터를 배열 temp에 담는다
		input.read(temp, 0, temp.length);
		output.write(temp, 5, 5); // temp[5]부터 5개의 데이터를 write 한다.

		outSrc = output.toByteArray(); // 스트림된 내용을 byte 배열로 반환 해 준다.

		System.out.println("input source : " + Arrays.toString(inSrc)); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
		System.out.println("temp : " + Arrays.toString(temp)); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
		System.out.println("output source : " + Arrays.toString(outSrc)); // [5, 6, 7, 8, 9]
	}

}

10byte를 읽어오고, output에 출력할 때는 temp[5] 부터 5byte을 출력했다.

= 필요한만큼 input 하고, 필요한만큼 output 한다

 

read()가 값을 읽어오는 방식

available()은 블락킹(blocking)없이 읽어올 수 잇는 바이트의 수를 반환한다.

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;

import javax.print.event.PrintEvent;

public class IOTest3 {

	public static void main(String[] args) {
		byte[] inSrc = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
		byte[] outSrc = null;
		byte[] temp = new byte[4];

		ByteArrayInputStream input = null;
		ByteArrayOutputStream output = null;

		input = new ByteArrayInputStream(inSrc);
		output = new ByteArrayOutputStream();
		
		System.out.println("input source : " + Arrays.toString(inSrc));
		
		// IOException 타입으로 예외처리
		// 4바이트씩 순서대로 읽어오는 구조가 아니기 때문에 available()을 이용해 다음 4바이트의 시작 위치를 찾아준다.
		try {
			while(input.available() > 0) {
				input.read(temp); // 읽어온 값의 갯수 ( 4 -> 4 -> 2 )
				output.write(temp);
				
				outSrc = output.toByteArray();
				printArrays(temp, outSrc);
				
			}
			
		}catch (IOException e) {}
	}
	
	static void printArrays(byte[] temp, byte[] outSrc) {
		System.out.println("temp : " + Arrays.toString(temp));
		System.out.println("Output Source : " + Arrays.toString(outSrc));
	}

}

 

출력 :

input source : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
temp : [0, 1, 2, 3]
Output Source : [0, 1, 2, 3]
temp : [4, 5, 6, 7]
Output Source : [0, 1, 2, 3, 4, 5, 6, 7]
temp : [8, 9, 6, 7]
Output Source : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 6, 7]

Output Source : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 6, 7] 에 보면 6, 7이 함께 읽힌다.

이를 해결하기 위해 코드를 수정해보았다.

 

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;

public class IOTest4 {

	public static void main(String[] args) {
		byte[] inSrc = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
		byte[] outSrc = null;
		byte[] temp = new byte[4];

		ByteArrayInputStream input = null;
		ByteArrayOutputStream output = null;

		input = new ByteArrayInputStream(inSrc);
		output = new ByteArrayOutputStream();

		try {
			while (input.available() > 0) {
				int len = input.read(temp); // 출력을 조절
				output.write(temp, 0, len); // 원하는 위치만큼 write
			}

		} catch (IOException e) {
		}

		outSrc = output.toByteArray();

		System.out.println("Input Source : " + Arrays.toString(inSrc));
		System.out.println("temp : " + Arrays.toString(temp)); // [8, 9, 6, 7]
		System.out.println("Output Source : " + Arrays.toString(outSrc)); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

	}
}

 

출력 :

Input Source : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
temp : [8, 9, 6, 7]
Output Source : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

read() 메소드 자체는 바뀌지 않았지만 Output 의 값은 9까지 들어갔다.

 

 

파일기반의 IO 스트림

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

public class FileViewer {

	public static void main(String[] args) {

		// FileInputStream , FileOutputStream

		// 무조건 예외처리를 해야한다.
		try {
			FileInputStream fis = new FileInputStream("src/FileViewer.java");

			int data = 0;

			while ((data = fis.read()) != -1) {
				char c = (char) data;
				System.out.print(c);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

}

 

결과 :

	public static void main(String[] args) {

		// FileInputStream , FileOutputStream

		// 무조건 예외처리를 해야한다.
		try {
			FileInputStream fis = new FileInputStream("src/FileViewer.java");

			int data = 0;

			while ((data = fis.read()) != -1) {
				char c = (char) data;
				System.out.print(c);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

}

한글 주석이 특수문자 처리되어 결과가 나온다.

복붙이 바로 이런 스트림을 이용한 것..!

 

 

파일 자체를 복사해 새로 생성하는 프로그램

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

public class FileCopy {

	public static void main(String[] args) {
		
		try {
			FileInputStream fis = new FileInputStream("src/FileCopy.java");
			FileOutputStream fos = new FileOutputStream("FileCopy.bak");
			
			int data = 0;
			
			while((data = fis.read()) != -1) {
				fos.write(data);
			}
			
			// 스트림을 사용할 때는 항상 닫아줘야 한다.
			// 서버부하를 막기 위함.
			fis.close();

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

	}

}

실행 후 새로고침을 하면 복사한 파일이 생긴다.

 

 

 

보조스트림 연결해보기

main 스트림을 도와주는 역할을 한다.

보조스트림 자체로 구현 X

 

BufferedInputStream, BufferedOutputStream 보조스트림

import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class BufferedOutputTest {

	public static void main(String[] args) {
		try {

			FileOutputStream fos = new FileOutputStream("123.txt");

			BufferedOutputStream bos = new BufferedOutputStream(fos, 5); // 생성자에 메인스트림을 연결해야 한다.

			for (int i = '1'; i <= '9'; i++) {
				bos.write(i);
			}

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

	}

}

 

출력 : (파일에 출력됨)

12345

5바이트씩 가지고 와야 하는데 나머지는 5바이트를 채우지 못해 가지고 오지 않았다.

→ 버퍼에 데이터가 다 차지 않더라도 flush()를 이용해 데이터를 밀어줄 수 있다.

 

수정된 코드 :

import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class BufferedOutputTest {

	public static void main(String[] args) {
		try {

			FileOutputStream fos = new FileOutputStream("123.txt");

			BufferedOutputStream bos = new BufferedOutputStream(fos, 5); // 생성자에 메인스트림을 연결해야 한다.

			for (int i = '1'; i <= '9'; i++) {
				bos.write(i);
			}
			
			bos.flush();
			// 닫아주는 순서는 역순
			bos.close();
			fos.close();

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

	}

}

 

출력 : (파일에 출력됨)

123456789

→ 보조스트림을 닫아주는 것 만으로도 동작한다.

  		// bos.flush();
			// 닫아주는 순서는 역순
			bos.close();
			// fos.close();

 

 

 

DataInputStream, DataOutputStream 보조스트림

8가지 기본 자료형의 단위로 읽고, 쓰기 가능

Output에서 write한 순서대로 read 해야한다

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

public class DataInputStreamTest {

	public static void main(String[] args) {
		
		// DataInputStrem, DataOutputStream
		// 8가지 기본 자료형의 단위로 읽고, 쓰기 가능
		// write한 순서대로 read 해야한다
		
		try {
			
			FileInputStream fis = new FileInputStream("sample.data");
			DataInputStream dis = new DataInputStream(fis);
			
			System.out.println(dis.readInt());
			System.out.println(dis.readFloat());
			System.out.println(dis.readBoolean());
			
			dis.close();
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

}

 

결과 :

10
20.0
true

 

import java.io.DataOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class DataOutputStreamTest {

	public static void main(String[] args) {
		
		// DataInputStrem, DataOutputStream
		// 8가지 기본 자료형의 단위로 읽고, 쓰기 가능
	
        try {
			
			FileOutputStream fos = new FileOutputStream("sample.data");
			DataOutputStream dos = new DataOutputStream(fos);
			
			dos.writeInt(10);
			dos.writeFloat(20.0f);
			dos.writeBoolean(true);
			
			dos.close();
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		

	}

}

 

 

파일을 읽어와 연산 처리하기

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class DataInputStreamTest2 {

	public static void main(String[] args) {
		
		//int[] score = { 100, 90, 95, 85, 50 };
		int max = Integer.MIN_VALUE;
        int min = Integer.MAX_VALUE;
        int sum = 0;
        int count = 0;
		// 최대값
		// 최소값
		// 합계
		// 평균
		
		try {
			
			FileInputStream fis = new FileInputStream("score.data");
			DataInputStream dis = new DataInputStream(fis);
			
			while(dis.available() > 0) {
				int score = dis.readInt();
                max = Math.max(max, score);
                min = Math.min(min, score);
                sum += score;
                count++;
			}
			
		}catch (FileNotFoundException e) {
			e.printStackTrace();
        } catch (IOException e) {
        	e.printStackTrace();
        }
	
	 double avg = (double) sum / count;


     System.out.println("Max: " + max);
     System.out.println("Min: " + min);
     System.out.println("Sum: " + sum);
     System.out.println("Avg: " + avg);
 }
}

 

결과 :

Max: 100
Min: 50
Sum: 420
Avg: 84.0

 

import java.io.DataOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;


public class DataOutputStreamTest2 {

	public static void main(String[] args) {
		
		int[] score = { 100, 90, 95, 85, 50 };
		
		 try {
				
				FileOutputStream fos = new FileOutputStream("score.data");
				DataOutputStream dos = new DataOutputStream(fos);
				
				for(int i : score) {
					dos.writeInt(i);
				}
				dos.close();
				
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}

	}

 

 

파일을 읽어와 연산 처리하기

  • 배열에 스트림연산을 적용해 풀어보기
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;

public class DataInputStreamTest3 {

	public static void main(String[] args) {
		
		FileInputStream fis = null;
		DataInputStream dis = null;
		ArrayList<Integer> list = new ArrayList<Integer>();
		
		try {
			
			fis = new FileInputStream("score.data");
			dis = new DataInputStream(fis);
			
			while(true) {
				list.add(dis.readInt());
			}
			
			
		} catch (EOFException e) {
			System.out.println("파일 읽기 완료");
        } catch (FileNotFoundException e) {
        	e.printStackTrace();
	    } catch (IOException e) {
        	e.printStackTrace();
        }
		
		System.out.println(list);
		
		// 배열의 데이터를 스트림을 이용해 int형의 일차원 배열 만들기
		int[] arr = list.stream().mapToInt(i -> i).toArray();
		
		int max = Arrays.stream(arr).max().getAsInt();
		int min = Arrays.stream(arr).min().getAsInt();
		int sum = Arrays.stream(arr).sum();
		double avg = Arrays.stream(arr).average().getAsDouble();
		
		   System.out.println("Max: " + max);
	     System.out.println("Min: " + min);
	     System.out.println("Sum: " + sum);
	     System.out.println("Avg: " + avg);
	
 }
}

결과 :

파일 읽기 완료
[100, 90, 95, 85, 50]
Max: 100
Min: 50
Sum: 420
Avg: 84.0

 

 

 

문자 기반 스트림

Reader, Writer -> 인터페이스

 

 

내일 이어서..

내일까지 자바를 배움.

+ Recent posts