[THEC!T] 앱 스쿨2기 : Android

TECHIT 앱 스쿨 2기: Android 10일차 (23.05.08)

끝까지 처음처럼 2023. 5. 8. 22:32
728x90

자료 출처 : 안드로이드 앱스쿨 2기 윤재성 강사님 수업 내용

 

오늘은 자바 스트림에 대해 배웠으나, 아직 부족하여 내일 중으로 다시 작성 할 수 있도록 하겠습니다.

저장위치에 대한 설명
주기억장치, 보조기억장치
주기억장치 -> RAM
RAM의 특징은 속도가 빠름, 휘발성 메모리
실행 중 사용할 데이터등

보조기억장치 -> HDD,SSD
속도가 느림, 비휘발성 메모리
지속해서 사용해야할 데이터등

 

스트림에 대한 설명
외부에 있는 데이터를 읽고 쓰고를 할 수 있도록 제공되는 자바 클래스들.


InputStream : 데이터를 외부파일에서 읽어올 때
OutputStream : 데이터를 외부 파일에 쓸 때

-> 지금 작성하고 있는 코드의 입장으로 생각하였을 때 지금 외부 데이터를 가져올 때는 코드쪽으로 데이터가  들어오니 Input, 반대로 지금 만든 데이터가 나가야 하니 Output 


스트림에는 InputStream 과 OutputStream 를 상속받는 Strime이 있고 자체적으로 파일의 읽고 쓰고의 기능이 있다.
상속 받지 않는 스트림은 통칭 FilterStream 이라고 부르며 데이터의 가공의 목적을 가지고 있다.

일반적으로 InputStream 으로 받아서 FilterStream 으로 데이터를 가공한 뒤 사용하고 FilterStream 으로 데이터를 가공한 다음 OutputStream으로 외부 파일에 저장한다. 

파일스트림에 대한 설명.

 

FileInputStream: 파일로부터 데이터를 읽기 위해 사용되는 클래스입니다.
FileOutputStream: 파일에 데이터를 쓰기 위해 사용되는 클래스입니다.
FileInputStream과 FileOutputStream은 바이트 단위로 데이터를 처리합니다.
FileInputStream은 read() 메서드를 사용하여 파일로부터 데이터를 읽고, FileOutputStream은 write() 메서드를 사용하여 데이터를 파일에 씁니다.

참고로 Stream들은 try~catch문을 이용하여 작성해야 합니다.

package com.test.main;

import java.io.FileInputStream;
import java.io.FileOutputStream;

public class Study {
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		// 데이터 저장
		saveData();
		saveData2();
		loadData();	
	}

	
	// 데이터를 저장하는 메서드
	public static void saveData() {
		
		try {
			// 파일을 쓰기위한 스트림 생성
			// 파일이 없다면 파일을 생성함.
			FileOutputStream fos = new FileOutputStream("study.txt");
			
			// 데이터 생성
			String value = "데이터1";
			
			// 데이터를 바이트 형태로 가공한다.
			byte [] data1 = value.getBytes();
			
			// 데이터 작성
			fos.write(data1);
			
			// 출력버퍼에 데이터가 남아 있는 것을 방지
			fos.flush();
			
			// 스트림을 닫아준다.
			fos.close();
			
		}catch(Exception e) {
			e.printStackTrace();
		}
		
	}

	// 데이터를 저장하는 메서드
	public static void saveData2() {
		
		try {
			// 파일을 쓰기위한 스트림 생성
			// 파일이 없다면 파일을 생성함.
			// 뒤에 true를 보내주면, 기존 파일이 있을 경우 내용을 추가한다.
			FileOutputStream fos = new FileOutputStream("study.txt",true);
			
			// 데이터 생성
			String value = "데이터2";
			
			// 데이터를 바이트 형태로 가공한다.
			byte [] data1 = value.getBytes();
			
			// 데이터 작성
			fos.write(data1);
			
			// 출력버퍼에 데이터가 남아 있는 것을 방지
			fos.flush();
			
			// 스트림을 닫아준다.
			fos.close();
			
		}catch(Exception e) {
			e.printStackTrace();
		}
		
	}
		
	// 데이터를 가져오는 메서드
	public static void loadData() {
		try {
			// 데이터를 읽어오는 스트림.
			FileInputStream fis = new FileInputStream("study.txt");
			
			// 읽어올 데이터의 양을 구한다.
			int byteSize = fis.available();
			
			// 데이터를 저장할 byte타입 배열을 만든다.
			byte[] loadArr = new byte[byteSize];
			
			// 데이터를 읽어온다.
			fis.read(loadArr);
			// 스트림을 닫아준다.
			fis.close();
			
			// 읽어온 데이터를 String 객체로 생성한다.
			String str = new String(loadArr);
			System.out.println(str);
			
		}catch(Exception e) {
			e.printStackTrace();
		}
		
	}
	
}

출력 결과.

