스트림
- 자바에서의 모든 입출력을 담당
- 일종의 가상 통로
- 입출력 장치는 다양하기 때문에 호환성을 높이기 위해 사용
- 자료를 읽어 들이려는 소스(source)와 자료를 쓰려는 대상(target)에 따른 스트림이 다름
입/출력 스트림
- 스트림은 단뱡향으로 자료가 이동하기에 입/출력을 동시에 할 수 없다.
‼️ InputStream이나 Reader로 끝나는 이름의 클래스는 입력 스트림
- FileInputStream, FileReader, BufferedInputStream, BufferedReader 등
‼️ OutputStream이나 Writer로 끝나는 이름의 클래스는 출력 스트림
- FileOutputStream, FileWriter, BufferedOutputStream, BufferedWriter 등
바이트 단위 스트림과 문자 단위 스트림
- char형은 2바이트이기에 1바이트만 읽으면 한글 같은 문자는 깨짐 이를 위해 별도로 제공
- 읽어 들이는 자료형에 따라 바이트용과 문자용 스트림이 있다.
- Stream으로 끝나는경우 바이트단위 스트림
- Reader나 Writer로 끝나는 경우 문자단위 스트림
기반스트림
- 읽어 들일 곳(소스)이나 써야 할 곳(대상)에서 직접 읽고 쓸 수 있음
- 입출력 대상에 직접 연결되어 생성되는 스트림
보조스트림
- 직접 읽고 쓸 수 없음
- 항상 다른 스트림을 포함하여 생성됨
- 기반스트림과 보조스트림의 구별은 이름만 가지고는 구별하기 어려울 수 있음
- ex)커피로치면 샷이 아닌 설탕시럽, 캬라멜시럽 등 조미하는 역할.
표준 입출력 클래스
- System.out : 표준 출력용
- System.in : 표준 입력용
- System.err : 빨간색으로 오류 메시지를 출력할 때 사용
- 위에 3개지 모두 정적(static) 메소드
System.in
- 바이트 단위로 읽어들이는 InputStream
- 문자에 대한 숫자값을 출력 (형변환이 필요함)
Scanner 클래스
- java.util 패키지에 있는 클래스
- 문자, 정수, 실수 등 다른 자료형도 읽을 수 있음
- 다양한 매개변수로 읽어 올 수 있음
Console 클래스
- System.in을 사용하지 않고 콘솔 내용을 일을 수 있음
- 직접 콘솔 창에서 자료를 입력 받을 때 사용
- 이클립스와는 연동 안됨
InputStream
- 바이트 단위로 읽는 스트림 중 최상위 스트림
- read( )의 반환형이 int인 이유는 읽어들일 자료가 없을 때 -1을 반환하기 위함
FileInputStream
- 파일에서 바이트 단위로 자료를 읽어 들일 때 사용
파일 끝까지 읽기
- i값이 -1이 아닌 동안 read( ) 메소드로 한 바이트를 반복해 읽음
while((i = fis.read()) !=-1){
System.out.println((char)i);
}
int read(byte[ ] b) 메소드
- read( ) 메소드로 한 바이트씩 읽는 것 보다 배열을 사용하여 읽는게 처리 속도가 더 빠름
- 선언한 바이트 배열의 크기만큼 한꺼번에 자료를 읽음
- 읽어들인 자료의 수를 반환함
byte[ ] bs=new byte[10]; //이면 10바이트씩 자료를 읽어들임
- ex) 알파벳 개수를 10개씩 출력시
- 마지막에 6바이트를 읽었지만, 출력값은 QRST가 더 출력됨
- 남은 4개 공간에 기존 자료가 남아 있기 때문
- i개수만큼 출력하도록 코드를 다음과 같이 바꾸면 됨
OutputStream
- 바이트 단위로 쓰는 스트림 중 최상위 스트림
FileOutputStream
- 파일에 바이트 단위 자료를 출력하기 위해 사용하는 스트림
- 생성자 매개변수로 전달한 파일이 경로에 없으면 파일을 새로 생성함
- append 변수 : 기존 파일의 내용이 있더라도 처음부터 쓸지(overwrite), 연결해서 쓸지(append)를 선택
- 스트림 생성자에서 append의 디폴트 값은 false, 기존에 내용 있더라도 새로 씀
write( ) 메소드
- 파일에 숫자를 쓰면 해당하는 아스키 코드 값으로 변환됨
- 기존파일에 이어서 작성하고 싶으면 두 번째 매개변수에 true라고 작성
FileOutputStream fos=new FileOutputStream("output.txt", true);
write(byte[ ] b) 메소드
- write( ) 메소드로 한 바이트씩 읽는 것 보다 배열을 사용하여 읽는게 처리 속도가 더 빠름
write(byte[ ] b, int off, int len) 메소드
- 배열 전체 자료를 출력하지 않고 배열의 off위치 부터 len길이 만큼 출력
flush( ) 메소드와 close( ) 메소드
- 강제로 자료를 출력하는 것
- write( ) 메소드로 값을 썼다 해도 출력을 위한 자료가 쌓이는 출력 버퍼에 어느 정도 자료가 모여야 출력되는데, 이 때, 파일에 쓰이지 않거나나 전송되지 않았을 때 close( ) 메소드 안에서 flush( ) 메소드를 호출하여 출력 버퍼가 비워지면서 남아 있는 자료를 모두 출력함
Reader
- 문자 단위로 읽는 스트림 중 최상위 스트림
FileReader
- FileInputStream과 마찬가지로 읽으려는 파일이 없으면 FileNotFoundException이 발생
Writer
- 문자 단위로 출력하는 스트림 중 최상위 스트림
FileWriter
- FileOutputStream과 마찬가지로 출력 파일이 존재하지 않으면 파일을 생성
보조스트림
- 직접 쓰거나 읽는 기능은 없음
- 어떤 보조 스트림이 더해지느냐에 따라 스트림 기능이 추가됨
- Wrapper 스트림이라고도 함
데코레이터(decorator)
- 보조스트림처럼 다양한 기능을 제공하는 클래스를 디자인 패턴에서 부르는 말
FilterInputStream과 FilterOutputStream
- 보조 스트림의 상위 클래스
- 다른 생성자는 제공하지 않음
- 직접 생성하여 사용하는 경우는 거의 없고 상속한 하위 클래스를 프로그램에서 많이 사용
- 다른 보조 스트림을 매개변수로 전달받을 수도 있음
InputStreamReader와 OutputStreamWriter
- 바이트단위로 자료를 읽으면 한글 같은 문자는 깨짐, 따라서 Reader나 Writer에 상속받은 스트림을 사용해서 자료를 읽거나 써야함
Buffered 스트림
- 내부적으로 8,192바이트 크기의 배열을 가지고 있음
- 이미 생성된 스트림에 배열 기능을 추가해 더 빠르게 입출력을 실행할 수 있는 버퍼링 기능을 제공
DataInputStream과 DataOutputStream
- 메모리에 저장된 0,1 상태를 그대로 읽거나 씀
- 자료형의 크기가 그대로 보존됨, 따라서 같은 정수라도 자료형에 따라 다르게 처리함
- 파일이든 네트워크든 자료를 쓸 때 사용한 메소드 순서대로 읽어야함
ex)정수 100을 쓰는데 writeInt(100)을 쓰고 readByte( ) 로 읽으면 읽을 수 없음
직렬화(serialization)
- 인스턴스 변수 값은 계속 변하는데, 그 인스턴스의 어느 순간 상태를 그대로 저장하거나 네트워크를 통해 전송할 일이 있을 때 사용
- 인스턴스 내용을 연속 스트림으로 만드는 것(스트림으로 만들어야야 파일or네트워크로 전송 가능)
- 보조 스트림인 ObjectInputStream과 ObjectOutputStream을 사용하여여 쉽게 구현
역직렬화(deserialization)
- 저장된 내용이나 전송받은 내용을 다시 복원하는 것
package stream.serialization;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
class Person implements Serializable{
private static final long serialVersionUID = 6412276319311846923L;
String name;
transient String job;
public Person() {}
public Person(String name, String job) {
this.name = name;
this.job = job;
}
public String toString() {
return name + ", " + job;
}
}
public class SerializationTest {
public static void main(String[] args) throws ClassNotFoundException {
Person personAhn = new Person("안재용", "대표이사");
Person personKim = new Person("김철수", "상무이사");
try(FileOutputStream fos = new FileOutputStream("serial.out");
ObjectOutputStream oos = new ObjectOutputStream(fos)){
oos.writeObject(personAhn);
oos.writeObject(personKim);
} catch(IOException e) {
e.printStackTrace();
}
try(FileInputStream fis = new FileInputStream("serial.out");
ObjectInputStream ois = new ObjectInputStream(fis)){
Person p1 = (Person)ois.readObject();
Person p2 = (Person)ois.readObject();
System.out.println(p1);
System.out.println(p2);
} catch(IOException e) {
e.printStackTrace();
}
}
}
안재용, null
김철수, null
Serializable 인터페이스
- 직렬화는 인스턴스 내용이 외부로 유출되므로 프로그래머가가 직렬화를 하겠다는 의도를 표시해야함
- 따라서, 클래스에 마커 인터페이스인 Serializable 인터페이스를 추가
class Person implements Serializable{
...
String name;
String job;
...
}
transient 예약어
- 직렬화 될 수 없는 클래스(socket 클래스)가 인스턴스 변수로로 있거나 직렬화하고 싶지 않은 변수가 있을 때 사용하는 예약어
- 해당 변수는 직렬화되고 복원되는 과정에서 제외됨
- 그 자료형의 기본 값으로 저장
안재용, null
김철수, null
serialVersionUID
- 직렬화/역직렬화시 클래스와 상태가가 다르면 오류가 발생, 이 사이 클래스가 수정되었따거나 변경되었으면 역직렬화가 불가능 하기 때문
- 따라서 직렬화시에 자동으로 serialVersionUID를 생성하여 정보를 저장하여 역직렬화시 비교
- 작은 변경에도 계속 바뀌면 배포과정이 번거롭기에 개발자가 버전관리를 할 수 있다.
- 자바 설치 경로의 /bin/serialver 사용하면 생성됨, 이정보를 클래스 파일에 적어주면 된다.
- 이클립스에서는 이 기능을 자동으로 제공.
Externalizable 인터페이스
- 직렬화시에 사용하는 또다른 인터페이스
- 프로그래머가가 따로 구현하지 않음, 하지만 따로 구현해야 할 메소드가 있음
- 객체의 직렬화/역직렬화를 직접 세밀하게 제어하고자 할때 메소드에 그 내용을 구현
- writeExternal( ), readExternal( ) 메소드를 구현해야함.
- 복원할 때 디폴트 생성자가 호출되므로 디폴트트 생성자를 추가해 주어야함
ex)name 속성을 가진 Dog클래스에 Externalizable를 구현
package stream.serialization;
import java.io.Externalizable;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
class Dog implements Externalizable {
String name;
public Dog() {}
@Override
public void writeExternal(ObjectOutput out) throws IOException{
out.writeUTF(name);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException{
name = in.readUTF();
}
public String toString() {
return name;
}
}
public class ExternalizableTest {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Dog myDog = new Dog( );
myDog.name = "멍멍이";
FileOutputStream fos = new FileOutputStream("external.out");
ObjectOutputStream oos = new ObjectOutputStream(fos);
try(fos; oos){
oos.writeObject(myDog);
} catch(IOException e) {
e.printStackTrace();
}
FileInputStream fis = new FileInputStream("external.out");
ObjectInputStream ois = new ObjectInputStream(fis);
Dog dog = (Dog)ois.readObject();
System.out.println(dog);
}
}
멍멍이
File 클래스
- 파일이라는 개념을 추상화한 클래스
- 별도의 입출력 기능은 없지만, 파일 자체의 경로나 정보를 알 수 있고 파일을 생성할 수 있음
- File 클래스를 생성했다고 실제로 파일이 생성되지는 않는다.
- createNewFile( ) 메소드를 활용하여 파일을 생성
RandomAccessFile 클래스
- 입출력 클래스 중 유일하게 파일 입출력을 동시에 할 수 있는 클래스
- 파일 포인터를 사용해 처음부터 자료를 읽지않고, 임의의 위치로 이동하여 자료를 읽을 수 있다.
- 스트림을 생성하지 않고 간단하게 파일에 자료를 쓰거나 읽을 때 유용
- 파일 포인터 위치를 잘 생각하며 구현해야함!!
- 다양한 자료형 값을 읽거나 쓸 수 있다.
- 구현한 인터페이스 종류 : DataInput, DataOutput
- seek( ) : 파일 포인터 위치를 이동해 주는 메소드. 맨앞으로 이동한다.
'Language > Java' 카테고리의 다른 글
Java Deque란?? (0) | 2022.12.14 |
---|---|
멀티캠퍼스 15일차 (완) (0) | 2022.10.31 |
멀티캠퍼스 13~14일차 (0) | 2022.10.28 |
멀티캠퍼스 12일차 (0) | 2022.10.26 |
멀티캠퍼스 11일차 (0) | 2022.10.25 |
댓글