JAVA 6주차

Organ·2023년 10월 16일
0

JAVA

목록 보기
10/14

25일차

Map 인터페이스(170)

/*================================
  ■■■ 컬렉션(Collection) ■■■
=================================*/

// Map -> Hashtable, HashMap

/*
○ java.util.Map 인터페이스
   키(Key)를 값(value)에 매핑(mapping) 하며 동일한 키를 등록할 수 없고, 유일해야 하며,
   각 키는 한 개의 값만을 매핑해야 한다. 즉, 하나의 키에 대응하는 하나의 값을 갖는 구조이다.

○ Hashtable<K, V> 클래스

   - 해시테이블 구조를 객체 모델링화 한 클래스로 검색이 용이하기 때문에 사용 빈도가 높은 편에 속한다.
   - 해시테이블이란 키(key)와 그에 상응하는 데이터(value)로 구분된 데이터 구조이다.
   - 데이터를 저장하고, 검색하기 위해서 키(key)로 접근하며 이 구조에서는 키값을 부여하면 해당 데이터가 
     변환 된다.
   - 또한, Hashtable 클래스는 Key 또는 value 의 값으로 null 을 허용하지 않는다.
*/

import java.util.Hashtable;

public class Test170
{
	private static final String[] names = {"강혜성", "길현욱", "김경태", "김다슬", "김동민", "김민지"};

	private static final String[] tels = {"010-6380-7047", "010-6678-9867", "010-4012-6216", "010-8972-1901", "010-4073-4940", "010-7159-4231"};

	public static void main(String[] args)
	{
		// Hahstable 자료구조 생성
		// key, value 두 가지 종류가 있기 때문에 제네릭도 두가지를 작성해준다.
		Hashtable<String, String> ht = new Hashtable<String, String>();

		// ht 라는 Hashtable 자료구조에 배열(names, tels)에 담겨있는 데이터를 요소로 담아내기
		// -> put(k, v);
		for(int i = 0; i < names.length; i++)
		{
			// ht.put("강혜성", "010-6380-7047");
			ht.put(names[i], tels[i]);
		}

		// ht 라는 Hashtable 자료구조에서 Key를 이용하여 데이터 검색
		// -> get(k);
		// String findName1 = "김동민";
		String findName1 = "이윤수";
		String str = ht.get(findName1);
		if(str != null)
		{
			System.out.println(findName1 + " 전화번호 : " + str);
		}
		else
		{
			System.out.println("테스트");
		}
		System.out.println();
		// 김동민 전화번호 : 010-4073-4940
		// 테스트(이윤수 존재하지 않아서 str에 null이 들어감)

		// ht 라는 Hashtable 자료구조에 Kay가 존재하는지의 여부 확인 -> containsKey() value찾는 메소드 아님!!
		String findName2 = "이주형";
		if(ht.containsKey(findName2))
		{
			System.out.println(findName2 + " 데이터가 존재합니다.");
		}
		else
		{
			System.out.println(findName2 + " 데이터가 존재하지 않습니다.");
		}
		System.out.println();
		// 이주형 데이터가 존재하지 않습니다.

		String findName3 = "김민지";
		if(ht.containsKey(findName3))
		{
			System.out.println(findName3 + " 데이터가 존재합니다.");
		}
		else
		{
			System.out.println(findName3 + " 데이터가 존재하지 않습니다.");
		}
		System.out.println();
		// 김민지 데이터가 존재합니다.

		// ht 라는 Hashtable 자료구조에 value가 존재하는지 확인
		// -> contains();
		String findTel1 = "010-4012-6216";				// 김경태 전화번호
		if(ht.contains(findTel1))
		{
			System.out.println(findTel1 + " 데이터가 존재합니다.");
		}
		else
		{
			System.out.println(findTel1 + " 데이터가 존재하지 않습니다.");
		}
		System.out.println();
		// 010-4012-6216 데이터가 존재합니다.

		// ht 라는 Hashtable 자료구조에서 길현욱 데이터 삭제 -> remove()
		ht.remove("길현욱");

		// ※ remove() 메소드는 인자값으로 key를 넘겨받지만 이 때, key 만 삭제하는 것이 아니다.
		//    해당 key와 연결되어(매핑되어)있는 value 도 함께 제거된다.

		// 삭제(remove()) 이후 ht라는 Hashtable 자료구조에 해당 key 가 존재하는지 확인
		if(ht.containsKey("길현욱"))
			System.out.println("길현욱이 존재합니다.");
		else
			System.out.println("길현욱 어디갔어??");
		System.out.println();
		// 길현욱 어디갔어??

		// 삭제(remove()) 이후 ht라는 Hashtable 자료구조에 해당 key 가 존재하는지 확인
		if(ht.contains("010-6678-9867"))
			System.out.println("길현욱 전화번호가 존재합니다.");
		else
			System.out.println("길현욱 전화번호가 존재하지 않습니다.");
		System.out.println();
		// 길현욱 전화번호가 존재하지 않습니다.

		
		// ※ null 관련 처리
		// ht.put(null, null);				// key 와 value 모두 null 인 상태
		// 런타임 에러  NullPointerException

		// ht.put("김수환", null);				// value 가 null 인 상태
		// 런타임 에러  NullPointerException

		// ht.put(null, "010-1234-5678");		// key 가 null 인 상태
		// 런타임 에러  NullPointerException

		// 중복된 key 입력
		ht.put("강혜성", "010-1111-1111");

		System.out.println(ht.get("강혜성"));
		System.out.println();
		// 010-1111-1111
		// 중복된 key 를 활용하여 데이터를 입력할 경우 기존 "010-6380-7047"에서
		// "010-1111-1111"로 변경되었음을 확인 -> 덮어쓰기 개념


		// 중복된 value 입력
		ht.put("김지민","010-8972-1901");

		System.out.println(ht.get("김다슬"));
		System.out.println(ht.get("김지민"));
		// 010-8972-1901
		// 010-8972-1901
		// value 는 중복된 값이 입력되더라도 기존 데이터에 아무런 영향을 미치지 않음.

	}
}

