입출력 파트 이제 끝. 오늘로 자바 파트가 끝나고 오라클로 넘어간다.
그렇다고 자바가 완전히 끝난게 아니니 오라클 수업동안 자바도 같이 복습해야만 한다.
자바 + 오라클 + 당일과제 + 팀스터디 -> 오 빡세다...
여기에 정처기 필기까지 했다면 더 힘들었겠지만 정처산기 실기 까지 여유가 있으니 다행이다.
보조 스트림 filterStream
- 스트림의 기능을 향상시키거나 새로운 기능을 추가하기 위해서 사용
- 보조 스트림은 실제 데이터를 주고 받는 스트림이 아니기 때문에 입출력 처리가 불가능
- 기반 스트림을 먼저 생성한 후 이를 이용하여 보조 스트림을 생성
보조 스트림의 종류
입출력 성능(BufferedInputStream/BufferedOutputStream)
기본 데이터 타입 출력(DataInputStream, DataOutputStream)
객체 입출력(ObjectInputStream/ObjectOutputStream) 등의 기능을 제공하는 보조스트림이 있다
기본 스트림은 외부 데이터에 직접 연결이 되는 스트림이고,
필터 스트림은 외부 데이터에 직접 연결하는 것이 아니라 기본 스트림에 추가로 사용할 수 있는 스트림이다.
생성자 쪽에 매개변수로 다른 스트림을 이용하는 클래스는 필터 스트림이라고 볼 수 있다.
FileInputStream fis = new FileInputStream("sample.txt"); //기반 스트림 생성
BufferedInputStream bis = new BufferedInputStream(fis); //보조스트림 생성
bis.read(); //보조스트림으로부터 데이터 읽어옴
위 코드를 한 줄로 표현할 수 도 있다.
BufferedInputStream bis =new FileInputStream("sample.txt");
성능 향상 보조 스트림 BefferedInputStream / BufferedoutputStream
느린 속도로 인해 입출력 성능에 영향을 미치는 입출력 소스를 이용하는 경우 사용
입출력 소스와 직접 작업하지 않고 버퍼에 데이터를 모아 한꺼번에 작업을 하여 실행 성능을 향상
(입출력 횟수를 줄임)
BufferedWriter로 파일을 생성하고, 내용을 입력해보자.
/* BufferedWriter 인스턴스 생성 */
BufferedWriter bw =null;
try {
bw = new BufferedWriter(new fileWriter("파일경로")); //자동 생성
//버퍼를 이용하는 경우 버퍼가 가득 차면 자동으로 내보내기를 하지만
//버퍼가 가득 차지 않은 상태에서는 강제로 내보내기를 해야 한다.
이때 flush()를 해주면 기록이 된다.
bw.writer("안녕하세요.\n");
bw.writer("반갑습니다.\n");
bw.flush();
}catch(IOException e){
e.printStackTrace();
}finally {
//colse()를 호출하면 내부적으로 flush()를 하고 나서 자원을 반납한다.
if(bw != null){
try{
bw.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
BufferedReader 버퍼에 미리 읽어온 후 한 줄 단위로 읽어들이는 기능을 제공하며 기본 스트림보다 성능을 개선시킨다.
readLine()을 추가로 제공한다.
버퍼의 한 줄을 읽어와서 문자열로 반환한다.
BufferedReader br =null;
try{
br= new BufferedReader(new FilerReader("파일경로"));
String temp;
while((temp = br.readLLine()) ! = null){
System.out.println(temp);
}
}catch(FileNotFoundException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}finally {
if(br != null){
try{
br.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
형변환 보조 스트림 InputStreamReader / OutputStreamWriter
기본 스트림이 byte기반 스트림이고, 보조 스트림이 chsr 기반 스트림인 경우에 사용
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.in을 InputStreamReader로 변환하여 바이트기반 스트림을 문자 기반 스트림으로 변환 후
버퍼를 이용한 보조스트림과 연결
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
표준 스트림
자바에서는 콘솔이나 키보드 같은 표준 입출력 장치로부터 데이터를 입출력 하기 위한 스트림을
표준 스트림 형태로 제공하고 있다. System 클래스의 필드 in, out, err가 대상 데이터의 스트림을 의미한다.
System.in (InputStream) : 콘솔로부터 데이터를 입력받음
System.out (printStream) : 콘솔로 데이터를 출력
System.err (printStream) : 콘솔로 데이터를 출력
즉, 자주 사용되는 자원에 대해 미리 스트림을 생성해 두었기 때문에 개발자가 별도로 스트림을 생성하지 않아도 된다.
이런 표준 스트림 중 콘솔로부터 읽어오는 기반 스트림이 inputStream인데
Buffer를 이용해서 성능을 향상시키고 싶은 경우에 형변환 보조스트림을 사용할 수 있다.
InputStreamReader
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
try{
System.out.println("문자열 입력 : ");
String value = br.readLine();
System.out.println("value : " + value);
}catch(IOException e){
e.printStackTrace();
}finally{
if(br != null){
try {
br.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
출력을 위한 것도 동일한 방식으로 사용할 수 있다.
OutputStreamWriter
BufferedWriter br = new BufferedWriter(new OutputStreamWriter(System.out));
try{
bw.write("java oracle jdbc")
}catch(IOException e){
e.printStackTrace();
}finally{
if(bw != null){
try {
bw.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
기본 데이터 타입 보조 스트림 DataInputStream / DataOutputStream
기본 자료형 별 데이터를 읽고 쓰기 가능하도록 기능을 제공
(단, 입력된 자료형의 순서와 출력 될 자료형의 순서는 일치해야 함)
외부 데이터로부터 읽어오는 데이터를 바이트형으로만 읽어오면
정수, 문자, 문자열 등 여러 데이터 타입을 취급하는 경우 별도로 처리해주어야 한다.
ex )정수 입력 받아 처리하려면 parsing을 해주어야 한다.
데이터 자료형 별로 처리하는 기능을 추가한 보조 스트림을 제공하고 있다.
DataInputStream / DataOutputStream
데이터형별로 파일에 기록하는 DataOutputStream 인스턴스를 생성해보자.
DataOutputStream dout = null;
try {
dout = new DataOutputStream(new FileOutputStream("파일경로"));
//파일에 자료형 별로 기록
dout.writeUTF("김영희");
dout.writeInt(95);
dout.writeChar('A');
dout.writeUTF("김철수");
dout.writeInt(87);
dout.writeChar('B');
dout.writeUTF("홍길동");
dout.writeInt(73);
dout.writeChar('C');
}catch(FlieNotFoundException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}finally{
if(dout != null){
try {
dout.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
파일을 읽어올 수 있는데, 데이터의 자료형은 기록된 순서와 동일하게 읽어와야 한다.
문자열, 정수 , 문자 순으로 데이터 저장했을 때
문자, 문자열, 정수 순으로 데이터을 읽어오면 에러 발생 또는 올바르지 않은 값을 읽어온다.
DataInpurStream
DataInputStream din = null;
try{
din = new DataInputStream (new FileInputStream("파일경로"));
System.out.println(din.readUTF() + ", " + din.readInt() + ", " + din.readChar());
}catch(FlieNotFoundException e){
e.printStackTrace();
//무한루프로 읽어들이게 되면 파일에 더 이상 읽을 것이 없는 경우 EOFException 발생.
//catch 블럭에 EOFException을 핸들링하는 코드를 추가한다.
}catch(EOFException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}finally{
if(din != null){
try {
din.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
그런데 이 학생의 이름, 점수, 등급 을 학생마다 일일히 입력해 보내주는 방식 어디선가 익숙한 방법이 떠오르는데 ..
public class Student {
private String name;
private int score;
private char grade;
}
학생 객체를 만들어서 전달하는 건 어떨까. 이러한 기능 역시 있다.
객체 입출력 보조 스트림 ObjectInputStream / ObjectOutputStream
객체 단위로 파일 또는 네트워크로 입출력할 수 있는 기능을 제공한다.
회원 정보를 관리하기 위한 용도의 DTO 클래스가 있다고 한다면
public class memberDTO {
private String id;
private String pwd;
private String name;
private int age;
private char gender;
private double point;
}
//기본생성자 / 모든필드를 매개변수로 받는 생성자 / getter/setter / toString() 생성하기.
객체 생성 후 객체 입출력 보조 스트림을 이용하여 기록해보자.
MemberDTO[] outputMemvers = {
new MemberDTO("user01","pass01","김영희",25,'여',1000);
new MemberDTO("user02","pass02","김철수",26,'남',2000);
new MemberDTO("user03","pass03","홍길동",18,'남',2500);
}
ObjectOutputStream object = null;
//보조스트림은 중첩해서 사용 가능하다.
//객체입출력보조스트림(성능향상Buffer스트림(기반스트림(파일경로)));
try{
objOut = new ObjectOutputStream(new bufferOutputStream(new FileOutputStream("파일경로")));
for(int i= 0; i < outputmembers.length; i++){
objOut.writeObject(outputMembers[i]);
}
}catch(IOException){
e.printStackTrace();
}finally{
if(objOut != null){
try {
objOut.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
이렇게 작성 후 코드를 실행해 보면 java.io.NotSerializableException 이 발생한다.
이는 직렬화 처리를 해주지 않아서 발생하는 에러이다.
직렬화란? Serializable
자바 시스템 내부에서 사용되는 객체 또는 데이터를 외부에서도 사용할 수 있도록
바이트(byte) 형태로 데이터를 변환하는 기술을 발한다.
반대로 바이트로 변환 된 데이터를 다시 객체로 변환하는 기술을 역직렬화라고 함.
객체로 입출력 하기 위해서는 반드시 직렬화 처리를 해야 한다,
직렬화 대상 클래스에 Serializable 인터페이스만 구현하면
직렬화가 필요한 상황인 경우 해당 인터페이스를 상속 받았을 시 데이터를 직렬화 처리한다.
public class memberDTO implements java.io.Serializable {
private String id;
private String pwd;
private String name;
private int age;
private char gender;
//직렬화에서 제외시키고 싶을 때는 transient 키워드를 추가한다.
private transient double point;
}
*직렬화 대상에서 제외시키고 싶은 필드의 경우 transient 키워드를 이용할 수 있다.
역직렬화
MemberDTO[] inputMembers = new MemberDTO[3];
ObjectInputStream objIn = null;
try{
objIn = new ObjectInputStream(new BufferInputStream(new FileInputStream("파일경로")));
//읽어온 Object가 해당하는 Class가 없는 경우 ClassNotFoundException이 발생할 수 있다.
// while(true){
// System.out.println(objIn.readObject());
// }
for(int i=0; i< inputMembers.length; i++){
inputMembers[i] = (MemberDTO) objIn.readObject(); //다운캐스팅
}
}catch(FileNotFoundxception e){
e.printStackTrace();
}catch(EOException e){
System.out.println("파일을 모두 읽어왔습니다.");
}catch(IOException e){
e.printStackTrace();
}catch(ClassNotFoundException e){
e.printStackTrace();
}finally{
if(objIn != null){
try {
objIn.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
for(Members member : inputmembers){
System.out.println(member);
}
srialVersionUID 필드
직렬화된 클래스와 같은 클래스임을 알려주는 식별자
컴파일 시 JVM이 자동으로 serialVersionUID 정적필드를 추가해 주기 때문에
별도로 작성하지 않아도 오류는 나지 않지만 자동 생성 시 역질력화에서 예상하지 못한
InvalidClassException을 유발할 수 있으므로 명시해 줄 것을 권장
private static final long serialVersionUID = -6423919775137290062L;
'백엔드 과정 > Java' 카테고리의 다른 글
[Java] 객체 배열 개념 복습 (0) | 2022.01.15 |
---|---|
[Java] 클래스와 객체 개념 복습 (0) | 2022.01.14 |
[Java] day22. 입출력IO / Stream / File (0) | 2022.01.12 |
[Java] 국비교육 day21. 예외처리 Exception (0) | 2022.01.12 |
[Java] day20. 컬렉션 프레임워크 Set / Map (0) | 2022.01.12 |