Language/JAVA

열아홉번째날[IO기반 입출력 및 네트워킹(1) - IO 패키지 소개 / 입력 스트림 / 출력 스트림 / 콘솔 / 파일 입출력 / 보조 스트림 ]

구일일구 2022. 8. 18. 21:23
반응형

목차

  1. IO 패키지 소개
  2. 입력 스트림과 출력 스트림 : 여기만 잘 해도 앞으로 별 문제X
  3. 콘솔(Console) 입출력
  4. 파일(File) 입출력 
  5. 보조 스트림

IO 패키지 소개

* IO : Input / Output

* 프로그램에서 데이터를 외부에서 읽고, 다시 외부로 출력하는 작업 빈번함

* 자바에서 데이터는 스트림(Stream)을 통해 입출력됨
- 스트림 : 단일 방향으로 연속적으로 흘러가는 것
- 출발지에서 나와 도착지로 들어간다는 개념

* 남의 컴퓨터에서 읽어서, 내 컴퓨터에 씀 // 내 컴퓨터에서 읽어서, 남의 컴퓨터에 씀

 

* Java.io 패키지 : 자바의 기본적인 데이터 입출력 API 제공
- InputStream / OutputStream : 바이트 단위 (1바이트를 읽고 쓰는 애들)
- Reader / Writer : 문자 단위 (2바이트를 읽고 쓰는 애들)
- Buffered : 임시 메모리 저장이기 때문에, 다른 애들보다 성능이 느려짐


입력 스트림과 출력 스트림

* 입력 스트림과 출력 스트림의 개념
- 입력과 출력을 따로따로 하나씩 만들어서 사용해야 함
- 입력스트림 : 프로그램이 데이터를 입력받을 때
- 출력스트림 : 프로그램이 데이터를 보낼 때

 

 

* 바이트 기반 스트림 : 1바이트 읽고 씀 , 많이 사용됨
- 그림, 멀티미디어, 문자 등 모든 종류의 데이터를 받고 보내는 것 가능

* 문자 기반 스트림 : 2바이트 읽고 씀 (char 타입)
-  문자만 받고 보낼 수 있도록 특화


InputStream

* 바이트 기반 입력 스트림의 최상위 클래스

* 추상 클래스 : 상속받아서 만들어야 함

* 읽어 들이는 입력 스트림 : 무언가를 읽는다고 생각해야 함 : 메소드가 read

리턴 타입 메소드 설명
int read() 입력 스트림으로부터 1바이트를 읽고
읽은 바이트를 리턴한다.
int read(byte[] b) 입력 스트림으로부터 읽은 바이트들을
매개값으로 주어진 바이트 배열 b에 저장하고
실제로 읽은 바이트 수를 리턴한다.
int read(byte[] b, int off, int len) 배열의 b[off] 부터, len개까지 저장
void close() 시스템 자원을 반납
입력 스트림을 닫음

 

* read() 메소드

InputStream is = new FileInputStream("/Users/user/Desktop/국비/test.txt");
int readByte;
while((readByte = is.read()) != -1) {...}

* read(byte[] b) 메소드

InputStream is = new FileInputStream("/Users/user/Desktop/국비/test.txt");
int readByteNo;
byte[] readBytes = new byte[100];
while((readByteNo = is.read(readBytes)) != -1) {...}

* read(byte[] b, int off, int len)

InputStream is = new FileInputStream("/Users/user/Desktop/국비/test.txt");
int readByteNo;
byte[] readBytes = new byte[100];
int readByteNo = is.read(readBytes, 0 , 20);	//인덱스 0부터 길이20 
while((readByte = is.read()) != -1) {...}

OutputStream

* 바이트 기반 출력 스트림의 최상위 클래스

* 추상 클래스

* 쓰는 출력 스트림 : 무언가를 쓴다고 생각해야 함 : 메소드가 write