Map 인터페이스(171)

/*================================
  ■■■ 컬렉션(Collection) ■■■
=================================*/

// Map -> Hashtable, HashMap

/*
○ java.util.Map 인터페이스
   키(Key)를 값(value)에 매핑(mapping) 하며 동일한 키를 등록할 수 없고, 유일해야 하며,
   각 키는 한 개의 값만을 매핑해야 한다. 즉, 하나의 키에 대응하는 하나의 값을 갖는 구조이다.


○ HashMap<K, V> 클래스

   - HashMap 클래스는 Hashtable 클래스와 마찬가지로 Map 인터페이스를 상속받아 주요 기능이 같지만
     Synchronization 이 없기 때문에 동시성 문제가 없다면 (즉, 멀티 스레드 프로그램이 아닌 경우라면)
	 HashMap 을 사용하는 것이 성능을 향상시킬 수 있다.
   - 또한, HashMap 은 Hashtable 과 달리 null 을 허용한다.
*/

import java.util.HashMap;
import java.util.Map;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class Test171
{
	public static void main(String[] args) throws IOException
	{
		// HashMap 자료구조 생성
		// HashMap<String, String> map = new HashMap<String, String>();
		Map<String, String> map = new HashMap<String, String>();

		// map 이라는 HashMap 자료구조에 요소 추가
		// -> put();
		map.put("영화", "거미집");
		map.put("드라마", "무빙");
		map.put("만화", "슬랩덩크");
		map.put("소설", "지구끝의온실");

		// 테스트(확인) -> 더미 확인
		// System.out.println(map);
		// {소설=지구끝의온실, 드라마=무빙, 영화=거미집, 만화=슬랩덩크}
		// 데이터 매핑 구조 확인
		// 데이터 요소 격납 순서가 추가 순서와 관계 없음


		// ※ null 관련 처리
			
		map.put(null, null);			// key 와 value 가 모두 null
	
		// 테스트(확인) -> 더미 확인
		System.out.println(map);
		// {소설=지구끝의온실, null=null, 드라마=무빙, 영화=거미집, 만화=슬랩덩크}

		map.put("동화", null);			// value 가 null

		// 테스트 -> 더미 확인
		System.out.println(map);
		// {소설=지구끝의온실, null=null, 드라마=무빙, 영화=거미집, 동화=null, 만화=슬랩덩크}

		map.put(null, "모나리자");		// key 가 null

		// 테스트 -> 더미 확인
		System.out.println(map);
		// {소설=지구끝의온실, null=모나리자, 드라마=무빙, 영화=거미집, 동화=null, 만화=슬랩덩크}
		// null=null 이 null=모나리자 로 바뀐 모습 확인 가능
		// null 도 하나의 key 와 value 로 간주된다.

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		System.out.print("카테고리,타이틀 입력(컴마 구분) : ");
		String[] temp;

		for(String str; ((str = br.readLine()) != null); )
		{
			temp = str.split(",");
			if(temp.length < 2)
			{
				System.out.print("카테고리, 타이틀 입력(컴마 구분) : ");
				continue;
			}

			map.put(temp[0].trim(), temp[1].trim());
			System.out.println(map);
			// 카테고리,타이틀 입력(컴마 구분) : 소설,어린왕자
			// {소설=어린왕자, null=모나리자, 드라마=무빙, 영화=거미집, 동화=null, 만화=슬랩덩크}
			// 드라마,힙하게
			// {소설=어린왕자, null=모나리자, 드라마=힙하게, 영화=거미집, 동화=null, 만화=슬랩덩크}
			// 영화,잠
			// {소설=어린왕자, null=모나리자, 드라마=힙하게, 영화=잠, 동화=null, 만화=슬랩덩크}

		}

	}
}

