Skip to content

17. 입력과 출력(IO)


1. 키워드

  • 스트림(Stream)과 입출력 스트림
  • 바이트 기반 스트림, 보조 스트림, 문자 기반 스트림
  • 표준 입출력, RandomAccessFile 클래스, File 클래스


2. 스트림(Stream)

  • 자바에서는 파일이나 콘솔의 입출력을 직접 다루지 않고, 스트림이라는 흐름을 통해 다룬다.
  • 스트림이란 실제의 입력이나 출력이 표현된 데이터의 이상화된 흐름을 의미한다.
  • 즉, 스트림은 OS에 의해 생성되는 가상의 연결 고리를 의미하며, 중간 매개자 역할을 한다.


001


  • Java SE 8 버전부터 추가된 스트림 API는 앞서 설명한 스트림과는 전혀 다른 개념이다.


1) 입출력 스트림

  • 스트림은 한 방향으로만 통신할 수 있으므로, 입력과 출력을 동시에 처리할 수는 없다.
  • 따라서 스트림은 사용 목적에 따라 입력 스트림과 출력 스트림으로 구분된다.
  • 자바에서는 java.io 패키지를 통해 InputStreamOutputStream 클래스를 별도로 제공하고 있다.
  • 즉, 자바에서의 스트림 생성이란 이러한 스트림 클래스 타입의 인스턴스를 생성한다는 의미이다.
  • InputStream 클래스에는 read() 메서드가, OutputStream 클래스에는 write() 메서드가 각각 추상 메서드로 포함되어 있다.
  • 사용자는 이 두 메서드를 상황에 맞게 적절히 구현해야만 입출력 스트림을 생성하여 사용할 수 있다.


Note

  • read() 메서드는 해당 입력 스트림에서 더 이상 읽어들일 바이트가 없으면, -1을 반환해야 한다.
  • 그런데 반환 타입을 byte 타입으로 하면, 0부터 255까지의 바이트 정보는 표현할 수 있지만 -1은 표현할 수 없게 된다.
  • 따라서 InputStreamread() 메서드는 반환 타입을 int형으로 선언하고 있다.


2) 바이트 기반 스트림

  • 자바에서 스트림은 기본적으로 바이트 단위로 데이터를 전송한다.


3) 보조 스트림

  • 자바에서 제공하는 보조 스트림은 실제로 데이터를 주고받을 수는 없지만, 다른 스트림의 기능을 향상시키거나 새로운 기능을 추가해 주는 스트림이다.


4) 문자 기반 스트림

  • 자바에서 스트림은 기본적으로 바이트 단위로 데이터를 전송한다.
  • 하지만 자바에서 가장 작은 타입인 char형이 2바이트이므로, 1바이트씩 전송되는 바이트 기반 스트림으로는 원활한 처리가 힘든 경우가 있다.
  • 따라서 자바에서는 바이트 기반 스트림뿐만 아니라 문자 기반의 스트림도 별도로 제공한다.
  • 이러한 문자 기반 스트림은 기존의 바이트 기반 스트림에서 InputStreamReader로, OutputStreamWriter로 변경하면 사용할 수 있다.


3. 파일 입출력

1) 표준 입출력

  • 자바에서는 콘솔과 같은 표준 입출력 장치를 위해 System이라는 표준 입출력 클래스를 정의하고 있다.
  • 표준 입출력 스트림은 자바가 자동으로 생성하므로, 개발자는 별도로 스트림을 생성하지 않아도 사용할 수 있다.


2) 표준 입출력의 대상 변경

  • 앞서 살펴본 세 가지 입출력 스트림은 모두 콘솔과 같은 표준 입출력 장치를 대상으로 한다.
  • 하지만 이와 같은 스트림에 System 메서드를 사용하면 스트림의 대상을 다른 입출력 장치로 변경할 수 있다.


3) RandomAccessFile 클래스

  • 앞서 살펴본 다양한 입출력 스트림을 이용하면 파일에 순차적으로 입출력 작업을 수행할 수 있다.
  • 하지만 순차적인 접근이 아닌 임의의 지점에 접근하여 작업을 수행하고 싶다면, RandomAccessFile 클래스를 사용하면 된다.
  • 이 클래스는 파일만을 대상으로 하며, 임의의 지점에서 입출력을 동시에 수행할 수 있다.
  • RandomAccessFile 클래스의 생성자에는 인수로 파일의 이름뿐만 아니라 파일 모드까지 함께 전달해야 한다.


  • getFilePointer() 메서드를 사용하면 파일 포인터의 현재 위치를 확인할 수 있다.
  • 또한, seek() 메서드를 사용하면 파일 포인터의 위치를 변경할 수도 있다.


try {
  // "rw" 모드로 "data.txt" 파일을 개방함
  RandomAccessFile file = new RandomAccessFile("data.txt", "rw");

  System.out.println(file.getFilePointer()); // 0 -> 파일 포인터의 현재 위치를 반환함

  file.writeInt(10); // 정수 10을 저장함

  System.out.println(file.getFilePointer()); // 4

  file.seek(20); // 파일 포인터의 위치를 20으로 이동시킴

  System.out.println(file.getFilePointer()); // 20
} catch (IOException e) {
  e.printStackTrace();
}


4) File 클래스

  • 앞서 살펴본 입출력 스트림을 사용하면 파일을 통한 입출력 작업을 수행할 수 있다.
  • 하지만 파일의 제거나 디렉터리에 관한 작업 등은 입출력 스트림을 통해서는 수행할 수 없다.
  • 자바는 이러한 입출력 잡업 이외의 파일과 디렉터리에 관한 작업을 File 클래스를 통해 처리하도록 하고 있다.


File dir = new File("D:\\data"); // 디렉터리 생성
File file = new File(dir, "data.txt"); // 파일 생성

if (!file.exists()) {
  System.out.println("파일이 존재하지 않습니다.");
  System.exit(0);
}

System.out.println(file.getPath()); // D:\data\data.txt
System.out.println(file.length()); // 0 -> 파일의 크기를 반환함

References