* BufferdOiutputStream : 프로그램에서 읽어들인 내용을 쓰기 위해 '버퍼'라는 메모리 공간에 집어넣고 그게 꽉 차야 화면으로 밀어서 보여줌 , ... 버퍼링을 생각하면 됨 (동영상 버퍼링 : 네트웤이 불안정해도 라는 이유도 있지만, 계속 네트워크를 통해 날라오는 데이터를 받기 때문. 버퍼가 꽉 차야 데이터를 전송해서 내 화면에 영상으로 전송해서 볼 수가 있음) ➡️ 버퍼가 꽉 차지 않았는데도 데이터를 날려보내기 위해 사용하는 것이 flush()가 됨 / 스캐너 객체보다 버퍼 쓰는게 훨 나음 . 성능 면에서.

리턴타입 메소드 설명
void write(int b) 출력 스트림으로 1바이트를 보냄
void write(byte[] b) 출력 스트림에 매개값으로 주어진 바이트 배열 b의  모든 바이트를 보냄
void write(byte[]b, int off, int len) b[off] 부터 len개까지의 바이트를 보냄
void flush() 버퍼에 잔류하는 모든 바이트 출력
void close() 사용한 시스템 자원 반납
출력 스트립 닫음

 


Reader

* input, output이랑 다르게 byte가 아니라 char 로 씀

* 문자 기반 입력 스트림의 최상위 클래스

* 추상 클래스

리턴타입 메소드 설명
int read() 입력 스트림으로부터 한개의 문자 읽고 리턴
int read(char[] cbuf) 읽은 문자들을 매개값으로
주어진 문자 배열 cbuf에 저장
실제로 읽은 문자수 리턴
int read(char[] cbuf, int off, int len) cbuf[off] 부터 len개까지 저장 
실제로 읽은 문자 len개 리턴 
void close() 사용한 시스템 자원 반납
입력 스트림 닫음 

 


Writer

* 문자 기반 출력 스트림의 최상위 클래스

* 추상 클래스

리턴타입 메소드 설명
void write(int c) 매개값으로 주어진 한 문자 보냄
void write(char[] cbuf) 매개값으로 주어진 문자 배열 cbuf의 
모든 문자 보냄
void write(char[] cbuf, int off, int len) cbuf[off]부터 len개까지 문자 보냄
void write(String str) 매개값으로 주어진 모든 문자열 보냄
void write(String str, int off, int len) 매개값으로 주어진 문자열 off번부터 len개까지 문자 보냄 
void flush() 버퍼에 잔류하는 모든 문자열 출력
void close() 사용한 시스템 자원 반납
출력 스트림 닫음

* 거의 다 필요없고 write(String str)을 제일 많이 사용함


* inputstream 의 리더는 아스키 코드로 : 영어만 읽을 수 잇음 

* 뒤의 Reader는 유니코드 값  : 전 세계 언어를 다 쓸 수 있음 


콘솔(Console) 입출력

* 콘솔 : 시스템을 사용하기 위해 키보드로 입력 받고, 화면으로 출력하는 소프트웨어
- Unix, Linux : 터미널
- Windows 운영체제 : 명령 프롬프트
- 이클립스 : Console 뷰

 

* System.in : InputStream의 객체

* System.out : OutputStream 의 객체

* System.err : OutputStream 의 객체


System.in 필드

* InputStream 타입의 입력 스트립 : InputStream 변수 대입 가능

InputStream is = System.in;

* 읽은 byte는 아스키코드(ascii code)

* 아스키코드로부터 문자 변환

* InputStream의 read() 메소드 : 1바이트만 읽기 때문에, 한글과 같은 2바이트는 읽을 수 없음 ➡️ 오류 발생
- 키보드로 입력된 한글을 읽기 위해선 ➡️ read(byte[] b) 또는 read(byte[]b, int off, int len) 사용
➡️ 전체 입력된 내용을 바이트 배열로 받음 ➡️ 배열을 이용해 String 객체 생성

byte[] byteData = new byte[15];
int readByteNo = System.in.read(byteData);

String strData = new String(byteData, 0, readByteNo-2);

System.out 필드

* PrintStream 타입의 출력 스트림 : OutputStream으로 타입 변환 가능

* 아스키 코드를 출력하면 콘솔에는 문자가 출력됨

byte b = 97;
os.write(b)

</>
a

 

* 문자열을 출력하기 위해선, 바이트 배열을 얻어야 함 

String name = "홍길동"
byte[] nameBytes = name.getBytes();
os.write(nameBytes);
os.flush();

 Console 클래스

* 자바6부터 콘솔에서 입력된 문자열을 쉽게 읽을 수 있도록 제공함