데이터1데이터2

 

필터 스트림에 대한 설명.

필터 스트림은 기본 자료형 값을 byte 배열 형태로 변환해주는 역할을 한다.

 

package com.test.main;

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

public class MainClass {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		// DataStream
		// 기본 자료형 값을 byte 배열 형태로 변환해주는 역할을 하는
		// 필터 스트림이다.
		
		//savdData();
		readData();
	}

	
	public static void savdData() {
		try {
			// 기본 스트림 생성
			FileOutputStream fos = new FileOutputStream("text3.txt");
			// 필터 스트림 생성
			// DataStream 생성
			DataOutputStream dos = new DataOutputStream(fos);
			
			// 쓴다.
			dos.writeInt(100);
			dos.writeDouble(11.11);
			dos.writeBoolean(true);
			dos.writeUTF("안녕하세요");
			
			// 닫는다
			dos.flush();
			dos.close();
			fos.close();
			
			System.out.println("쓰기 완료");
			
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	
	
	
	public static void readData() {
		try {
			// 기본 스트림 생성
			FileInputStream fis = new FileInputStream("text3.txt");
			// DataStream 생성
			DataInputStream dis = new DataInputStream(fis);
			
			// 쓴 순서 그대로 가져온다.
			int a1 = dis.readInt();
			double a2 = dis.readDouble();
			boolean a3 = dis.readBoolean();
			String a4 = dis.readUTF();
			
			// 닫는다.
			dis.close();
			fis.close();
			
			System.out.println(a1);
			System.out.println(a2);
			System.out.println(a3);
			System.out.println(a4);
			
			
		}catch(Exception e){
			e.printStackTrace();
		}
	}
}

 

2바이트 스트림에 대하여 설명.

자바는 글자 하나에 2byte를 사용하기 때문에  문자열 입출력 전용으로 사용하는 스트림들을

2byte stream 이라고 부르며,  라인 단위 입출력이 가능하고 문자열 인코딩 설정이 가능합니다.

사실 백준이라는 사이트에 있는 문제를 풀며, BufferedWriter와 BufferedReader를 알고 있었지만, 사용법을 더 자세히 알게될 수 있었습니다.

package com.test.main;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

public class MainClass {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		saveData();
		printData();
		loadData();
		keyboardInput();
	}

	
	public static void saveData() {
		try {
			// 기본 스트림 생성
			FileOutputStream fos = new FileOutputStream("test4.txt");
			// OutputStreamWriter
			// 문자열 인코딩을 설정하는 필터 스트림
			OutputStreamWriter writer = new OutputStreamWriter(fos, "UTF-8");
			// 출력 버퍼를 사용하는 필터 스트림
			BufferedWriter bw = new BufferedWriter(writer);
			// 라인 단위로 쓰는 필터 스트림
			// println, print, printf 를 사용할 수 있는 필터 스트림.
			PrintWriter pw = new PrintWriter(bw);
			
			// 파일에 쓴다.
			pw.print("안녕하세요");
			pw.println("반갑습니다");
			pw.printf("이름은 %s이고, 나이는 %d살 입니다.\n", "홍길동", 30);
			
			pw.flush();
			pw.close();
			bw.close();
			writer.close();
			
			System.out.println("쓰기 완료");
			
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	
	public static void printData() {
		try {
			// 기본 출력(터미널)에 인코딩을 설정할 수 있도록 작업한다.
			OutputStreamWriter writer = new OutputStreamWriter(System.out,"utf-8");
			BufferedWriter bw = new BufferedWriter(writer);
			PrintWriter pw = new PrintWriter(bw);
			
			pw.print("안녕하세요");
			pw.println("반갑습니다.");
			pw.printf("이름은 %s이고, 나이는 %d살 입니다.", "홍길동",30);
			
			pw.flush();
			pw.close();
			bw.close();
			
			
			
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	public static void loadData() {
		try {
			FileInputStream fis = new FileInputStream("test4.txt");
			// 인코딩 설정
			InputStreamReader irs = new InputStreamReader(fis, "utf-8");
			// 입력 버퍼 사용
			BufferedReader br = new BufferedReader(irs);
			
			// 읽어온다.
			String str1 = null;
			StringBuffer buffer = new StringBuffer();
			
			do {
				// 한 줄을 읽어 온다.
				str1 = br.readLine();
				if(str1 != null) {
					buffer.append(str1 + "\n");
				}
			} while(str1 != null);
			
			br.close();
			irs.close();
			fis.close();
			
			// StringBuffer의 문자열로 String을 만든다.
			String result = buffer.toString();
			System.out.println(result);
			
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	
	public static void keyboardInput() {
		try {
			
			InputStreamReader isr = new InputStreamReader(System.in, "utf-8");
			BufferedReader br = new BufferedReader(isr);
			System.out.print("입력1 : ");
			String str1 = br.readLine();
			System.out.print("입력2 : ");
			String str2 = br.readLine();
			
			br.close();
			isr.close();
			
			System.out.println(str1);
			System.out.println(str2);
			
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
	
}

출력 결과

쓰기 완료
안녕하세요반갑습니다.
이름은 홍길동이고, 나이는 30살 입니다.


오브젝트 스트림 및 객체 직렬화

객체 직렬화란 객체를 저장하게 되면 개발자 입장에서는 한곳에 저장한 것처럼 느껴지지만 실제로는

객체의 효율적인 관리를 위해 객체의 구성 요소를 메모리상에 나눠서 관리하는데 이를 한데 모아 바이트 배열 형태로 변환해주는 것 입니다.

 

위 사진 처럼 메모리에 따로 되어 있어 이것을 한곳에 모아서 하려면 객체를 만드는 클래스에 Serializable 인터페이스를 구현하면 됩니다. 그렇게 만든 객체를 오브젝트 스트림을 이용하여 파일에 저장할 수 있습니다.

 

package com.test.main;

import java.io.EOFException;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Study {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		saveObj();
		loadObj();
		
	}

	// 파일에 저장하는 메서드
	public static void saveObj() {
		try {
			
			// 파일에 저장하는 스트림 생성
			FileOutputStream fos = new FileOutputStream("test1.txt");
			// 파일에 저장할 객체를 내보내는 스트림 생성
			ObjectOutputStream oos = new ObjectOutputStream(fos);
			
			// 저장할 학생들 객체 생성.
			Student s1 = new Student("one",1,1);
			Student s2 = new Student("two",2,2);
			Student s3 = new Student("three",3,3);
			
			// 파일에 객체를 저장(쓴다)
			oos.writeObject(s1);
			oos.writeObject(s2);
			oos.writeObject(s3);
			
			// 남아 있는 데이터가 있을 수 있으니 남아있다면 파일에 모두 저장.
			oos.flush();
			// 저장하기 위한 스트림을 닫아준다.
			// 닫는 순서는 역순
			oos.close();
			fos.close();

			System.out.println("저장완료");
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	// 파일에 있는 정보를 가져오는 메서드
	public static void loadObj() {
		FileInputStream fis = null;
		ObjectInputStream ois = null;
		try {
			// 파일에 저장된 정보 가져오는 스트림 생성.
			fis = new FileInputStream("test1.txt");
			ois = new ObjectInputStream(fis);
			
			while(true) {
				// 읽어온 데이터는 바이트배열 형식으로 되어 있으므로 형변환을 해야한다.
				Student readStd = (Student)ois.readObject();
				readStd.printInfo();
			}
		}catch(EOFException e) {
			System.out.println("더 이상 읽어올 학생이 없습니다.");
			
			if(ois != null)
				try {
					ois.close();
					fis.close();
				} catch (IOException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
		}catch(Exception e) {
			
			e.printStackTrace();
		}
	}
}


// 객체 직렬화를 위해 Serializable 인터페이스를 구현한 클래스

class Student implements Serializable{
	
	String name;
	Integer age;
	Integer grade;
	
	public Student(String name,Integer age,Integer grade) {
		this.name = name;
		this.age = age;
		this.grade = grade;
	}
	
	public void printInfo() {
		System.out.printf("이름 : %s\n",name);
		System.out.printf("나이 : %s\n",age);
		System.out.printf("학급 : %s\n",grade);
	}
	
}

출력결과

저장완료
이름 : one
나이 : 1
학급 : 1
이름 : two
나이 : 2
학급 : 2
이름 : three
나이 : 3
학급 : 3
더 이상 읽어올 학생이 없습니다.

 

강사님께서 내주신 과제는 사용자가 입력해주는 번호에 따라 학생의 정보를 저장하거나 과목의 총점, 평균을 구하거나 등의 기능을 구현하는 것였습니다. 학생의 정보는 메모리에 있지 않고 파일에서 읽고 쓰고 하는 조건이였습니다.

 

근데 진행 중 학생을 여러명 저장하고 나서 불러올 때 1명만 불러오는 오류가 있어 이거 때문에 정말 고민하다가 회고도 못쓰고....다음날 아침에 운동도 못갔습니다... ㅠㅜ 그래서 스트림개념을 잘못 이해했나 싶기도 했지만, 결국 스트림 관련 강의를 들은 당일 날 해결을 하지 못했었습니다. 결론을 먼저 말씀드리면 다음 날 계속 회의를 하면서 수정해보고 그러다가 조원분께서 해당 부분을 다른 방식으로 해결하였습니다. 즉 이틀동안....고통을 받았던..... 이 부분은 추후 강사님께 어떻게 해야 되는지 여쭤볼 생각입니다. 하지만 해당 문제를 해결하려하면서 나름? 실력이 상승한 것 같기도 합니다.

 

 

늦게 쓰는 오늘의 마음가짐

문제해결등을 통해 점점 발전해가는 개발자가 되자~!