Day38 실습프로젝트(File I/O)
Stack 리팩토링 - menuPath
1. 기존 스택의 문제점
- ```java //기존 menuGroup에서 Stack이 사용되는 소스코드 public MenuGroup(String title) { super(title); this.menuPath = new Stack<>(); } public void setParent(MenuGroup parent) { this.parent = parent; this.menuPath = parent.menuPath; } private String getMenuPathTitle(Stack
- 기존 소스코드에서 Stack은 menuGroup이 인스턴스 될 때마다 새로운 Stack을 생성한다.
- 부모의 menuGroup이 있다면 인스턴스된 Stack은 Garbage가 된다.
- menuPath를 호출하는 메서드는 Stack의 구조로 꺼내는 것이 아니라 List타입으로 탐색을 한다. </ul>
2. 스택 구조 변경
- 현재 위치의 menuTitle을 push한다.
- 부모가 있다면 부모의 menuPath로 이동한다.
- root의 부모인 null를 만날때 까지 1~2를 반복한다.  ```java public MenuGroup(String title) { super(title); } public void setParent(MenuGroup parent) { this.parent = parent; } private String getMenuPath() { Stack
menuPath = new Stack<>(); MenuGroup menuGroup = this; while (menuGroup != null) { menuPath.push(menuGroup.title); menuGroup = menuGroup.parent; } StringBuilder strBuilder = new StringBuilder(); while (!menuPath.empty()) { if (!strBuilder.isEmpty()){ strBuilder.append("/"); } strBuilder.append(menuPath.pop()); } return strBuilder.toString(); } ``` </ol> 파일 입출력 FILE I/O
1. 바이너리 데이터 입출력
- 바이너리 타입의 입력은 텍스트 타입 보다 메모리를 적게사용하고, 속도가 빠르다.
- 타입별로 인코딩하는 방식이 다르다.
- "abc" --> UTF-8 문자코드 바이트
- 20 --> 2의 보수
- 3.14 --> IEEE-754 규칙
- true --> 2의 보수
- 설정 방법이 복잡하다.
- PDF, PPT, DOC, GIF, JPEG, MP3, AVI 등이 있다.
2. 데이터 입출력 적용
1) 데이터 입출력 흐름
- 
2) byte[] 만들기
- 객체를 byete[] 배열에 1바이트씩 담아야한다.
- ByteArrayOutputStream 클래스를 이용하여 바이트배열 담을 저장소를 만든다.
- 이후 toByteArray()메서드로 통해 바이트 배열을 리턴 할 수 있다. ```java public byte[] getBytes() throws IOException { try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { //객체의 정보들을 byte로 담는다. return out.toByteArray(); } } ```
3) write(int) 메소드
- 객체를 byete[] 배열에 1바이트씩 담을때 write 메서드를 사용한다.
- write(int) int 타입을 받지만 1바이트만 읽고 저장할 수 있다.
- 비트 연산자를 통해 바이트를 1바이트까지 이동 해야한다. ```java ByteArrayOutputStream out = new ByteArrayOutputStream() out.write(no >> 24); out.write(no >> 16); out.write(no >> 8); out.write(no); ```
4) 데이터 구조
- 데이터의 구조에 따라 바이트의 할당규칙을 정해야 load과정에서 해당규칙을 통해 값을 읽을 수 있다.  ```java //유저정보를 바이트배열로 변환 public byte[] getBytes() throws IOException { try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { //회원번호 넣기 out.write(no >> 24); out.write(no >> 16); out.write(no >> 8); out.write(no); //이름 넣기 byte[] bytes = name.getBytes(StandardCharsets.UTF_8); out.write(bytes.length >> 8); out.write(bytes.length); out.write(bytes); //이메일 넣기 bytes = email.getBytes(StandardCharsets.UTF_8); out.write(bytes.length >> 8); out.write(bytes.length); out.write(bytes); //password bytes = password.getBytes(StandardCharsets.UTF_8); out.write(bytes.length >> 8); out.write(bytes.length); out.write(bytes); //tel bytes = tel.getBytes(StandardCharsets.UTF_8); out.write(bytes.length >> 8); out.write(bytes.length); out.write(bytes); return out.toByteArray(); } } ```
5) 파일로 출력
- 데이터의 구조에 따라 바이트배열들을 병합하고 객체의 전체 개수를 구한다 .
- FileOutputStream에 바이트의 배열들 개수를 넣고 저장한 바이트 배열들을 넣는다.  ```java //바이트배열로 변환된 유저정보를 파일로 출력 private void saveUser() { try (FileOutputStream out = new FileOutputStream("user.data")) { int userLength = userList.size(); out.write(userLength >> 8); out.write(userLength); for (User user : userList) { byte[] bytes = user.getBytes(); out.write(bytes.length >> 8); out.write(bytes.length); out.write(bytes); } } catch (IOException e) { System.out.println("회원 정보 저장 중 오류 발생" + e.getMessage()); } } ```
6) 파일로 입력
- 입력은 출력과정의 역순으로 진행한다.  ```java //파일을 테이터 배열로 전환 private void loadUser() { try (FileInputStream in = new FileInputStream("user.data")) { int userLength = in.read() << 8 | in.read(); int maxUserNum = 0; for (int i = 0; i < userLength; i++) { int len = (in.read() << 8) | in.read(); byte[] bytes = new byte[len]; in.read(bytes); User user = User.valueOf(bytes); userList.add(user); maxUserNum = Math.max(maxUserNum, user.getNo()); } User.initSeqNo(maxUserNum); } catch (IOException e) { System.out.println("회원 정보 로딩 중 오류 발생" + e.getMessage()); } } // 데이터 배열을 유저 객체로 전환 public static User valueOf(byte[] bytes) throws IOException { try (ByteArrayInputStream in = new ByteArrayInputStream(bytes)) { User user = new User(); user.setNo(in.read() << 24 | in.read() << 16 | in.read() << 8 | in.read()); byte[] buffer = new byte[10000]; int len = in.read() << 8 | in.read(); in.read(buffer, 0, len); user.setName(new String(buffer, 0, len, StandardCharsets.UTF_8)); len = in.read() << 8 | in.read(); in.read(buffer, 0, len); user.setEmail(new String(buffer, 0, len, StandardCharsets.UTF_8)); len = in.read() << 8 | in.read(); in.read(buffer, 0, len); user.setPassword(new String(buffer, 0, len, StandardCharsets.UTF_8)); len = in.read() << 8 | in.read(); in.read(buffer, 0, len); user.setTel(new String(buffer, 0, len, StandardCharsets.UTF_8)); return user; } } ```
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.