---
title: "Java 정리 27"
date: "2018-12-19"
tags: ["Java"]
status: archived
verified: false
---

## Java 정리 27 - IO Stream(1)

---

### IO(Input/ Output) Stream

* **JVM 외부에 존재하는 데이터를 처리하기 위해 사용하는 클래스들**
* **java.io 패키지**에서 관련 클래스를 제공
* **단방향 IO**
  * 읽기 스트림은 읽기만, 쓰기 스트림은 쓰기만 가능
* **8bit Stream, 16bit Stream 두가지** 제공
  * **8bit Stream (byte기반 스트림)**
    * 모든 데이터를 읽고 쓸 수 있음
  * **16bit Stream (문자열기반 스트림)**
    * 문자열 데이터만 읽고 쓸 수 있음

![01](/md/legacy-assets/java/27/01.webp)

* 클래스 이름뒤에 **Input,OutStream**이면 **8bit**, **Reader,Writer**면 **16bit Stream**
* **Input, OutputStream을 부모로 두면 8bit Stream**
	* Data**InputStream** / Data**OutputStream**
	* File**InputStream** / File**OutputStream**
	* Object**InputStream** / Object**OutputStream**
	* ...
* **Reader, Writer를 부모로 두면 16bit Stream**
	* Buffered**Reader** / Buffered**Writer**
	* File**Reader** / File**Writer**
	* InputStream**Reader** / OutputStream**Writer**
	* ...
* 8bit Stream과 16bit Stream은 **결합하여 사용할 수 있다.**
  * **8bit와 16bit를 같이쓰면 속도가 보완이 된다.**
  * **8bit Stream이 속도가 빠름**
  	* 데이터의 양은 적다.
  * **16bit Stream**은 속도가 느림
  	* **데이터의 양은 많다.**

---

### 입력 Stream

![02](/md/legacy-assets/java/27/02.webp)

* **JVM이 시작될 때** 자동으로 **표준 error OutputStream, 표준 input InputStream, out OutputStream 이 생성**된다.
  * 이 표준 Stream을 close하면 JVM을 다시 실행할때까지 다시 Stream 연결을 못함
* 키보드로 입력하면 **메인보드 Keyboard Buffer**에 값이 들어가짐
  * 버퍼의 크기는 256(0~255), 크기만큼 입력 가능
  * **Enter가 떨어지면 Buffer 내용이 OS로 전달됨**
    * cpu에 따라 입력순서를 그대로 처리하는 **Little Endian**, 입력순서를 거꾸로 처리하는 **Big Endian** 처리방식(RISC 계열 cpu(MAC계열) )이 존재.
    * 인텔계열 cpu는 Little Endian 방식
  * OS에 전달된 키입력 내용은 **JVM의 System.in(InputStream)을 통해 JVM으로 들어오게 되고** JVM에 존재하는 **instance는 InputStream의 read() 를 통해 해당 값을 읽어올 수 있다.**

![03](/md/legacy-assets/java/27/03.webp)

---

### 키보드 입력 처리

* **System.in**
  * **in은 InputStream**
  * read()로 키보드로 입력된 내용을 읽어들일 수 있다. 

```java
// 입력 값 중 최초 입력 문자 받기
public class UseKeyboardInput {
     public UseKeyboardInput() {
          System.out.println("아무키나 누르고 엔터");
          try {
              int input = System.in.read();
              System.out.println("입력값 : " + input);

          } catch (IOException e) {
              e.printStackTrace();
          }
     }
     public static void main(String[] args) {
          new UseKeyboardInput();
     }
}
```

![04](/md/legacy-assets/java/27/04.webp)

```java
// 여러 단어 입력받기
public class UseKeyboardInput {
     public UseKeyboardInput() {
          System.out.println("아무키나 누르고 엔터");
          try {
              int input = 0;
              while(true) {
                   input = System.in.read();
                   
                   System.out.print((char)input);
                   
                   // enter는 13, 13나오면 종료
                   if (input == 13) {
                        break;
                   }
              }
          } catch (IOException e) {
              e.printStackTrace();
          }
     }
     public static void main(String[] args) {
          new UseKeyboardInput();
     }
}
```

![05](/md/legacy-assets/java/27/05.webp)

![06](/md/legacy-assets/java/27/06.webp)

* 위에 입력을 찍어보면 **윈도우는 엔터 입력 시 \r\n이 함께 입력됨**
	* **\r (Carriage Return)** : 그 줄 맨 앞으로 이동
	* **\n (Line Feed)** : 다음 줄로 이동
* **한글 입력받기**
	* 한글을 입력받기위해선 **8bit과 16bit Stream을 연결해야 한다.**
		* 한글은 8bit Stream을 사용하면 깨짐, **16bit Stream은 안깨짐**
		* 두 Stream의 크기가 달라 바로 연결 못함
			* **두 Stream을 연결하는 Stream이 필요**

