chapter 14. 입출력 스트림
스트림(Stream) 이란? 데이터를 목적지로 입출력하기 위한 방법이다. 스트림의 소개 스트림(Stream) 이란? 데이터를 목적지로 입출력하기 위한 방법이다. 스트림에 데이터를 쓸 수 있고, 스트림에서 데이터를 읽을 수 있다. 스트림에 데이터를 쓸 경우, 이러한 스트림을 출력 스트림(output stream)이라고 한다. 스트림에서 데이터를 읽을 경우, 이러한 스트림을 입력 스트림(input stream)이라고 한다.
스트림의 소개 스트림의 특징 스트림은 FIFO 구조이다. – FIFO구조란 먼저 들어간 것이 먼저 나오는 형태로서 데이터의 순서가 바뀌지 않는다는 특징이 있다. 스트림은 단방향이다. – 자바에서 스트림은 읽기, 쓰기가 동시에 되지 않는다. 따라서 읽기, 쓰기가 필요하다면 읽는 스트림과 쓰는 스트림을 하나씩 열어 사용해야 한다. 스트림은 지연될 수 있다. – 스트림은 넣어진 데이터가 처리되기 전까지는 스트림에 사용되는 스레드는 지연상태에 빠진다. 따라서 네트워크 내에서는 데이터가 모두 전송되기 전까지 네트워크 스레드는 지연상태가 된다.
File 클래스 File 클래스 생성자 시스템에 있는 파일이나 디렉토리를 추상화한 클래스이다.
File 클래스 File 클래스의 주요 메서드 예제[14-1] FileEx.java
바이트 스트림 바이트 스트림의 종류 바이트 스트림은 1 byte를 입출력 할 수 있는 스트림이다. 일반적으로 바이트로 구성된 파일, 즉 동영상 파일, 이미지 파일, 음악 파일을 처리하기에 적합한 스트림이다. 바이트 스트림의 종류 InputStream과 OutputStream으로 구성되어 있다.
바이트 스트림 바이트 입력 스트림의 구조(1)
바이트 스트림 바이트 출력 스트림의 구조(2)
바이트 입력 스트림(InputStream) 자바 프로그램은 객체를 생성하고 생성된 객체와 바이트 스트림과 연결함으로써 파일을 연다. 자바는 다른 장치들과도 바이트 스트림을 연결할 되어 있는고 프로그램이 시작되면 장치들과 연결된 세 개의 객체(System.in, System.out, System.err)를 생성한다. System.in 객체는 키보드로 바이트를 입력할 수 있는 InputStream 객체이다.
바이트 입력 스트림 InputStream의 주요 메서드 예제[14-7] InputStreamEx.java
FileInputStream FileInputStream은 시스템에 있는 모든 파일을 읽을 수 있는 기능을 제공한다. 바이트 입력 스트림 예제[14-8] FileInputStreamEx.java FileInputStream FileInputStream은 시스템에 있는 모든 파일을 읽을 수 있는 기능을 제공한다. 파일을 읽을 때는 파일의 경로와 파일 객체를 생성자의 매개 변수로 설정할 수 있다. 만약, 파일이 존재하지 않으면 FileNotFoundException을 발생하게 된다.
DataInputStream DataInput 인터페이스는 입력 스트림으로 부터 기본형 데이터를 읽기 위한 메서드를 정의한다. 바이트 입력 스트림 DataInputStream DataInput 인터페이스는 입력 스트림으로 부터 기본형 데이터를 읽기 위한 메서드를 정의한다. DataInput 인터페이스는 기본 자료형을 읽을 수 있는 각종 메서드와 문자를 읽을 수 있는 메서드를 정의 하고 있다. DataInputStream 클래스의 생성자는 한 개로 구성되어 있으며, 어떠한 예외 처리도 되어 있지 않다.
BufferedInputStream 버퍼링은 입출력 수행을 향상 시킨 기술이다. 바이트 입력 스트림 예제[14-9] BufferedInputStreamEx.java BufferedInputStream 버퍼링은 입출력 수행을 향상 시킨 기술이다. 버퍼링이란 논리적 데이터 덩어리들이 하나의 큰 물리적 입력 연산으로서 파일로 부터 읽혀서 버퍼로 입력 하는 것을 말한다. 버퍼링을 이용하면 데이터를 읽어서 버퍼를 꽉 채우고, 연속된 read() 메서드 호출의 경우는 단지 메모리 버퍼로 부터 데이터를 읽어 내는 것일 뿐으므로 훨씬 효율적이다. 또한 mark 기능과 reset 기능을 구현 추가로 구현하였다.
바이트 출력 스트림(OutputStream) 예제[14-10] OutputStreamEx.java 바이트 출력 스트림(OutputStream) OutputStream은 바이트 출력을 수행하는 필요한 메서드를 정의한 추상 클래스이다. 프로그램이 시작 되면 장치와 연결된 두 개의 출력 스트림은 System.out, System.err를 생성한다. System.out 객체는 화면에 데이터를 출력 한다. System.err 객체는 화면에 오류 메시지를 출력하게 된다.
FileOutputStream FileOutputStream은 시스템에 있는 모든 파일에 쓸 수 있는 기능을 제공한다. 바이트 출력 스트림 예제[14-8] FileOutputStreamEx.java FileOutputStream FileOutputStream은 시스템에 있는 모든 파일에 쓸 수 있는 기능을 제공한다. 만약 객체를 생성할 때 , 파일이 존재하지 않으면 FileNotFoundException을 발생하게 된다. 객체가 생성되면 파일이 있는 경우에는 파일을 생성하지 않으면 파일이 없는 경우에는 파일을 생성하게 된다. FileNotFoundException의 의미는 경로가 일치하지 않을 때 발생하는 예외이다. 즉 경로는 일치하고 파일이 없는 경우에는 예외가 발생하지 않고 파일 생성하게 된다.
바이트 출력 스트림 예제[14-11] FileOutputStreamEx.java
바이트 출력 스트림 예제[14-12] DataOutputStreamEx.java DataOutputStream DataOutput 인터페이스는 출력 스트림으로 부터 기본형 데이터를 쓰기 위한 메서드를 정의한다. DataOutput 인터페이스는 기본 자료형을 쓸 수 있는 각종 메서드와 문자를 쓸 수 있는 메서드를 정의 하고 있다. DataOutputStream 클래스의 생성자는 한 개로 구성되어 있으며, 어떠한 예외 처리도 되어 있지 않다.
BufferedOutputStream 바이트 출력 스트림 예제[14-13] BufferedOutputStreamEx.java BufferedOutputStream 이 클래스를 사용하면 버퍼가 채워질 때마다 한번에 대량으로 출력장치로의 실제 전송이 수행된다. OutputStream은 출력 속도의 향상을 위해서 flush() 메서드를 정의하고 있다. 하지만 실제로는 구현되지 않았다. 플러쉬란 버퍼가 다 차지 않더라도 버퍼를 비워주는 기능을 말한다. 플러쉬 기능을 구현한 클래스가 바로 BufferedOutput-Stream 클래스가 된다.
바이트 출력 스트림 PrintStream PrintStream은 모든 자료형을 출력할 수 있는 print(), println() 메서드가 오버로딩 되어 있다. 프로그램이 시작되면 장치와 연결된 출력스트림인 System.out, System.err 객체가 PrintStream 객체이다. 자바 5.0에서는 PrintStream의 format() 메서드와 printf() 메서드가 추가되어 있기 때문에 이전의 System.out.printf() 나 System.out.format()을 이용해서 출력문을 작성할 수 있었다.
PrintStream PrintStream은 두 가지 중용한 특징을 가진다. 바이트 출력 스트림 PrintStream PrintStream은 두 가지 중용한 특징을 가진다. 첫번째, 다른 스트림과는 다르게 플러쉬 기능을 자동으로 처리할 수 있는 생성자를 가지고 있다. 두번째, 모든 메서드의 예외처리를 하지 않았다는 점이다. 예제[14-14] PrintStreamEx.java
문자 스트림 문자 스트림의 특징 바이트 스트림에 추가하여 Reader와 Writer 클래스를 제공하는데, 이것은 2 바이트를 입출력 할 수 있는 문자 기반 스트림이다. 바이트 스트림은 1바이트를 입출력하기 때문에 일반적으로 영문자로 구성된 파일, 동영상 파일, 음악 파일의 입출력 등에 적합한 스트림이다. 문자 스트림은 2바이트를 입출력하기 때문에 세계 모든 언어로 구성된 파일을 입출력 하기에 적합하다. 문자 스트림의 구조 문자 스트림은 Reader와 Writer로 나눈다. 문자 입력 스트림 – Reader 문자 출력 스트림 - Writer
문자 스트림 문자 입력 스트림의 구조(1)
문자 스트림 문자 출력 스트림의 구조(2)
Reader Reader 클래스는 문자 입력 스트림의 최상위 추상 클래스이다. InputStream 클래스와 거의 같은 메서드를 제공하고 있으며, 차이점은 Reader 클래스는 2바이트를 읽을 수 있는 메서드로 구성되었다는 점이다.
FileReader FileReader클래스는 시스템에 있는 파일을 읽을 수 있는 기능을 제공한다. 문자 입력 스트림 FileReader FileReader클래스는 시스템에 있는 파일을 읽을 수 있는 기능을 제공한다. 파일을 읽을 때는 파일의 경로, File 객체를 생성자의 매개변수로 지정할 수 있다. 파일이 존재 하지 않으면 FileNotFoundException 예외를 발생한다. FileReader 클래스는 문자 스트림으로 한문자를 읽기 때문에 화면에 출력하더라도 한글 깨지는 현상이 일어나지 않는다. 예제[14-15] FileReaderEx.java
문자 입력 스트림 BufferedReader 바이트 입력 스트림의 BufferedInputStream과 동일한 기능을 제공하는 BufferedReader 클래스는 문자 출력 스트림의 효율적인 버퍼링을 가능하게 한다. BufferedReader클래스에는 readLine() 메서드가 추가 되었는데, 이 메서드는 한 줄 단위로 읽는 메서드이다. 이 때, 한 줄의 끝을 ‘\r’,’\n’ 중의 하나가 올 경우 또는 ‘\r\n’이 오는 경우를 한 줄의 끝으로 간주한다. 예제[14-16] BufferedReaderEx.java
문자 출력 스트림 Writer Writer 클래스는 문자 출력 스트림의 최상위 추상 클래스이며, OutputStream과 거의 같은 메서드를 제공한다. Writer 클래스는 2 바이트를 출력할 수 있는 메서드로 구성되어 있다.
FileWriter 문자 출력 스트림 예제[14-17] FileWriterEx.java 만약, 경로가 실제로 존재하지 않으면 IOException를 발생하게 된다.(FileNotFoundException예외가 아님) 예제[14-17] FileWriterEx.java
문자 출력 스트림 BufferedWriter 바이트 출력 스트림의 BufferedOutputStream과 동일한 기능을 제공하며, 문자 출력 스트림의 효율적인 버퍼링을 가능하게 한다. 객체를 생성할 때는 예외처리를 하지 않아도 된다. 이 클래스에서는 한 줄 내려쓰기를 할 수 잇는 newLine() 메서드가 추가되었다. 예제[14-17] BufferedWriterEx.java
문자 출력 스트림 PrintWriter PrintWriter 클래스는 다른 스트림과 다르게 바이트 출력 스트림과 문자 출력 스트림을 가지고 객체를 생성할 수 있는 클래스이다. 자동 플러쉬 기능을 가지고 있다. PrintWriter 클래스의 생성자에는 FileNotFoundException 예외를 발생하기 때문에 반드시 예외처리를 해야 한다.
InputStreamReader와 OutputStreamWriter 바이트 스트림과 문자 스트림의 연결 InputStreamReader와 OutputStreamWriter InputStreamReader : 바이트 입력 스트림=>문자 입력 스트림 OutputStreamWriter 바이트 출력 스트림 = > 문자 출력 스트림
Scanner JDK 5.0에서는 java.util 패키지에 Scanner 클래스를 제공하고 있다. 정규 표현식이란 언어을 표현 할 수 있는 문자식을 말한다. 이렇게 구분된 토큰은 다양한 nextXXX() 메서드를 사용하여 다른 타입의 값으로 바뀌게 된다. http://java.sun.com/j2se/1.5.0/docs/api/java/util/regex/Pattern.html
File 클래스를 이용한 double로 변환한 예 Scanner 클래스 키보드로 입력한 값을 int로 변환한 예 File 클래스를 이용한 double로 변환한 예 Scanner scan = new Scanner(System.in); int _int = scan.nextInt(); Scanner scan = new Scanner(new File(“c:\\scan.txt”)); while( scan.hasNextDouble()){ long _long = scan.nextDouble(); }
문자열을 구분 패턴으로 변환한 예 “\\s*and\\s*” => and 앞뒤로 있는 0개 이상의 빈 공백을 의미한다. Scanner 클래스 문자열을 구분 패턴으로 변환한 예 “\\s*and\\s*” => and 앞뒤로 있는 0개 이상의 빈 공백을 의미한다. String str = “1 and 2 and animal and lion and tiger”; Scanner scan = new Scanner(str); scan.useDelimeter(“\\s*and\\s*”); int firstToken = scan.nextInt(); int secondToken = scan.nextInt(); int thirdToken = scan.next(); int fourthToken = scan.next(); int fifthToken = scan.next();
스트림을 이용한 구분 패턴으로 변환한 예 “\\Z” => 문서의 끝을 의미한다. Scanner 클래스 URLConnection urlCon = new URL(“http://www.sist.co.kr”).openConnection(); Scanner scan = new Scanner(urlCon.getInputStream()); scan.useDelimiter(“\\Z”); String text = scan.next(); System.out.println(text);
Scanner 클래스의 생성자 Scanner 클래스는 매개변수로 네 가지 타입을 갖는다. 네 가지 타입 – File, InputStream, Readable, String Scanner 클래스는 네 가지 타입을 매개변수로 구분자나 구분 패턴을 사용하여 문자열이나 기본 데이터 타입으로 토큰 할 수 있는 클래스이다.
Scanner 클래스 Scanner 클래스의 주요 메서드
Scanner 클래스의 예제 [예제 14-22] ScannerConsoleEx.java [예제 14-23] ScannerFileEx.java [예제 14-24] ScannerReadableEx.java [예제 14-25] ScannerURLConnectionEx.java [예제 14-26] ScannerRegEx.java
객체의 직렬화 Serializable 객체의 직렬화란 객체를 스트림으로 파일에 저장하는 방법이다. 객체를 직렬화 하기위한 두 가지 방법으로 Serializable과 Externalizable 인터페이스 구현하면 된다. Serializable Serializable 인터페이스를 구현한 클래스를 작성하면 해당 클래스의 모든 멤버변수가 직렬화 대상이 된다. 객체가 스트림을 통해 직렬화 될 때는 객체에 있는 멤버변수가 직렬화 되는 것이다. 객체의 멤버변수 중에 직렬화 대상에 제외하고 싶다면 transient 키워드를 사용하면 된다. public transient int age;
Externalizable Externalizable 인터페이스는 Serializable 인터페이스의 서브 인터페이스이다. 객체의 직렬화 Externalizable Externalizable 인터페이스는 Serializable 인터페이스의 서브 인터페이스이다. Externalizable 인터페이스를 구현한 클래스는 위의 두 가지 메서드를 이용하여 특정 멤버 변수만을 직렬화 할 수 있는 기능을 제공한다. Public interface Externalizabel extends Serializable{ public void readExternal(ObjectInput in) throws IOException,ClassNotFoundException; public void writeExternal(ObjectOutput out) throws IOExcepiton; }
오브젝트 스트림 ObjectOutputStream 객체를 직렬화 하고 다시 역직렬화 시킬 수 있는 클래스가 ObjectInputStream과 ObjectOutputStream 이다. ObjectOutputStream ObjectOutput 인터페이스를 구현한 클래스로 객체를 파일에 기록 가능한 클래스이다. ObjectOutput 인터페이스는 writeObject(Object obj) 메서드를 포함하는데 이 메서드가 객체의 데이터를 직렬화 시켜주는 메서드(직렬화 메서드)이다. 만약 obj가 Serializable 인터페이스로 구현되어 있지 않다면 NotSerializableException 예외가 발생한다. 보통 직렬화된 데이터를 저장할 파일 확장자는 “ser”로 정하는것이 관례이다.
오브젝트 스트림 ObjectInputStream ObjectInput 인터페이스를 구현한 클래스로 직렬화 된 객체를 읽어올 수 있는 클래스이다. ObjectInput 인터페이스는 readObject() 메서드를 포함하는데 이 메서드는 객체의 데이터를 복원 시켜주는 메서드(역 직렬화 메서드)이다. 예제[14-27] Customer.java 예제[14-28] ObjectInOutputStreamEx.java 예제[14-29] ExternalizableEx.java
StreamTokenizer 문자 입력 스트림을 토큰 단위로 나눠서 관리할 수 있는 클래스이다. 기타 스트림 StreamTokenizer 문자 입력 스트림을 토큰 단위로 나눠서 관리할 수 있는 클래스이다. 문자 입력 스트림을 읽을 때 토큰의 유형을 문자와 숫자로 구분할 수 있기 때문에 문자와 숫자로 구성된 파일을 읽을 유용하게 쓰일 수 있다.
기타 스트림 예제[14-30] StreamTokenizerEx.java
기타 스트림 예제[14-30] RandomAccessFile.java RandomAccessFile 입력 스트림과 출력 스트림의 두가지 기능을 가지고 있는 스트림이며, 기존의 입력 스트림과 달리 한 번 읽었던 입력 스트림을 다시 읽을 수 있는 스트림이다.