* 이클립스에서 System.console()은 null을 리턴 ➡️ 명령 프롬프트에서 실행

 

*Console 클래스 읽기 메소드

리턴타입 메소드 설명
String readLine() 엔터키를 입력하기 전의  모든 문자열 읽음
char[] readPassword() 키보드 입력 문자를 콘솔에 보여주지 않고 문자열 읽음 

Scanner 클래스

* Console 클래스 단점: 콘솔로부터 문자열은 읽을 수 있음 / 기본타입(정수, 실수)는 바로 읽을 수 없음

* Scanner 클래스 : 콘솔로부터 기본 타입의 값을 바로 읽을 수 있음 

* 단점 : 저장되어 있는 타입이 아닌경우 오류 발생 


파일(File) 입출력

File 클래스

* 파일 시스템의 파일을 표현하는 클래스
- 파일 크기, 파일 속성, 파일 이름 등의 정보 제공
- 파일 생성 및 삭제 기능 제공
- 디렉토리 생성, 디렉토리에 존재하는 파일 리스트 얻어내는 기능 제공

 

* 파일 객체 생성

File file = new File("파일경로")

 

* 파일 또는 디렉토리 존재 유무 확인 메소드

boolean isExist = file.exists();

 

* 파일 및 디렉토리 생성 및 삭제 메소드

 

* 파일 및 디렉토리의 정보를 리턴하는 메소드


FileInputStream

* 파일로부터 바이트 단위로 읽어들일 때 사용 
- 그림, 오디오, 비디오, 텍스트 파일 등 모든 종류의 파일을 읽을 수 있음

 

* 객체 생성 방법
- FileInputStream 객체가 생성될 때 파일과 직접 연결
- 만약 파일이 존재하지 않으면 FileNotFoundException 발생 : try-catch문으로 예외 처리

 

* InputStream 하위 클래스 : 사용방법은 InputStream과 동일 


FileOutputStream

* 파일로부터 바이트 단위로 데이터를 저장할 때 사용
- 그림, 오디오, 비디오, 텍스트 파일 등 모든 종류의 파일을 읽을 수 있음

 

* 객체 생성 방법
- 파일이 이미 존재할 경우, 데이터를 출력하게 되면 파일을 덮어쓰게 되는 단점

 

* InputStream 하위 클래스 : 사용방법은 InputStream과 동일 


FileReader

* 텍스트 파일로부터 데이터를 읽어들일 때 사용 : 문자 단위로 읽음
- 텍스트가 아닌 그림, 오디오, 비디오 등의 파일은 읽을 수 없음

 

* 객체 생성 방법
- FileReader 객체가 생성될 때 파일과 직접 연결
- 만약 파일이 존재하지 않으면 FileNotFoundException 발생 : try-catch문으로 예외 처리

FileReader fr = new FileReader("파일경로");

File file = new File("파일경로");
FileReader fr = new FileReader(file);

 

* Reader 하위 클래스 : 사용 방법은 Reader와 동일함 


FileWriter

* 텍스트 파일에 문자 데이터를 저장할 때 사용
- 텍스트가 아닌 그림, 오디오, 비디오 등의 데이터를 파일로 저장 불가함

 

* 객체 생성 방법
- 파일에 이미 존재할 경우, 데이터 출력 : 덮어쓰게 됨
- 기존 파일 끝에 데이터를 추가할 경우

FileWriter fw = new FileWriter("경로", true);
FileWriter fw = new FileWriter(file, true);

 

* Writer 하위 클래스 : 사용 방법은 Writer와 동일함 


보조 스트림

* 읽고 쓰는 또 다른 클래스 라고 생각하기

* 다른 스트림과 연결 되어 여러 가지 편리한 기능을 제공해주는 스트림 
- 문자 변환, 입출력 성능 향상, 기본 데이터 타입 입출력, 객체 입출력 등의 기능을 제공
- 앞에서 만든 입력, 출력 스트림이 있어야 보조 스트림도 사용할 수 있음

* 보조 스트림 생성

보조스트림 변수 = new 보조스트림(연결스트림)

 

*보조 스트림 체인 : 다른 보조 스트림과 연결되어 역할 수행


문자 변환 보조 스트림