![07](/md/legacy-assets/java/27/07.webp)

```java
InputStream is = System.in;
InputStreamReader isr = new InputStreamReader(is); // has-a 
BufferedReader br = new BufferedReader(isr);       // is-a
```

![08](/md/legacy-assets/java/27/08.webp)


* **InputStreamReader**
  * **8bit-16bit Stream 결합**
  * 읽어들인 **charset**을 변환(파라미터 2개받는 생성자 사용시)
* **BufferedReader**
  * **속도개선**
  * **줄단위로 읽는 기능(readLine())**

```java
// 한줄로 바꾼다면
BufferedReader br = new BufferedReader(
    new InputStreamReader(System.in));

try {
    // br의 readLine()을 사용하면 한줄 읽어서
    String s = br.readLine();
} catch (IOException ie) {
    ie.printStackTrace();
}

// 사용 후 연결을 끊어야 한다.
br.close();
```

```java
public class UseKeyboardInput {
     public UseKeyboardInput() {
          System.out.println("아무키나 누르고 엔터");
          
          // 8bit Stream과 16bit Stream을 연결
          BufferedReader br = new BufferedReader(
                        new  InputStreamReader(System.in));
          
          try {
              // 16bit Stream을 사용하여 입력된 데이터를 줄단위로 읽어 들인다.
              String s = br.readLine();
              System.out.println(s);
              
              // 스트림 사용이 끝났으면 스트림의 연결을 끊는다.
              br.close();

          } catch (IOException ie) {
              ie.printStackTrace();
          }
     }
     public static void main(String[] args) {
          new UseKeyboardInput();
     }
}
```

![09](/md/legacy-assets/java/27/09.webp)

---

### File 입력 처리

* **FileInputStream**
  * **8bit**
  * **모든 형식의 파일**을 읽어들일 수 있다.
    * 이미지, 동영상, 문서열
    * 파일을 복사할때 사용
      * 웹에서 파일 첨부
* **FileReader**
  * **16bit**
  * **독자 포맷으로 만들어지지 않은 문자열 파일만** 읽어들일 수 있다.
    * txt (hwp, doc 등은 읽어들일 수 없다.)

---

### 파일시스템


* **FAT**
  * **File Allocation Table**
  * 단일파일로 4GB까지만 저장됨
  * USB에 파일포맷이 이거면 4GB 이상 파일을 넣을 수 없음
* **NTFS**
  * **NTFS (New Technology File System)**
  * FAT 파일 시스템을 개선하여 만든 새로운 파일 시스템
* **exFAT**
  * **Extended File Allocation Table**

---

### Character Set

* **EUC-KR**
    * 한글 인코딩 방식 중 하나, **현재 산업 표준**
    * 글자 코드 세트에 쓸 문자를 현대 한국어에서 빈도가 높은 한글을 추려내어 '가'부터 '힝'까지 배당한 후 문자를 기록하는 방식
    * **과거에 사용빈도가 많은 단어를 토대로 만듦**
      * '아햏햏'같은 단어는 사용을 못함, '햏'이란 문자가 없기 때문에 사용을 못함.
    * 초기 MS Office가 EUC-KR기반이었다
        * 문서가 저장 안되는 문제가 발생
        * MS에서 해결하고자 만들어줌 **MS949(CP949)**
* **CP949 (code page 949)**
    * MS Windows의 기본 코드 페이지
    * 한글 인코딩의 한 종류, **EUC-KR의 확장형**
* **UTF-8**
    * 유니코드를 위한 가변 길이 문자열 인코딩 방식 중 하나
    * Universal Coded Character Set + Transformation Format - 8bit의 약자
    * **한글은 3byte로 표기**

---

### File

* **java.io 패키지에서 제공하는 클래스**
* **File에 대한 정보를 얻는 일**
* **Directory를 생성**
* **File 삭제**

```java
// 생성
File file = new File("경로");

// 길이(크기)
long l = file.length(); // byte로 반환, 정수보다 큰 값을 반환가능하므로 long

// 파일인지 확인할 때
file.isFile();

// 폴더인지 확인할 때
file.isDirectory();

// 읽기 가능한지 확인할 때
file.canRead();

// 쓰기 가능한지 확인할 때 
file.canWrite();

// 실행 가능한지 확인할 때
file.canExecute();

// 숨김파일인지 확인할 때
file.isHidden();

// 폴더 내 모든 폴더/파일을 얻기
File[] f = file.listFiles();

// 파일 삭제
file.delete();

// 디렉토리 생성
file.mkdir();  // root부터 생성하는 디렉토리는 생성불가(과거에, 현재는 mkdirs와 동일)
file.mkdirs(); // 어느 경로의 디렉토리든 생성가능

// 파일의 마지막 수정날짜
long date = file.lastModified();

// 파일의 경로
String path = file.getPath();

// 파일의 파일명
String fName = file.getName();

// 파일의 절대경로(AbsolutePath)
String aPath = file.getAbsolutePath(); // Drive 레터가 소문자, 대문자 다 됨

// 파일의 규범경로(CanonicalPath), 파일에 접근하는 유일한 경로
String cPath = file.getCanonicalPath(); // Drive 레터가 대문자만 가능

// 파일이 존재
file.exists();

// 파일명 변경
file.renameTo(변경할이름);
```

