23. 입출력 스트림 (InputStream, OutputStream) [ JAVA ]

duck-ach·2022년 8월 15일
2

JAVA

목록 보기
23/27
post-thumbnail

스트림(Stream)

스트림(Stream) 이란, '데이터의 흐름'을 의미한다.

  • 프로그램은 외부에서 데이터를 읽거나 외부로 데이터를 출력하는 작업이 빈번하게 일어나는데, 이때 데이터는 어떠한 통로를 통해서 데이터가 이동된다.
    이 통로를 Stream 이라고 한다.
  • 다양한 데이터 소스(Collection, Array 등)를 표준화된 방법으로 다루기 위한 것(그 전까지는 List, Set, Map 등의 사용방법이 서로 달랐다.)

자바에는 이러한 기능을 수행하기 위해 InputStream과 OutputStream이 존재하며, 단일 방향으로 연속적으로 흘러간다.

Java.io 패키지의 주요 클래스설명
File파일 시스템의 파일 정보를 얻기 위한 클래스
Console콘솔로부터 문자를 입출력하기 위한 클래스
InputStream/OutputStreambyte(바이트) 단위 입출력을 위한 최상위 스트림 클래스
FileInputStream / FileOutputStream
DataInputStream / DataOutputStream
ObjectInputStream / ObjectOutputStreambyte(바이트) 단위 입출력을 위한 하위 스트림 클래스
PrintStream
BufferedInputStream / BufferedOutputStream
Reader / Writer문자 단위 입출력을 위한 최상위 입출력 스트림 클래스
FileReader / FileWriter
InputStreamReader / OutputStreamWriter문자 단위 입출력을 위한 하위 스트림 클래스
PrintWriter
BufferedReader / BufferedWriter
  • 바이트단위 입출력 스트림 : 그림, 멀티미디어, 문자 등 모든 종류의 데이터들을 주고받을 수 있다.
  • 문자단위 입출력 스트림 : 오로직 문자만 주고받을 수 있게 특화되어 있다.

🍒 InputStream

바이트 기반 입력 스트림의 최상위 추상 클래스이다.

  • 모든 바이트 기반 입력 스트림은 이 클래스를 상속 받는다.
  • 파일 데이터를 읽거나 네트워크 소켓을 통해 데이터를 읽거나 키보드에서 입력한 데이터를 읽을 때 사용한다.
  • InputStream은 읽기에 대한 다양한 추상 메소드들을 정의해 두어 사용할 수 있다.
  • InputStream의 추상메소드를 오버라이딩하여 목적에 따라 데이터를 입력 받을 수 있다.
Class NameType객체 생성Method
InputStreambyteInputStream in = System.in;read()
InputStreamReadercharInputStreamReader reader = new inputStreamReader(in);read()
BufferedReaderStringBufferedReader br = new BufferedReader(reader);readLine()

주요 메소드

메소드(Method)설명
int available()현재 읽을 수 있는 바이트 수를 반환한다.
void close()현재 열려있는 InputStream을 닫는다.
void mark(int readlimit)InputStream에서 현재의 위치를 표시해준다.
boolean markSupported()해당 InputStream에서 mark()로 지정된 지점이 있는지에 대한 여부를 확인한다.
abstract int read()InputStream에서 한 바이트를 읽어서 int값으로 반환한다.
int read(byte[] b)byte[] b만큼의 데이터를 읽어서 b에 저장하고 읽은 바이트 수를 반환한다.
int read(byte[]b, int off, int len)len만큼 읽어서 byte[] b의 off위치에 저장하고 읽은 바이트 수를 반환한다.
void reset()mark()를 마지막으로 호출한 위치로 이동한다.
long skip(long n)InputStream에서 n바이트만큼 데이터를 스킵하고 바이트 수를 반환한다.

🍒OutputStream