* 소스 스트림이 바이트 기반 스트림이지만 데이터가 문자일경우 사용 :  1바이트지만, 2바이트로 바꿔서 출력 할 수 있다

* InputStreamReader

InputStream is = System.in;
InputStreamReader reader = new InputStreamReader(is);
FileInputStream fis = new FileInputStrea("파일경로");
Reader reader = new InputStreamReader(fis);

 

* OutputStreamReader

OutputStream is = System.out;
OutputStreamWriter reader = new OutputStreamWriter(is);
FileOutputStream fos = new FileOutputStrea("파일경로");
Writer writer = new OutputStreamReader(fos);

 


성능 향상 보조 스트림

* 입출력 성능에 영향을 미치는 것
- 하드디스크 : CD 같은 디스크 여러개를 집어넣고 저장 ➡️ SSD로 바꾸면 성능 향상 
- 느린 네트워크 

 

* 버퍼를 이용한 해결
- 입출력 소스와 직접 작업하지 않고 버퍼(buffer)와 작업 : 실행 성능 향상
- 프로그램은 쓰기 속도 향상
- 버퍼가 꽉 차게 되면 데이터를 한번에 하드 디스크를 보내 출력 횟수를 줄여줌 

 

* BufferedInputStream, BufferedReader

 

* BufferedOutputStream, BufferedWriter


기본 타입 입출력 보조 스트림

* 잘 안씀 귀찬귀찬 

* 바이트 스트림은 바이트 단위로 입출력하기 때문에, 자바 기본 타입 단위로 출력할 수 없음

* 입출력 순서를 맞춰서 사용 

* DataInputStreamr과 DataOutputStream 보조스트림 연결하면 기본 데이터 단위로 입출력 가능

DataInputStream dis = new DataInputStream(바이트입력스트림);
DataOutputStream dos = new DataOutputStream(바이트출력스트림);

 

 

* 메소드


프린터 보조 스트림

* 파일에 타입 상관 없이 사용 가능하기 때문에, 많이 유용함 

PrintStream ps = new PrintStream(바이트출력스트림);
PrintWriter pw = new PrintWriter(문자출력스트림);

 

* printf : 출력하고자 하는 format을 정하고 씀 

 


객체 입출력 보조 스트림

* 객체를 파일 또는 네트워크로 입출력할 수 있는 기능 제공

* 객체 직렬화 : 객체의 데이터(필드값)을 바이트 기반 스트림으로 데이터 변경하는 것 (객체는 문자가 아니기 때문) : 파일에 쓰는 거

* 객체 역직렬화 : 읽어들인 바이트를 객체로 복원하는 것 : 읽어오는 거

* 직렬화가 가능한 클래스 : Serializable 인터페이스를 구현한 클래스만 직렬화 가능 

- transient가 붙은 필드는 제외

- private 필드를 포함한 모든 필드를 바이트로 변환 가능 

 

serialVersionUID 필드

* 직렬화된 객체를 역직렬화 할 땐 직렬화했을 때와 같은 클래스 사용

* 클래스 이름이 같아도, 클래스 내용이 변경된 경우 역직렬화 실패

* serialVersionUID 
- 같은 클래스임을 알려주는 식별자 역할
- Serializable 인터페이스 구현 : 컴파일 시 자동적으로 serialVersionUID 정적 필드 추가 
- 재컴파일하면 serialVersionUID의 값 변경됨!

* 수정이 있다면, 명시적으로 serialVersionUID 선언해야 함

static final long serialVersionUID = 정수값;

 

wirteObject()와 readObject() 메소드

* writeObject(ObjectOutputStream out)
- 직렬화 직전 자동 호출 
- 추가 직렬화할 내용 작성 가능 

*readObject( )
- 역직렬화 직전 자동 호출 
- 추가 역직렬화 내용 작성 가능 

* 추가 직렬화 및 역직렬화 필요한 경우 : 부모가 serializable 구현X, 자식만 serializable 구현한 경우
- 부모 필드는 직렬화에서 제외됨
- writeObject()에서 부모 필드 직렬화 필요
- readObject()에서 부모 필드 역직렬화 필요
- 부모 클래스가 Serializable 구현하도록 하는게 가장 쉬운 방법 

반응형