```java
// File method사용 예제
public class UseFile {
     public UseFile() {
          String path =  "c:/.../temp/java_read.txt";
          
          // 1. 생성
          File file = new File(path);
          System.out.println(file);
          
          if (file.exists()) { // 파일이 존재할 때
              System.out.println("절대 경로 :  "+file.getAbsolutePath());
              try {
                   System.out.println("규범 경로 :  "+file.getCanonicalPath());
              } catch (IOException e) {
                   e.printStackTrace();
              }
              System.out.println("경로 :  "+file.getPath());
              System.out.println("폴더명 :  "+file.getParent());
              System.out.println("파일명 :  "+file.getName());
              
               System.out.println(file.isFile()?"파일":"디렉토리");
               System.out.println(file.isDirectory()?"디렉토리":"파일");
              
              System.out.println("파일 길이 :  "+file.length()+" byte");
              System.out.println("실행  "+(file.canExecute()?"가능":"불가"));
              System.out.println("읽기  "+(file.canRead()?"가능":"불가"));
              System.out.println("쓰기  "+(file.canWrite()?"가능":"불가"));
              System.out.println(file.isHidden()?"숨긴파일":"일반파일");

              Date d = new Date(file.lastModified());
              SimpleDateFormat sdf = new  SimpleDateFormat("yyyy-MM-dd a HH:mm:ss");
              System.out.println("마지막 수정일 :  "+sdf.format(d));
              
          } else {
              System.out.println("경로를  확인해주세요.");
          }
     }
     public static void main(String[] args) {
          new UseFile();
     }
}
```

![10](/md/legacy-assets/java/27/10.webp)

```java
// File 생성, 삭제 예제
public class UseFile2 {
     
     public void createDirectory() {
          File file = new File("c:/young/oh");
          
          if (file.mkdir()) {
              System.out.println("폴더 생성 성공");
          } else {
              System.out.println("같은 이름의 폴더가  존재");
          }
     }
     
     public void removeFile() {
          File file = new  File("C:/.../temp/a.txt");
          boolean flag = file.delete();
          
          if (flag) {
              System.out.println("파일 삭제 성공");
          } else {
              System.out.println("파일 삭제 실패");
          }
     }
     
     public static void main(String[] args) {
          UseFile2 uf2 = new UseFile2();
          // uf2.createDirectory();
          uf2.removeFile();
     }
}
```

---

### File 내용 읽기

![11](/md/legacy-assets/java/27/11.webp)

* **File을 FileInputStream을 사용해서 read()로 1byte씩 읽어온다면 한글은 깨짐.**

```java
File f = new File(경로);
FileInputStream fis = new FileInputStream(f);

int i = 0;
while ((i = fis.read()) != -1) { // 읽어들인 내용이 있을 때까지 
    System.out.println(i);
}
```

---

### 숙제1

* 프로그램이 실행되면 콘솔에 "디렉토리명 입력 : " 메세지가 출력
* 사용자가 콘솔에 디렉토리 "예) c:/dev"를 입력
  * 입력값이 디렉토리라면 해당 디렉토리내 파일정보를 JOptionPane.showMessageDialog에 출력
  * 디렉토리가 아니라면 "파일은 취급하지 않습니다."를 콘솔에 출력

![12](/md/legacy-assets/java/27/12.webp)

* [숙제풀이1](https://github.com/younggeun0/SSangYoung/blob/master/dev/workspace/sistJavaStudy2/src/date181219/hw/FileHomework.java)

### 숙제2

* JOptionPane.showInputDialog를 사용하여 경로를 입력 받음
* 입력받은 경로에 확장자가 java인 파일이 존재한다면 JOptionPane.showConfirmDialog를 사용하여  삭제여부를 묻는다.
    * ConfirmDialog의 메세지는 "java 파일이 x개 존재합니다. 삭제하시겠습니까?" 
        * "예"를 누르면 해당 파일을 삭제
        * "아니오"나 "취소"가  눌려지면 종료

* [숙제풀이2](https://github.com/younggeun0/SSangYoung/blob/master/dev/workspace/sistJavaStudy2/src/date181219/hw/FileHomework2.java)

![13](/md/legacy-assets/java/27/13.webp)
