java.io - accidentlywoo/java GitHub Wiki

java.io

  1. java.io 패키지의 구조와 바이트 스트립의 특징을 이해하고 설명할 수 있다.
  2. 표준 입출력과 파일 입출력의 개념을 이애하고 구현할 수 있다.

입출력 개요 및 입출력 API

입출력 스트림의 개념

입출력 프로그래밍

필요 정보 --입력--> 자바 프로그램 수행 결과 --출력--> 출력 장치

입출력 기능 (I/O) 구현

입축력 스트림 : 다양한 경로의 입출력을 구현하는 일관된 방식 제공 다양한 입출력 장치들 : 메모리, 파일, 네티워크 등

Stream : 순서가 있는 일련의 데이터

Source : 키보드, 파일, 네트워크 등의 데이터의 근원지 --data(input Stream)--> : 근원지에서 흘러 들어오는 데이터 Read) Program Write)--data(Output Stream)--> : 목적지로 흘러가는 데이터 Destination : 모니터, 파일, 네티워크 등의 데이터의 목적지

입출력 스트립의 특징

  1. 순차적인 데이터의 흐름으로 데이터의 무작위적인 접근이 불가능함
  2. 단방향의 흐름으로 입력 스트림과 출력 스트림이 따로 존재함
  3. 모든 데이터의 입출력이 근원지, 목적지의 형태와 관계없이 일정한 형태로 전송됨 -> 동일한 방법으로 프로그램이 작성될 수 있는 유연한 구조의 API를 가짐

자바는 입출력을 위해 스트림을 생성하고 다루는 클래스들을 java.io패키지를 통해 제공하고 있음

java.io패키지

자바로 입출력 기능을 구현하는 프로그램을 개발하는 데 필요한 다양한 클래스를 포함함

File 클래스 : 파일이나 폴더를 다루는데 이용됨

RandomAccessFile 클래스 : 파일에 무작위적인 접근을 가능하게 함

스트림 클래스 : 입출력 스트림을 가능하게 함

스트림 클래스의 계층 구조

  1. Input Stream

  2. FileInputStream

  3. PipedInputStream

  4. FilterInputStream

  5. LineNumberInputStream

  6. DataInputStream

  7. BufferedInputStream

  8. PushbackInputStream

  9. ByteArrayInputStream

  10. SequenceInputStream

  11. StringBufferInputStream

  12. ObjectInputStream


  1. Output Stream

  2. FilOutputStream

  3. PipOutputStream

  4. FilterOutputStream

  5. DataOutputStream

  6. BufferedOutputStream

  7. PushbackOutputStream

  8. ByteArrayOutputStream

  9. ObjectOutputStream


  1. Reader

  2. BufferReader

  3. LineNumberReader

2.CharArrayReader

  1. InputStreamReader

  2. FileReader

  3. FilterReader

  4. PushbackReader

  5. PipedReader

  6. StringReader


  1. Writer

  2. BufferWriter 2.CharArrayWriter

  3. OutputStreamWriter

  4. FileWriter

  5. FilterWriter

  6. PipedWriter

  7. StringWriter

  8. PrintWriter

스트림 클래스의 분류

  • 입출력 단위에 의한 분류 바이트 단위의 입출력 클래스 캐릭터 단위의 입출력 클래스

  • 데이터 이동 통로에 의한 분류 1차 스트림 클래스 : 데이터가 이동하는 통로를 직접 만드는 클래스 2차 스트림 클래스 : 이미 만들어져 있는 통로에 새로운 기능을 더하는 클래스

바이트 단위와 캐릭터 단위는 서로 호환하지 않는 것을 원칙으로 함

  • 바이트 단위의 입출력 Data Source/Dest(byte stream) --InputStream--> <--OutputStream-- Java Internal(byte, byte[])

  • 캐릭터 단위의 입출력 Data Source/Dest(byte stream) --Reader--> <--Writer-- Java Internal(char, char[],String)

java.io

  • 바이트 입출력 InputStream / OutputStream

  • 캐릭터 입출력 Reader / Writer

File 클래스

입출력 프로그램의 기본인 파일과 관련된 데이터의 입출력 -> 파일을 제어하기 위한 File 클래스 제공

File클래스로 파일과 디렉토리를 모두 표현하고 관리할 수 있음

  • 파일이 실제로 존재하는 지 알 수 있음
  • 파일 복사 기능
  • 파일의 이름 변경 가능 -> 파일에 관련된 작업을 처리할 수 있음

File 클래스 자체에서는 파일의 데이터를 입출력하기 위한 메서드는 제공하지 않음 -> 데이터의 입출력은 스트림 클래스를 기반으로 수행

File 클래스로부터 생성된 객체는 변경할 수 없음 -> File 객체에 의해 표현되는 추상 경로명은 절대로 변하지 않음