자바의 기본 입출력(172)

/*=====================================
  ■■■ 자바의 기본 입출력(I/O) ■■■
=====================================*/

// Test174.java 파일과 비교

/*
○ 자바의 기본 입출력 개요

   - 자바에서의 모든 데이터의 입출력은 스트림(stream) 이라는 개념에 의해 이루어지는데, 스트림(Stream)
     이라는 단어의 사전적 의미는 "흐르는 물"의 개념이며, 이는 연속된 일련의 데이터를 일컫는다.
	 (대상과 형태는 상관없다)
   
   - 데이터 입출력 시 모든 데이터를 형태와 관계없이 일련의 흐름으로 전송을 하는 것이 스트림 입출력
     모델의 기본 개념이다.

   - 기본적으로 스트림(stream)에는 바이트 기반 스트림과 문자 기반 스트림이 있다.
	-> 입력스트림(바이트, 문자) 출력스트림(바이트, 문자)

○ 바이트 스트림(byte - stream) 입출력

   - InputStream 클래스와 OutputStream 클래스, 그리고 이들의 하위 클래스를 통해서 제공되는 바이트 스트림
     (byte-stream)을 위한 표준 입출력으로 8비트 크기를 갖는 바이트들의 스트림이 입출력된다.
	 (바이트, 바이트배열, 정수 등)

○ 문자 스트림(character-stream) 입출력

   - Reader 클래스와 Writer 클래스, 그리고 이들의 하위 클래스에 의해 구현되었으며, 8비트 크기를 갖는 바이트
     들의 스트림이 아닌 16비트 크기를 갖는 유니코드 문자들의 스트림이라는 점에서 차이가 있다.
	 (문자, 문자배열, 문자열 등)

※ 스트림(stream)의 특징

   - 스트림은 FIFO 구조이다.
     FIFO 구조란, 먼저 들어간 것이 먼저 나오는 형태로 스트림의 데이터는 순차적으로 흘러가며 순차적 접근 밖에는
	 허용되지 않는다.

   - 스트림은 단방향이다.
     자바에서 스트림은 읽기 쓰기가 동시에 이루어지지 않는다.
	 따라서 읽기 쓰기가 필요하다면 읽는 스트림과 쓰는 스트림을 하나씩 열어서 사용해야 한다.

   - 스트림은 지연될 수 있다. 
     스트림에 넣어진 데이터는 처리되기 전에는 스트림에 사용하는 스레드는 지연(blocking) 상태에 빠진다.
	 네트워크 상에서는 데이터가 모두 전송되기 전까지 스레드는 지연(blocking) 상태가 된다.
*/