바이트 기반 출력 스트림의 최상위 추상 클래스이다.

  • 모든 바이트 기반 출력 스트림은 이 클래스를 상속 받는다.
  • OutputStream의 추상메소드를 오버라이딩하여 목적에 따라 데이터를 입력 받을 수 있다.
Class NameType객체 생성Method
OutputStreambyteOutputStream out = System.out;write()
OutputStreamReadercharOutputStreamWriter writer = new OutputStreamWriter(out);write()
BufferedWriterStringBufferedWriter bw = new BufferedWriter(writer);write()

주요메소드

메소드(Method)설명
void close()OutputStream을 닫는다.
void flush()버퍼에 남아있는 출력 스트림을 출력한다.
void write(byte[] b)버퍼의 내용을 출력한다.
void write(byte[] b, int off, int len)b배열 안에 있는 시작 off부터 len만큼 출력한다.
abstract void write(int b)정수 b의 하위 1바이트를 출력한다.

🍒 예제

😶 키보드로 입력한 데이터 읽기

java.util.Scanner 보다 성능이 훨씬 좋다.

try {
		// System.in : 키보드와 연결된 바이트 스트림
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
			
			System.out.print("입력 >>> ");
			String str = br.readLine();
			System.out.println(str);
			
			br.close();
		} catch(IOException e) {
			e.printStackTrace();
		} 
 	}

😶 FileInputStream을 이용해서 파일 읽어오기

입력 데이터 단위 :

  • 1개 : int
  • 여러개 : byte[]

read(byte[] b)

  • 읽은 내용은 byte배열 b에 저장시킨다.
  • 읽은 바이트 수를 반환한다.
  • 읽은 내용이 없다면 -1을 반환한다.
File file = new File("C:\\storage", "b1.bin");
		FileInputStream fis = null;
        FileOutputStream fos = null;
	try {
    
		// 파일 생성
		fos = new FileOutputStream(file);
        
        // 출력할 데이터 설정
		int c = 'A'; 
			String str = "pple Mange 맛있다.";
			// java.io.Charset
			byte[] b = str.getBytes(StandardCharsets.UTF_8);
		
        // 파일에 정보 생성
        fos.write(c);
		fos.write(b);
        
        // 여기까지 하면 `C:\\storage` 경로의 b1.bin 파일에 `Apple Mango 맛있다.` 메세지가 담긴채로 생성 된다.
        
		// 바이트 입력 스트림 생성
		fis = new FileInputStream(file);
            
		StringBuilder sb = new StringBuilder();
		byte[] b = new byte[5]; // 5바이트씩 읽기 위해서 준비
		int readByte = 0;
            
        // 읽어오기
		while((readByte = fis.read(b)) != -1) { // readByte로 b(5개씩 읽기)를 해서 저장.
			sb.append(new String(b, 0, readByte)); // String객체를 생성하면서 offset과 length지정 String으로는 할 수있음.
		}
        // 문자를 byteStream으로 읽었기 때문에 문제가 발생.
		System.out.println(sb.toString()); // Apple Mange 맛있��.
        
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if(fis != null) fis.close();
                if(fos != null) fos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		} 
        

출력문 : Apple Mange 맛있��.

위의 코드에서 한글이 깨지게 출력되는게 정상이다.
이 문제를 해결하기 위해서는 문자로 바꿔주는 필터를 껴주면 된다. InputStreamReader

😶 InputStreamReader/OutputStreamReader를 이용해서 생성한 파일을 읽어와서 한글이 깨지지 않게 출력하기