File 클래스

  • File 클래스의 생성자 File(File parent, String child) : parent폴더의 child라는 파일에 대한 File객체를 생성함 File(String parent) : parent에 해당되는 파일의 File 객체를 생성함 File(String parent, String child) : parent 폴더의 child라는 파일에 대한 File 객체를 생성함

  • 파일 클래스로부터 객체를 생성하는 일반적인 방법

C:\Program Files 디렉토리에 해당하는 파일 객체 생성

  • File file = new File("C:\Program Files");

현재 작업 디렉토리에 해당하는 파일 객체 생성. '.'은 현재 작업 디렉토리를 의미함

  • File file = new File(".");

현재 작업 디렉토리 밑에 위치한 파일에 대한 파일 객체 생성

  • File file = new File("/system.log");

  • File 클래스 메서드 boolean delete() : 파일이나 폴더를 삭제함(단, 폴더가 비어있지 않으면 삭제할 수 없음) boolean exists() : 파일의 존재 여부를 리턴함 String getAbsolutePath() : 파일의 절대 경로를 문자열로 넘겨줌 String getName() : 파일이나 폴더의 이름을 넘겨줌 boolean isDirectory() : 폴더인지 여부를 리턴함

바이트 스트림

바이트 스트림 개요

  1. 스트림 클래스 : 입출력하는 데이터의 기본 단위 기준
  2. 바이트 스트림 : 8비트의 바이트를 읽고 쓰기 위한 스트림
  3. 문자 스트림 : 16비트 문자나 문자열들을 읽고 쓰기 위한 스트림

모두 바이트 단위로 입출력을 수행한다는 공통적인 특징과 함께 각 클래스들만의 고유한 기능을 가짐

어떤 클래스는 입출력 장치를 대상으로 직접 입출력을 하는 반면, 다른 클래스를 대상으로 입출력을 하는 클래스도 존재함

Java : 두개 이상의 클래스를 연결한 입출력 스트림을 생성하서 입출력을 하는 경우가 매우 일반적임

try {
  FileOutputStream output = new FileOutputStream("message.txt");
  BufferedOutputStream buffOutput = new BufferedOutputStream(output);
  buffOutput("Message Output..");
}catch(IOException e) {
  e.printStackTrace();
}

InputStream

바이트 단위 입력 스트림의 최상위 클래스로 추상 클래스로 정의되어 있기 떄문에 스스로 객체화 될 수 없음 -> InputStream을 상속한 자식 클래스는 InputStream 클래스에 존재하는 모든 추상 메서드를 적절하게 Overriding 해야함

InputStream 클래스를 상속한 자식 클래스의 객체를 생성하여 입력 관련 로직을 구현할 수 있음

  • InputStream 클래스의 주요 메서드 *void close() throws IOException : 입력 스트림을 닫음 *int read() throws IOException : 입력 스트림에서 한 바이트를 읽어서 int 값으로 반환함 *int read(byte buf[]) throws IOException : 입력 스트림에서 buff[] 크기만큼을 읽어 buf에 저장하고 읽은 바이트 수를 반환함

  • *read() 메서드 데이터를 읽어 들이는 기능을 제공 입력 스트림에서 하나의 바이트를 읽어 들임 EOF를 만나면 -1을 반환하여 읽기 작업이 끝났다는 것을 알려줌

  • read(byte[] buf) 메서드 사용자가 지정한 byte[]를 이용하여 한꺼번에 원하는 양을 읽어들일 수 있음 일반적으로 available() 메서드를 사용하여 스트림에서 읽을 수 있는 바이트 수를 얻은 후 이를 기준으로 byte[]를 생성하여 한꺼번에 읽을 수 있음

EOF(End Of Fole)의 의미

InputStream에서 제공되는 read() 메서드는 리턴형이 byte가 아니라 int입니다. 파일의 끝을 나타내는 EOF는 윈도우에서는 "Ctrl-Z"를 사용하고 있는 리눅스나 유닉스에서는 "Ctrl-D"를 사용하는데, 이 값을 -1로 표현할 수 있습니다. 자바의 숫자 체계는 바이트(byte)를 기준으로 -128에서 127까지 표현할 수 있습니다. 하지만 read()메서드를 통해서 읽는 값은 양수를 기준으로 표현하는데, 이 경우에느 0에서 127까지의 128개밖에 사용할 수 없습니다. 이를 해결하기 위한 방법으로 더 큰 자료형을 리턴으로 사용하여 0에서 255까지 사용할 수 있게 하고, -1을 특수한 입력 값으로 처리하도록 구성하기 위해서 정수형(int)을 사용하는 것입니다.

OutputStream