import java.io.IOException;

public class Test172
{
	public static void main(String[] args) throws IOException
	{
		int data;
		char ch;

		System.out.println("문자열 입력(종료:Ctrl+z)");
		
		// read() : InputStream 클래스의 대표적 메소드(-> 바이트 스트림)
		while ((data = System.in.read()) != -1)		
		// 문자열을 입력하라고 했지만 System.in.read()는 한 개만 읽고 int형 data에 아스키코드형으로 저장된다.
		{
			ch = (char)data;

			// System.out.print(ch);		// -> 문자 스트림
			// 문자열 입력(종료:Ctrl+z)
			// ABCD
			// ABCD
			// abcd
			// abcd
			// 123
			// 123
			// 한글
			// ??±?
			// ^Z
			// 계속하려면 아무 키나 누르십시오 . . .	읽어내는건 바이트로 받고 내보내는건 문자로 내보내니 깨지는 것
			
			// write() : OutputStream 클래스의 대표적 메소드(-> 바이트 스트림)
			System.out.write(ch);
			// 문자열 입력(종료:Ctrl+z)
			// abcd
			// abcd
			// ABCD
			// ABCD
			// 1234
			// 1234
			// 가나다라
			// 가나다라
			// ^Z
			// 계속하려면 아무 키나 누르십시오 . . .
		}
	}
}

OutputStream 실습(173)

/*======================================
  ■■■ 자바의 기본 입출력(I/O) ■■■
  - OutputStream 실습
======================================*/

import java.io.OutputStream;
import java.io.IOException;

public class Test173
{
	public static void main(String[] args) throws IOException
	{
		// ※ System.in   : 자바의 표준 입력 스트림(하나의 객체라.찍고 메소드 호출이 가능한 것)
		//    System.out  : 자바의 표준 출력 스트림
		OutputStream out = System.out;

		// 배열 구성
		byte[] ch = new byte[3];
		
		
		ch[0] = 65;				// A
		ch[1] = 97;				// a
		ch[2] = 122;			// z
		
		/*
		out.write(65);
		out.write(ch[0]);			// 매개변수로 ch[0]을 넣나 65를 넣나 출력이 안된다
		out.write(97);
		out.write(122);
		*/

		out.write(ch);				// 밖으로 내보낼 데이터(배열)를 스트림(물줄기)에 기록

		out.flush();				// 기록된 스트림을 내보내는(밀어내는) 기능을 수행
									// 지금은 Buffer 를 활용하지 않고 있는 상황이기 때문에
									// 생략이 가능한 코드.
									// (Buffered 되어있는 스트림(Stream)일 경우 생략 불가)

		out.close();				// 객체의 리소스를 반납해서 이 객체는 쓰지 않겠다라는 의미로 쓰임
									// 출력 스트림(물줄기)에 대한 리소스 반납
									// (out 스트림을(물줄기 수도꼭지를) 잠가버린 상황)


		System.out.println("절대적인 신뢰를 갖고 있는 구문"); 
		// 물줄기를 잠근 후 출력하려고 하기 때문에 나오지 않는다.
		// out.close() 를 작성한 이후 출력되지 않는 구문.

	}
}