파일 생성하기

		// 출력 속도 향상을 위한 BufferedOutputStream , BufferedInputStream
		File file = new File("C:\\storage", "b2.bin");
		BufferedOutputStream bos = null;
		BufferedInputStream bis = null;
        
		try {
        // 파일 생성
			bos = new BufferedOutputStream(new FileOutputStream(file)); 
			
			String str = "안녕하세요 반갑습니다."; 
			byte[] b = str.getBytes("UTF-8");
			
			bos.write(b);
        
        
			
		} catch(IOException e ) {
			e.printStackTrace();
		} finally {
			try {
				if(bos != null) bos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

파일 읽어오기

File file = new File("C:\\storage", "b2.bin");
		FileInputStream fis = null;
		InputStreamReader isr = null;
		
		try {
			fis = new FileInputStream(file);
			isr = new InputStreamReader(fis);
			// 속도 향상을 하고 싶으면 BufferedReader를 끼울 수 있다.
			
			
			StringBuilder sb = new StringBuilder();
			char[] cbuf = new char[5]; // 5글자씩 읽기 위해서
			int readCnt = 0;
			
			while((readCnt = isr.read(cbuf)) != -1) {
				sb.append(cbuf, 0, readCnt);
			}
			
			
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if(isr != null) isr.close();
			} catch(IOException e) {
				e.printStackTrace();
			}
		}

😶 변수를 그대로 출력해주는 DataOutputStream / DataInputStream 을 이용해서 생성한 파일 읽어오기

파일 생성하기

// 변수를 그대로 출력하는 DataOutputStream
		File file = new File("C:\\storage", "b3.dat"); // data저장하고있는 dat타입
		FileOutputStream fos = null;
		DataOutputStream dos = null;
		
		try {
			fos = new FileOutputStream(file);
			dos = new DataOutputStream(fos);
			
			// 출력할 변수
			String name = "에밀리";
			int age = 30;
			double height = 165.5;
			
			// 출력
			dos.writeUTF(name); // "에밀리" 문자 쓰기
			dos.writeInt(age); // 30 나이 쓰기
			dos.writeDouble(height);
			
			
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if(dos != null) dos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

파일 출력하기

// 변수를 그대로 입력 받는 DataInputStream
		
		File file = new File("C:\\storage", "b3.dat");
		FileInputStream fis = null;
		DataInputStream dis = null;
		
		try {
			fis = new FileInputStream(file);
			dis = new DataInputStream(fis);
			
			String name = dis.readUTF();
			int age = dis.readInt();
			double height = dis.readDouble();
			
			System.out.println(name + ", " + age + ", " + height);
			
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if(dis != null) dis.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

출력 : 에밀리, 30, 165.5

😶 객체를 그대로 출력하는 ObjectOutputStream을 이용하여 ArrayList에 담긴 요소 출력하기

파일만들기

// 객체를 그대로 출력하는 ObjectOutputStream(보조스트림)
		
		File file = new File("C:\\storage", "b4.dat");
		FileOutputStream fos = null;
		ObjectOutputStream oos = null;
		
		try {
			// 1. User를 3개 저장한 ArrayList
			List<User> users = Arrays.asList(
					new User(1, "kim", 30),
					new User(2, "lee", 40),
					new User(3, "choi", 50)
			);
			
			// 2. User 1개
			User user = new User(4, "min", 60);
			
			fos = new FileOutputStream(file);
			oos = new ObjectOutputStream(fos);
			
			oos.writeObject(users);
			oos.writeObject(user);
			
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if(oos != null) oos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

파일 출력하기

// 객체를 그대로 입력 받는 ObjectInputStream
		
        File file = new File("C:\\storage", "b4.dat");
		FileInputStream fis = null;
		ObjectInputStream ois = null;
		
		try {
			fis = new FileInputStream(file);
			ois = new ObjectInputStream(fis);
			
			@SuppressWarnings("unchecked")
			List<User> users = (List<User>)ois.readObject();
			User user = (User) ois.readObject(); // classcastException
			
			for(User u : users) {
				System.out.println(u);
			}
			System.out.println(user);
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if(ois != null) ois.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

출력

User [userNo=1, name=kim, age=30]
User [userNo=2, name=lee, age=40]
User [userNo=3, name=choi, age=50]
User [userNo=4, name=min, age=60]
profile
자몽 허니 블랙티와 아메리카노 사이 그 어딘가

0개의 댓글