바이트 단위의 출력을 대표하는 최상위 클래스임 InputStream 클래스와 마찬가지로 이 클래스에 정의되어 있는 메서드는 자식 클래스가 상속받아서 그대로 사용하거나 재정의하여 사용함

  • OutputStream 클래스의 주요 메서드 *void close() throws IOException : 출력 스트림을 닫음 *void flush() throws IOException : 버퍼에 남은 출력 스트림을 출력함 *void write(int i ) throws IOException : 정수 i의 하위 8비트를 출력함 *void write(byte buf[]) throws IOException : buf의 내용을 출력함

가장 중요한 메서드는 write(int i) 메서드

  • 1바이트를 출력하는 메서드로서, 메서드의 인자도 바이트가 아닌 정수형을 사용함
  • write(int i) 메서드에서는 세 개의 메서드가 Overloading 됨
  1. 인자로 byte[]를 사용하는 것

  2. 배열과 함께 시작 위치 및 크기를 지정하는 메서드 -> 출력하고자 하는 배열의 지정된 위치에서 정해진 크기만큼 출력이 가능함을 알 수 있음

  3. 출력이 끝났음을 알려 주기 위한 flush() 메서드

버퍼는 일종의 완충지대로 입출력을 조금 더 빨리 할 수 있게 도와줌 모든 출력은 도착 지점으로 나가지 않고 먼저 버퍼에 쌓임 버퍼에 데이터가 충분히 쌓인 후 flush() 명령을 받으면 현재 버퍼에 있던 모든 내용을 도착 지점으로 내보내고 버퍼를 비워 버림 flush() 메서드를 호출하지 않으면 버퍼로만 출력되기 때문에 실제로 도착 지점에서는 아무런 데이터를 받지 못하는 경우가 발생할 수 있음 ->일반적인 출력 스트임에서는 데이터를 출력하고 나면 자동으로 flush()메서드를 호출할 수 있는 기능을 제공하는 경우가 많음

표준 입력

표준 입력 : 사용자가 키보드를 통해 입력한 데이터를 읽어 들이는 작업 표준 출력 : 프로그램의 수행 결과 메시지가 콘솔 창에 출력되는 것

자바에서는 표준 입출력 기능을 System 클래스를 통해 제공함

표준 입출력은 왜 java.lang 패키지를 통해 제공할까?

java.lang 패키지는 자바 프로그램 개발에 있어 기본이 되는 필수 API들이 들어있는 클래스임 -> 결국 표준 입출력을 지원하는 System클래스를 java.lang 패키지에서 제공함으로써 모든 프로그램에서 기본적으로 표준 입출력을 사용할 수 있도록 하기 위함임

System 클래스에 in이라는 클래스 변수로 제공됨

System.in 변수의 타입이 InputStream이라는 점에 주의해야 함 InputStream -> 최상위 클래스이면서 추상 클래스임. 객체를 생성할 수 없는 클래스

  • System.in System클래스의 in 변수는 입력 스트림 객체를 참조하여, 이를 통해 키보드 입력을 처리할 수 있음 변수의 타입은 InputStream클래스이지만, 실제 참조하는 객체는 InputStream의 자식 객체임을 암시함 자연스러운 형변환이 지원되기 때문에 가능한 현상임

JVM이 메모리로 올라오면서 미리 객체를 생성해 놓는, 대표적인 객체임 자료형이 InputStream이기 때문에 바이트 단위로만 입출력이 허용됨 키보드에서 입력하는 자료는 때에 따라서 두 바이트가 합쳐져야 의미를 가지는 경우가 있음 영문과 한글의 처리를 분리해서 구성해야 제대로 인식할 수 있음

public final static InputStream in = nullInputStream();

System 클래스를 이용하여 키보드 입력을 읽어 들이기 위한 구문

System.in.read();
  • 자바 언어를 처름 학습할 때 사용하는 문장 중 하나가 System.out.println()메서드임 PrintStream 타입으로 선언되어 있음 PrintStream은 OutputStream 클래스의 후손 클래스로 Exception을 안전하게 처리한 메서드로만 구성되어 있음 -> System.out을 이용하여 출력할 때는 try-catch구문을 이용한 예외 처리 로직이 필요 없음
public final static PrintStream out = nullPrintStream();

System.out 변수가 참조하는 PrintStream타입의 객체에는 다양한 타입의 데이터를 출력하기 위한 print(), println()메서드가 데이터 타입별로 Overloading되어 있다.

FIleInputStream / FileOutputStream

  • FileInputStream 클래스 InputStream클래스를 상속한 자식 클래스로 하드 디스크상에 존재하는 파일로부터 바이트 단위의 입력을 처리하는 클래스

출발지점 --스트림을 생성하는 클래스--> 도착지점