Reader 실습(174)

/*======================================
  ■■■ 자바의 기본 입출력(I/O) ■■■
  - Reader 실습
======================================*/

// Test172.java 파일과 비교
/*
new BufferedReader(System.in)
					--------
	--------------   바이트기반으로 읽어들이는 스트림	
		  ↓
	문자기반 스트림들은 뒤에(reader / writer)가 붙어있다

	바이트기반으로 읽어들이는 것을 문자기반 스트림으로 바로 넘겨버리면 문제가 생기는데


new BufferedReader(new InputStreamReader(System.in))
					-------------------
					바이트 기반의 스트림을 문자기반의 스트림으로 번역하는 역할
					(InputStream 까지만 하면 바이트기반이다 말 그대로 바이트기반을 읽는 역할)
					---------------------------------
					  번역해서 문자기반의 스트림이 됨
*/

import java.io.InputStreamReader;
import java.io.Reader;
import java.io.IOException;

public class Test174
{
	public static void main(String[] args) throws IOException
	{
		int data;
		char ch;
		
		// System.in		 : 자바의 표준 입력 스트림 -> 바이트 기반 스트림
		// InputStreamReader : 바이트 기반 스트림을 문자 기반 스트림으로 변환을 해주는 역할 
		// Reader			 : 문자 기반 스트림 객체
		Reader rd = new InputStreamReader(System.in);

		System.out.println("문자열 입력(종료:Ctrl+z)");

		while ((data = rd.read()) != -1)
		{
			ch = (char)data;

			System.out.print(ch);
			// 문자열 입력(종료:Ctrl+z)
			// rkskekfk
			// rkskekfk
			// 가나다라
			// 가나다라
			// 1234
			// 1234
			// ASDS
			// ASDS
			// ^Z
			// 계속하려면...

			//System.out.write(ch); // 입력은 문자로 받고 내보내는건 바이트로 내보내니 문제가 생김
			// 문자열 입력(종료:Ctrl+z)
			// abcd
			// abcd
			// ABCD
			// ABCD
			// 123
			// 123
			// 가나다라
			//  섆|
			// ^Z
			// 계속하려면...
		}
	}
}

Buffered 관련 실습(175)

/*======================================
  ■■■ 자바의 기본 입출력(I/O) ■■■
  - Buffered 관련 실습
======================================*/
//import java.io.OutputStream;
import java.io.IOException;

public class Test175
{
	public static void main(String[] args) throws IOException
	{
		// System.out : 자바 기본 출력 스트림
		
		System.out.write(65);		// 'A'  
		System.out.write(66);		// 'B' 
		// -> 출력 안됨

		System.out.write(180);		// 
		System.out.write(235);		// 180 + 235 -> '대'
/*
		byte[] ch = new byte[3];
		
		ch[0] = 65;				// A
		ch[1] = 97;				// a
		ch[2] = 122;			// z
		System.out.write(ch);
*/
		// 여기까지 수행하면 아무것도 출력 안됨

		System.out.flush();			// 체크

		// ※ 출력 버퍼가 채워지지 않으면 출력할 데이터(자료)를 출력 디바이스(장치)로
		//    보내지 않기 때문에 flush() 메소드를 통해 아직 다 채워지지 않은 출력 버퍼의 내용
		//    을 출력 장치를 밀어내어 보낼 수 있도록 처리해야 한다.

		//    즉, 현재 구문에서는 System.out.flush(); 구문을 생략할 수 없다.

		//== AB대
	}
}

Reader Writer 관련 실습(176)

/*======================================
  ■■■ 자바의 기본 입출력(I/O) ■■■
  - Reader Writer 관련 실습
======================================*/

import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.io.IOException;

