---
# System prepended metadata

title: Java IO
tags: [과외(기태)]

---

# Java IO

## IO란?

- 입력(Input)과 출력(Output)을 줄여 부르는 말
- 두 대상 간의 데이터를 주고 받는 것
- 예) 키보드를 통한 사용자 입력이나 화면에 결과를 출력하는 것 or 하드디스크의 파일을 읽거나 저장하는 것

### 어플리케이션이 HW에 접근하기까지

![image](https://hackmd.io/_uploads/rJqkE8d_2.png)

## Java I/O란?

- Java 프로그램이 데이터를 읽고 쓸 수 있게 해주는 기능.
  - 여기서 '데이터'는 사용자로부터의 입력, 파일, 네트워크 연결 등 다양한 형태를 가질 수 있다.
- Java에서 데이터 입출력을 위한 기능을 제공하는 패키지
- Java는 I/O 작업을 빠르게 하기 위해 스트림 개념을 사용한다.
  - `java.io` 패키지에는 입력 및 출력 작업에 필요한 모든 클래스가 포함되어 있다.
  - 예시: 파일에서 데이터를 읽어오는 작업은 `FileInputStream` 클래스를 사용하고, 콘솔로 데이터를 출력하는 작업은 `System.out.println()` 메서드를 사용한다.
- Java I/O API를 통해 Java에서 파일 처리를 수행할 수 있다

## Java I/O의 구성

- 자바 I/O는 크게 스트림(Stream)과 채널(Channel), 그리고 버퍼(Buffer) 등 세 가지 주요 요소로 구성되어 있다.
- '스트림'은 일련의 데이터를 표현하는 개념으로, 데이터가 프로그램에 들어오는 '입력 스트림'과 프로그램에서 나가는 '출력 스트림'으로 나뉜다.
- '채널'은 스트림과 비슷하지만, 읽기와 쓰기를 동시에 수행할 수 있으며, 비동기 I/O 작업을 지원한다.
- '버퍼'는 데이터를 임시적으로 저장하는 메모리 영역으로, 채널을 통해 데이터를 읽고 쓸 때 사용된다.

## Java I/O의 클래스 계층구조

- 자바 I/O의 기능은 java.io 패키지와 java.nio 패키지에 포함된 다양한 클래스와 인터페이스를 통해 제공된다.
- 이들 클래스는 크게 '스트림 클래스', '리더/라이터 클래스', '채널 클래스', '버퍼 클래스' 등으로 나뉘며, 각각 다른 종류의 데이터와 상황에 따라 사용된다.

## 스트림(stream)

- 데이터를 운반(입출력)하는데 사용되는 연결 통로
- 연속적인 데이터의 흐름을 물(stream)에 비유해서 붙여진 이름
- 하나의 스트림으로 입출력을 동시에 수행할 수 없다.(단방향 통신)
- 입출력을 동시에 수행하려면, 2개의 스트림이 필요하다

![image](https://hackmd.io/_uploads/HyRLdQ8-C.png)

> 스트림을 통해 데이터를 주고받는 예시

### Java의 기본 Stream

- Java에서는 3개의 스트림이 자동으로 생성되며, 이 스트림들은 콘솔에 연결된다.
  - `System.out`: 표준 출력 스트림
  - `System.in`: 표준 입력 스트림
  - `System.err`: 표준 오류 스트림

**`System.out`, `System.err` 예시 코드**

```java
System.out.println( "간단한 메시지" );
System.err.println( "오류 메시지" );
```

**`System.in` 예시 코드**

```java
int i=System.in.read(); //첫 번째 문자의 ASCII 코드를 반환한다.
System.out.println(( char )i); //문자를 출력한다.
```

### 버퍼(Buffer)

![image](https://hackmd.io/_uploads/HyD9_Xawn.png)

- 데이터를 운반하는 데 사용되는 컨테이너.
- 버퍼는 데이터를 담을 수 있는 고정된 크기의 공간이며, 데이터의 읽기, 쓰기 작업을 버퍼를 통해 진행한다.
- Stream은 버퍼를 사용하지 않는다.

## Java의 I/O 입출력 클래스

- Java의 I/O는 `java.io` 패키지에 클래스가 정의되어 있는 경우가 대부분이다.
- Java의 초기에는 입출력 클래스도 단순했고 단순히 바이트 단위의 입출력만 지원했지만, 현재는 계속적으로 확장되며 문자 단위의 입출력 뿐만 아니라 다양한 기능을 지원하는 클래스들이 생겨났다.

### I/O 클래스의 이름과 의미

- Stream : 바이트 단위로 입출력 수행
- Reader / Writer : 문자 단위로 입출력 수행
- File : 하드디스크의 파일을 사용
- Data : 자바의 원시 자료형을 출력하기 위한 클래스
- Buffered : 시스템의 버퍼를 사용

#### 1차 스트림(Primary Stream)

- 입/출력 통로를 직접 만드는 클래스
- 1차 스트림은 데이터 소스나 데이터 목적지에 직접 연결되는 스트림을 의미한다
- 예시로는 `FileInputStream`, `FileOutputStream`, `FileReader`, `FileWriter` 등이 있다

#### 2차 스트림(Secondary Stream)

- 1차 스트림을 통해 생성되며, 기존의 통로를 이용하여 새로운 기능을 더하는 클래스
- 버퍼링, 문자변환, 객체직렬화 등의 보조 스트림을 추가하는 것이 이에 해당한다.
- 예시로는 `BufferedInputStream`, `ObjectOutputStream`, `InputStreamReader` 등이 있습니다.

### InputStream / OutputStream (바이트 입출력)

![바이트 입출력](https://hackmd.io/_uploads/SyeaOQLZR.png)

> `InputStream`, `OutputStream`의 클래스 계층도

- InputStream

  | 클래스                  | 설명                                              | Stream     |
  | ----------------------- | ------------------------------------------------- | ---------- |
  | InputStream             | 바이트 입력 스트림을 위한 추상 클래스             | 2차 스트림 |
  | FileInputStream         | 파일에서 바이트를 읽어들여 바이트 스트림으로 변환 | 1차 스트림 |
  | PipedInputStream        | PipedOutputStream에서 읽어들임                    | 1차 스트림 |
  | FilterInputStream       | 필터 적용 바이트 입력을 위한 추상 클래스          | 2차 스트림 |
  | LineNumberInputStream   | 바이트 입력시 라인 번호를 유지 **(비추천)**       | 2차 스트림 |
  | DataInputStream         | 기본 자료형 데이터를 바이트로 출력                | 2차 스트림 |
  | BufferedInputStream     | 바이트 버퍼 입력                                  | 2차 스트림 |
  | PushbackInputStream     | 읽어들인 바이트를 되돌림 (pushback)               | 2차 스트림 |
  | ByteArrayInputStream    | 바이트 배열에서 읽어들임                          | 1차 스트림 |
  | SequenceInputStream     | 서로 다른 InputStream을 입력받은 순서대로 이어줌  | 2차 스트림 |
  | StringBufferInputStream | 문자열에서 읽어들임 **(비추천)**                  | 1차 스트림 |
  | ObjectInputStream       | 객체로 직렬화된 데이터를 역직렬화하여 읽음        | 2차 스트림 |

- OutputStream

  | 클래스                | 설명                                     | Stream     |
  | --------------------- | ---------------------------------------- | ---------- |
  | OutputStream          | 바이트 출력 스트림을 위한 추상 클래스    | 2차 스트림 |
  | FileOutputStream      | 바이트 스트림을 바이트 파일로 변환       | 1차 스트림 |
  | PipedOutputStream     | PipedOutputStream에 출력                 | 1차 스트림 |
  | FilterOutputStream    | 필터 적용 바이트 출력을 위한 추상 클래스 | 2차 스트림 |
  | DataOutputStream      | 바이트를 기본 자료형으로 출력            | 2차 스트림 |
  | BufferedOutputStream  | 바이트 스트림에 버퍼 출력                | 2차 스트림 |
  | PrintStream           | Stream 값과 객체를 브린트                | 2차 스트림 |
  | ByteArrayOutputStream | 바이트 스트림에 바이트 배열 출력         | 1차 스트림 |
  | ObjectputStream       | 데이터를 객체로 직렬화하여 출력          | 2차 스트림 |

## Reader / Writer (문자 입출력)

![Reader/Writer](https://hackmd.io/_uploads/Bkj0u7U-0.png)

> `Reader`,`Writer`의 클래스 계층도

- Reader

  | 클래스            | 설명                                            | Stream     |
  | ----------------- | ----------------------------------------------- | ---------- |
  | Reader            | 문자 입력 스트림을 위한 추상 클래스             | 2차 스트림 |
  | BufferedReader    | 문자 버퍼 입력, 라인 해석                       | 2차 스트림 |
  | LineNumberReader  | 문자 입력 시 라인 번호를 유지                   | 2차 스트림 |
  | CharArrayReader   | 문자 배열에서 읽어들임                          | 1차 스트림 |
  | InputStreamReader | 바이트 스트림을 문자 스트림으로 변환            | 2차 스트림 |
  | FileReader        | 파일에서 바이트를 읽어들여 문자 스트림으로 변환 | 1차 스트림 |
  | FilterReader      | 필터 적용 문자 이력을 위한 추상 클래스          | 2차 스트림 |
  | PushbackReader    | 읽어들인 문자를 되돌림                          | 2차 스트림 |
  | PipedReader       | PipedWriter에서 읽어들임                        | 1차 스트림 |
  | StringReader      | 문자열에서 읽어들임                             | 1차 스트림 |

- Writer

  | 클래스             | 설명                                   | Stream     |
  | ------------------ | -------------------------------------- | ---------- |
  | Writer             | 문자 출력 스트림을 위한 추상 클래스    | 2차 스트림 |
  | BufferdWriter      | 문자 스트림에 버퍼 출력, 줄바꿈 사용   | 1차 스트림 |
  | CharArrayWriter    | 문자 스트림에 문자배열 출력            | 1차 스트림 |
  | OutputStreamWriter | 문자 스트림을 바이트 스트림으로 변환   | 2차 스트림 |
  | FileWriter         | 문자 스트림을 바이트 파일로 변환       | 1차 스트림 |
  | FilterWriter       | 필터 적용 문자 출력을 위한 추상 클래스 | 2차 스트림 |
  | PipedWriter        | PipedReader에 출력                     | 1차 스트림 |
  | StringWriter       | 문자열 출력                            | 1차 스트림 |
  | PrintWriter        | Writer값과 객체를 프린트               | 2차 스트림 |

## 그 외의 `java.io`클래스

| 클래스                 | 설명                                                              |
| ---------------------- | ----------------------------------------------------------------- |
| console                | 명령행에서 쉽게 입력받고 정형화된 출력을 명령행에 쉽게 출력 가능  |
| File                   | 파일 객체를 생성                                                  |
| FileDescriptor         | 물리적 파일에 대한 현재의 연결을 나타내기 위한 클래스             |
| FilePermission         | 파일 및 디렉토리에 엑세스 권한을 관리하는 클래스                  |
| RandomAccessFile       | 랜덤 액세스 파일로부터 읽기와 쓰기가 동시에 이뤄질 수 있다        |
| SerializablePermission | 직렬화 가능 액세스 권한을 위한 클래스                             |
| StreamTokenizer        | 입력 스트림에서 토큰을 추출하며, 한 번에 하나의 토큰을 읽어들인다 |

## Java I/O를 이용 패키지를한 코드 샘플

1. **`FileOutputStream`을 이용하여 파일 쓰기**

   ```java
   import java.io.FileOutputStream;
   import java.io.IOException;

   public class WriteFileExample {

       public static void main(String[] args) {
           try {
               // "example.txt" 파일을 열어서 FileOutputStream 객체 fos를 생성
               FileOutputStream fos = new FileOutputStream("example.txt");

               // 파일에 쓸 문자열을 정의
               String str = "Hello, Java!";

               // 문자열을 바이트 배열로 변환
               byte[] bytes = str.getBytes();

               // 변환한 바이트 배열을 파일에 씀
               fos.write(bytes);

               // 파일을 닫음. 이는 시스템 리소스를 반환하기 위해 필요함
               fos.close();
           } catch (IOException e) {
               // 파일 입출력 중 오류가 발생하면 오류 메시지를 출력
               e.printStackTrace();
           }
       }
   }

   ```

2. **`FileInputStream`을 이용하여 파일 읽기**

   ```java
   import java.io.FileInputStream;
   import java.io.IOException;

   public class ReadFileExample {

       public static void main(String[] args) {
           try {
               // "example.txt" 파일을 열어서 FileInputStream 객체 fis를 생성
               FileInputStream fis = new FileInputStream("example.txt");

               int i;
               // fis.read()는 한 바이트를 읽어서 반환하고, 파일의 끝에 도달하면 -1을 반환
               // 따라서 파일의 끝에 도달할 때까지 루프를 돌며 파일에서 한 바이트씩 읽음
               while ((i = fis.read()) != -1) {
                   // 읽은 바이트를 문자로 변환하여 출력
                   System.out.print((char) i);
               }

               // 파일을 닫음. 이는 시스템 리소스를 반환하기 위해 필요함
               fis.close();
           } catch (IOException e) {
               // 파일 입출력 중 오류가 발생하면 오류 메시지를 출력
               e.printStackTrace();
           }
       }
   }
   ```

3. **`FileWriter`와 `BufferedWriter`를 이용하여 텍스트 파일 쓰기**

   ```java
   import java.io.BufferedWriter;
   import java.io.FileWriter;
   import java.io.IOException;

   public class WriteTextFileExample {

       public static void main(String[] args) {
           try {
               // "example.txt" 파일에 쓰기 위한 FileWriter 객체 writer를 생성
               FileWriter writer = new FileWriter("example.txt");

               // FileWriter에 BufferedWriter를 연결하여 버퍼링 기능을 추가
               // 버퍼링을 통해 파일 쓰기 성능을 향상시킴
               BufferedWriter bufferedWriter = new BufferedWriter(writer);

               // 버퍼에 "Hello, Java!" 문자열을 쓴다.
               bufferedWriter.write("Hello, Java!");

               // 버퍼에 새 줄 문자를 추가한다.
               bufferedWriter.newLine();

               // 버퍼에 "This is an example text file." 문자열을 쓴다.
               bufferedWriter.write("This is an example text file.");

               // 버퍼를 닫고, 이 때 버퍼에 남아있는 모든 데이터를 파일에 쓴 후 시스템 리소스를 반환한다.
               bufferedWriter.close();
           } catch (IOException e) {
               // 파일 입출력 중 오류가 발생하면 오류 메시지를 출력한다.
               e.printStackTrace();
           }
       }
   }

   ```

4. **`FileReader`와 `BufferedReader`를 이용하여 텍스트 파일 읽기**

   ```java
   import java.io.BufferedReader;
   import java.io.FileReader;
   import java.io.IOException;

   public class ReadTextFileExample {

       public static void main(String[] args) {
           try {
               // "example.txt" 파일을 읽기 위한 FileReader 객체 reader를 생성
               FileReader reader = new FileReader("example.txt");

               // FileReader에 BufferedReader를 연결하여 버퍼링 기능을 추가
               // 버퍼링을 통해 파일 읽기 성능을 향상시킴
               BufferedReader bufferedReader = new BufferedReader(reader);

               String line;
               // bufferedReader.readLine()은 한 줄을 읽고 반환하며,
               // 파일의 끝에 도달하면 null을 반환
               // 따라서 파일의 끝에 도달할 때까지 루프를 돌며 한 줄씩 읽음
               while ((line = bufferedReader.readLine()) != null) {
                   // 읽은 한 줄을 출력
                   System.out.println(line);
               }

               // 파일을 닫음. 이는 시스템 리소스를 반환하기 위해 필요함
               reader.close();
           } catch (IOException e) {
               // 파일 입출력 중 오류가 발생하면 오류 메시지를 출력
               e.printStackTrace();
           }
       }
   }
   ```

> 각각의 예시에서, 항상 입출력을 완료한 후에 스트림을 닫는 것(`close()`)을 확인할 수 있다. 이는 리소스를 올바르게 해제하고, 데이터의 손실을 방지하기 위한 중요한 습관이다.