생성자의 인자로는 File 객체를 주거나 파일의 이름을 직접 String 형태로 줄 수 있음 파일의 이름을 String 형태로 주는 경우가 많은데 파일이 존재하지 않을 가능성도 있으므로 FileNotFoundException에 대한 예외 처리를 해야 함

  • FileOutputStream클래스 OutputStream 클래스를 상속한 자식 클래스로 파일로 바이트 단위의 출력을 처리하는 클래스 Sink 스트림의 일종으로 3개의 생성자가 Overloading되어 있는데, FileInputStream의 생성자보다 하나 더 많은 FileInputStream의 생성자와 거의 같은 형태인데, 하나 더 있는 생성자의 형식은 append 처리를 위한 논리 변수를 인자로 가짐 -> 이 값이 true로 설정되면 기존에 존재하고 있는 파일의 가장 뒷부분에 데이터를 연결하여 출력함

  • FileInputStream의 생성자 FileInputStream(String filepath) trows FileNotFoundException : filepath로 지정한 파일에 대한 입력 스트림을 생성함

FileInputStream(File fileObj) trows FileNotFoundException : fileObj로 지정한 파일에 대한 입력 스트림을 생성함

  • FileOutputStream의 생성자 FileOutputStream(String filepath) trows IOException : filepath로 지정한 파일에 대한 출력 스트림을 생성함

FileOutputStream(String filepath,Boolean append) trows IOException : 지정한 파일로 출력 스트림을 생성함. append인자로 출력할 때 append 모드를 설정함

FileOutputStream(File fileObj) trows IOException : fileObj로 지정한 파일에 대한 출력 스트림을 생성함

버퍼를 이용한 파일 입출력

보다 효울적인 프로그램을 작성하고 싶다면?

기계적인 동작의 횟수를 줄이는 것이 가장 좋음 -> 입출력 횟수를 줄이면 프로그램의 효율을 높일 수 있고, 더 빠른 프로그램으로 개선할 수 있음

1바이트씩 읽어 들이는 read()메서드 -> 한꺼번에 많은 데이터를 바이트의 배열로 읽어 들어오는 read(byte[]) 메서드 : 효율적인 프로그램 작성 가능!

파일을 통쨰로 한꺼번에 읽는 것은 기계적인 동작을 최소화하기 위한 방법임

버퍼의 크기가 무조건 파일의 크기만큼 크면 성능이 좋아질까? ->No 버퍼의 크기가 아주 작으면 효율은 급격히 떨어짐

버퍼가 크면 메모리의 낭비를 유발할 수 있음 -> 필요한 데이터는 4바이트 정도 밖에 안 되는 경우에도 무조건 100바이트를 다 가져와서 작업하기 때문임

파일의 크기가 예상하는 것보다 훨씬 큰 경우 충분한 메모리를 준비할 수 없는 상황도 발생할 수 있음

버퍼의 크기는 적정선에서 만족할 수 있도록 잡는 것이 필요함

보통 1024(2^10), 2048, 4096, 8192와 같이 배수 형식으로 준비하는 것이 일반적임

BufferedInputStream / BufferedOutputStream

사용자가 일일이 버퍼를 지정하여 입출력하는 것보다 조금 더 편리하게 입출력할 수 있는 방법

java 자바가 라이브러리로 제공하고 있는 BufferedInputStream과 BufferedOutputStream 클래스를 사용하여 프로그래밍하는 것

BufferedInputStream, BufferedOutputStream -> 2차 스트림의 일종으로, 이미 존재하고 있는 스트림을 이용하여 새로운 기능을 추가하는 형식으로 구성되어 있음

  • FileUnputStream 1차 스트림이기 때문에 미리 만들어져 있는 스트림 없이 자신의 객체를 생성하여 입력을 시도할 수 있음

  • BufferedInputStream 미리 만들어진 스트림을 생성자의 인자로 받아들여 객체를 생성함

  • BufferedInputStream 원하는 자료를 1바이트 단위로 읽는 read() 메서드를 수행하면?

내부적으로 버퍼를 준비하고, 이 버퍼를 이용함. -> 하드 디스크의 파일로부터 버퍼의 크기만큼 한꺼번에 많은 데이터를 가져오 -> 채워진 버퍼로부터 1바이트를 읽어 들임 : 준비된 시스템 버퍼에서 데이터를 읽음 -> 프로그램으로 전달함

  • BufferedOutputStream 1바이트를 출력함 -> 시스템 버퍼에 출력이 쌓임 -> 버퍼가 모두 채워지거나, flush() 명령을 만남 -> 버퍼의 모든 내용을 하드 디스크 파일로 출력함

--BufferedInputStream, BufferedOutputStream을 이용하여 프로그램 작성 시--> 1바이트씩 읽고 쓰는 모든 작업이 내부적으로는 버퍼를 대상으로 일어남 필요에 따라 버퍼와 파일 간에 입출력이 간혈적으로 발생하므로 전체적인 입출력 성능이 향상됨