public class Test176
{
	public void process(InputStream is)			// System.in이 전달됨
	{
		int data;
		
		System.out.println("문자열 입력(종료:Ctrl+z)");

		try
		{	
			// 매개변수 is 라는 바이트 기반 스트림 객체(InputStream)를 문자 스트림으로 
			// 변환하여 (-> InputStreamReader 가 수행) Reader 타입의 타입 rd에서 참조할 수 있도록 처리

			Reader rd = new InputStreamReader(is);
			//-> 문자 기반 입력 스트림 rd

			// 바이트 기반 스트림 객체인 자바 기본 출력 스트림(System.out)을 문자 스트림으로
			// 변환하여(-> OutputStreamWriter 가 역할 수행) Writer 타입의 wt 에서 참조할 수 있도록 처리
			Writer wt = new OutputStreamWriter(System.out);
			//-> 문자 기반 출력 스트림 wt
			
			// 읽어들이는 스트림으로부터 하나씩 얻어내기
			while ((data = rd.read()) != -1)
			{
				wt.write(data);				// 내보내는 스트림(물줄기)에 data를 하나씩 기록
				wt.flush();					// 기록한 스트림(물줄기)를 밀어내어 내보냄
			}
		}
		catch (IOException e)
		{
			System.out.println(e.toString());
		}
		

	}

	public static void main(String[] args)
	{
		Test176 ob = new Test176();
		ob.process(System.in);
		// 문자열 입력(종료:Ctrl+z)
		// 1234567
		// 1234567
		// abcd
		// abcd
		// ABCDE
		// ABCDE
		// 가나다라마바사
		// 가나다라마바사
		// ^Z
		// 계속하려면
	}
}

객체직렬화 (177)

/*==============================================
  ■■■ 객체 직렬화(Object Serialization ■■■
===============================================*/

/*
○ 객체 직렬화(Object Serialization)는
    
   메모리에 생성된 클래스 객체의 멤버 변수의 현재 상태를 그대로 보존해서 파일에 저장하거나
   네트워크를 통해 전달할 수 있는 기능으로 멤버 변수의 값을 보존한다거나 다른 네트워크에 있는
   호스트에 값을 보낼 경우 사용하게 된다.

   즉, 객체 직렬화는 내용물을 바이트 단위로 변환하여 파일 또는 네트워크를 통해 송수신(스트링)이
   가능하게 만들어주는 것으로 이 때, 객체란 멤버 변수의 메모리만으로 구성된 것을 말한다.

   따라서, 메소드와 생성자는 객체 직렬화의 대상에서 제외된다.


○ 객체 직렬화의 장점

   객체 자체의 내용을 입출력 형식에 구애받지 않고 객체를 파일에 저장함으로써 영속성을 제공할 수 있으며
   객체 자체를 네트워크를 통해 손쉽게 교환(송수신)할 수 있게 된다.

   객체 직렬화는 자바 1.1 이후에 도입되었는데 그 이유는 RMI 와 Bean 때문이었다. RMI 는 원래 객체 통신을
   지원해야 하기 때문에 객체가 그대로(특정 상태를 유지한 채로) 이동할 수 있어야 한다.
   따라서 이를 지원하기 위해서는 객체 직렬화가 필수적이었다.

   또한, Bean 은 설계 시 상태에 대한 정보를 저장할 때 이 객체 직렬화를 사용하면 편하게 객체 상태를 저장
   할 수 있다.

   ※ RMI(Remote Method Inovocation)
      서로 다른 가상 기계장치에 존재하는 함수를 호출하고 실행하는 기능을 담당한다.
	  서로 다른 통신 구조에 위치한 각각의 원격 객체들 간의 통신 구조를 지원하는 개념으로 이해하면 좋겠다.

   ※ Bean(빈, 자바 빈)
      C/S(Client, Server) 구조적 모델에서 서버측 구조에 해당하며, 재사용 가능한 소프트웨어 개체를 만들 수
	  있게 하는 컴포넌트 기술. 작성된 개체의 공유가 가능하며 프로젝트에 쉽게 포함시킬 수 있도록 한다.
	  클라이언트에게 빈이라는 프로그램 컴포넌트를 분배하는 방식으로 처리.

○ Serialiazable 인터페이스
  
   객체 직렬화를 하기 위해 먼저 객체 직렬화가 가능하도록 java.io.Serializable 인터페이스를 구현해 주어야 한다.
   이 인터페이스는 객체 직렬화가 제공되어야 한다는 사실을 JVM에 알려주는 역할을 수행한다. 또한,
   Serialiazable 인터페이스는 다른 인터페이스와 달리 구현해야 할 메소드가 없기 때문에 단지 선언만 해주면 된다.

   형식)
   1.
   public class 클래스명 implements Serialiazble
   {
	   ...
	   }

   2.										(이 둘을 포함해서 ObjectStream이라고 한다 객체 입출력 스트림)
   Serializable 인터페이스를 구현한 후 ObjectInputStream 클래스와 ObjectOutputStream 클래스를 이용하여
   객체 단위로 입출력을 수행하게 된다.

   ※ 멤버 변수가 static으로 선언된 경우(즉, 클래스 변수일 경우)
      객체 직렬화의 대상에서 제외된다.


○ Object Stream

   java.io.ObjectInputStream 클래스는 java.io.ObjectOutputStream 클래스(바이트기반)에 
   의해 파일에 저장되어 있는 객체나 네트워크를 통해 전달된 객체의 직렬화를 해제하는 기능을 제공한다.
   단, java.io.Serializable 인터페이스와 java.io.Serializable 인터페이스를 지원해주는 객체에 대해서만 
   사용이 가능하다.
   즉, Serializable 인터페이스와 Externalizable 인터페이스를 구현한 객체에서만 사용이 가능하다는 것이다.
   이 떄, readObject() 메소드를 이용하여 스트림으로 직렬화된 객체를 읽을 수 있으며 이렇게 읽은 객체는
   배열, 문자열 또는 각 객체 등 원래의 형(Type)으로 캐스팅 해 주어야 한다. 


*/

import java.io.File;
import java.util.Hashtable;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;

import java.io.FileInputStream;
import java.io.ObjectInputStream;
//import java.util.Hashtable;
import java.util.Enumeration;

public class Test177
{
	public static void main(String[] args) throws Exception
	{
		// 시스템 속성으로부터 현재 사용자가 사용중인 디렉터리 정보 얻어오기
		String appDir = System.getProperty("user.dir");

		// System.out.println(appDir);
		// C:\JavaStudy   <- 현재 Test177이라는 클래스가 어디서 작업되고 있는지 확인하는 것
		
		// 파일 객체 생성
		File f0 = new File(appDir, "\\data\\test.ser"); // 역슬러쉬 \\가 \로 처리됨
		// appDir -> C:\JavaStudy
		// appDir 위치를 기준으로(중심으로) "\\data\\test.ser"를 구성하겠다는 의미
		// 결과적으로 C:\JavaStudy\data\test.ser 구성.

		// 테스트(확인)
		// System.out.println(f0.getParentFile().exists()); 
		// false
		// test.ser 파일이 만들어지게 될 디렉터리 경로가 구성되어 있지 않다.

		// ※ C:\JavaStudy 경로에 data 디렉토리 생성해줘야 함

		// 생성 이후 다시 테스트
		// System.out.println(f0.getParentFile().exists());
		// true
		// test.ser 파일이 만들어지게 될 디렉터리 경로가 구성되어 있다.

		// test.ser 파일이 만들어지게 될 디렉터리 경로가 구성되어 있지 않다면
		if(!f0.getParentFile().exists())
		{
			// 디렉토리를 만들겠다.(생성하겠다.)
			f0.getParentFile().mkdirs();		// makedirectories
		}

		// Hashtable 자료구조 인스턴스 생성
		Hashtable<String, String> h1 = new Hashtable<String, String>();

		// 생성한 h1이라는 Hashtable 자료구조에 요소 추가
		h1.put("2308112", "노노노");
		h1.put("2308103", "문문문");
		h1.put("2308115", "박가가");
		h1.put("2308107", "박나나");
		h1.put("2308136", "박범범");

		// 테스트 
		// System.out.println(h1.get("2308107"));
		// 박나나
		

		// 파일 전용 출력 스트림 생성(수도꼭지 열기) -> 예외처리 해줘야함
		FileOutputStream fos = new FileOutputStream(f0);
		// 파일 전용 출력 스트림(물줄기)에 f0라는 파일 객체를 띄우겠다.
		// InputStreamReader isr = new InputStreamReader(System.in); 과 같은 의미

		// 객체 전용 출력 스트림 생성
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		// 객체 전용 출력 스트림(물줄기)으로 fos 라는 파일 전용 출력 스트림을 감싸겠다.
		// BufferedReader br = new BufferedReader(isr); 과 동일한 구조

		// ObjectOutputStream oos = new ObjectOutputStream(new fileOutputStream(f0));
		
		// ※ ObjectOutputStream 클래스는
		//    객체들을 출력하는 기능을 제공하는 클래스로 출력 스트림에 출력하기 전에 내부적으로
		//    객체 직렬화를 수행하게 된다. 자바 기본 데이터 또는 객체들을 파일에 저장하거나
		//	  네트워크를 통해 전달하기 위해 전달할 객체를 직렬화하는 기능을 제공하는 것이다.
		
		// 생성된 스트림에 내보낼 객체를 기록
		oos.writeObject(h1);
		// out.write(ch); 와 같은 개념의 구문

		// 객체 전용 리소스 반납
		oos.close();
		// ObjectOutputStream 리소스 반납

		//파일 전용 리소스 반납 
		fos.close();
		// FileOutputStream 리소스 반납



		// (객체를 직렬화하여 파일로) 내보내기 끝 (여기까지 직렬화)
		//-------------------------------------------------------------------------------------------------


		// (객체를 직렬화하여 내보낸 파일) 읽어들이기 시작~!!!

		// f0 파일 객체가 존재한다면...
		if(f0.exists())
		{
			// f0 파일을 파일 입력 스트림(fis, FileInputStream)으로 읽어들이고 
			FileInputStream fis = new FileInputStream(f0);
			
			// fis 파일 입력스트림으로부터 객체 입력 스트림(ois, ObjectInputStream)을 얻어내어
			ObjectInputStream ois = new ObjectInputStream(fis);

			// 객체 입력 스트림(ois, ObjectInputStream)으로부터 읽어들인 객체(Object)를
			// 캐스팅(Hashtable)하여 h2 라는 자료구조에 담아내기
			// Object obj = ois.readObject();  // Object타입으로 읽어들임
			Hashtable h2 = (Hashtable)ois.readObject();

			ois.close();
			// ois, ObjectInputStream 리소스 반납

			fis.close();
			// fis, FileInputStream 리소스 반납

			// ----------------------------여기까지 수행하면 읽어들이는 작업 끝

			// 읽어들인 h2 객체의 내용 확인

			String key;
			String value;

			// ※ Iterator 사용할 수 없음(Hashtable)

			Enumeration e = h2.keys();

			while (e.hasMoreElements())
			{
				key = (String)e.nextElement();
				// Hashtable 자료구조를 대상으로 key를 읽어들이는 과정

				// 테스트
				// System.out.println(key);
				// 2308136
				// 2308115
				// 2308107
				// 2308112
				// 2308103

				value = (String)h2.get(key);    // value 얻어내기
				// Hashtable 자료구조를 대상으로 key 를 활용하여 value를 얻어내는 과정

				System.out.println(key + " → " + value);
				// 2308136 → 박범범
				// 2308115 → 박가가
				// 2308107 → 박나나
				// 2308112 → 노노노
				// 2308103 → 문문문
			}

		}
	}
}

0개의 댓글