스트림(Stream)
자바 프로그램에서 입력되고 출력되는 데이터의 흐름. 자바는 데이터를 스트림 형태로 주고 받는다.

입력 스트림 : 프로그램으로 들어오는 스트림 (Input Stream : 키보드, HDD)
출력 스트림 : 프로그램에서 밖으로 나가는 스트림 (Output Stream : 모니터, HDD)

바이트 스트림 : 프로그램에서 사용할 수 있는 데이터로 구성된 스트림 (FileInputStream, FileOutputStream)
문자 스트림 : 사람이 이해할 수 있는 문자로 구성된 스트림 (FileReader, FileWriter)
java.io 패키지에 있는 클래스 : FileInputStream, FileOutputStream, FileReader, FileWriter


1. FileReader
- 문자 데이터를 파일로부터 읽는 클래스
- 파일 이름을 생성자 파라미터로 사용해서 FileReader 객체를 생성한다.

FileReader reader = new FileReader("poem.txt"); 
(생성자 안에서 현재 디렉토리의 poem.txt 파일을 연다.)

1) read 메소드 : 파라미터를 받지 않는 가장 간단한 메소드. 파일로부터 한 개의 문자를 읽어서 리턴한다.

date = reader.read(); 

- read 메소드는 파일에 있는 문자 하나를 읽어 리턴한다. 
- 처음 호출했을 때 첫번째 문자를 읽어 리턴, 2번째 호출시엔 2번째 문자 리턴, 3번째 호출시엔 3번째 문자 리턴하는 방식. 
- 리턴 타입이 char가 아니라 int인 것에 주의. 더이상 읽을 문자가 없으면 -1 리턴.

while (true) {
int data = reder.read(); // 데이터를 읽어서
if (data < 0) break;    // 마이너스 값이면 반복을 중단
char ch = (char) data; // 아니면 char 타입으로 캐스트
// 데이터 처리 로직이 들어가는 부분
}

2) reder.close(); 파일을 닫는 메소드



예제) 텍스트 파일을 읽는 프로그램

1) read 메소드를 이용하여 텍스트 파일을 읽는 프로그램 (미완성)
import java.io.*;
class ReaderExample1 {
    public static void main(String args[]) {
FileReader reader = new FileReader("poem.txt");  // FileNotFoundException
char data = reader.read();  // test.txt 파일에서 한 글자를 읽는다.
while(true) {
    int data = reader.read();  // IOException
    if(data == -1) break;
    System.out.println((char)data);
}
reader.close(); // FileNotFoundException,  IOException에 대한 Exception 처리 필요.

형식을 맞춰서 만들어도 파일이 없을 경우에 대한 익셉션과, 파일 입출력 관련 일반적인 오류에 대한 익셉션 처리를 하지 않으면 에러가 난다. 2개의 익셉션 처리까지 하면 다음과 같다.


2) read 메소드를 이용하여 텍스트 파일을 읽는 프로그램 (완성)
import java.io.*;
class ReaderExample1 {
    public static void main(String args[]) {
       FileReader reader = null;     
       try {                     // 읽고자 하는 파일이 없을 때의 오류, 입출력시 일반 오류가 발생하는 부분
           reader = new FileReader("poem.txt");   // 파일을 여는 부분
           while (true) {            
               int data = reader.read();          // 파일을 읽어서 처리
               if (data == -1)
                   break;
                char ch = (char) data;
                System.out.print(ch);
           }
       }       
       catch (FileNotFoundException fnfe) {   // FileReader의 생성자가 발생하는 익셉션을 처리
           System.out.println("파일이 존재하지 않습니다.");
       }       
       catch (IOException ioe) {    // FileReader의 read, close 메소드가 발생하는 익셉션을 처리
           System.out.println("파일을 읽을 수 없습니다.");
       }       
       finally {   // IOException가 발생하면 파일을 연 상태로 종료되니
          try {
               reader.close();   //  close를 finally로 처리해서 최후에 닫도록 해야함.
          }          
          catch (Exception e) {
          }
       }       
    }
}
※ 결과 : poem.txt 파일을 만들어 내부에 글을 쓴 뒤 위의 프로그램을 실행시키면 파일의 내용이 출력된다.



3) 한꺼번에 여러 문자를 읽는 read 메소드
읽은 문자를 파라미터를 받은 char 배열에 채우는 방식.

int num = reader.read(arr); 

- 파일로부터 문자를 읽었을 때 읽은 문자수를 리턴하고, 끝에 도달하면 -1을 리턴한다.
- 주의사항 : 파라미터로 넘겨주는 배열을 미리 생성해둬야 한다.

char arr[] = new char[100]; // 배열을 미리 생성해둘 것.
int num = reader read(arr);


--------------------------------------------------------------------------------------------------------------------------------

2. FileWriter
- 문자 데이터를 파일에 쓰는 클래스. 

FileWriter writer = new FileWriter(output.txt");
(현재 디렉토리에 output.txt라는 파일을 새로 만들어서 연다.)

1) writer 메소드 : 하나의 문자를 파라미터로 받아 출력하는 가장 간단한 메소드. 

writer.write(ch);  
// ch 부분에 문자를 파일에 쓴다.

2) writer.close(); 파일을 닫는 메소드


1) write 메소드를 이용하여 문자 데이터를 파일에 쓰는 프로그램
import java.io.*;
public class WriterExample1 {
public static void main(String[] args) {
FileWriter writer = null;
try {
writer = new FileWriter("output.txt"); // output.txt 파일을 연다.
char arr[] = { '파', '일', '에', '문', '자', '를', '쓰', '는', '예', '제' };
for (int cnt = 0; cnt < arr.length; cnt++)     // 파일에 반복하여 문자를 쓰는 for문
writer.write(arr[cnt]);
}
catch (IOException ioe) {
System.out.println("파일로 출력할 수 없습니다.");
}
finally {
try {
writer.close(); // 파일을 닫는다.
catch (Exception e) {
}
}
}
}
※ FileWriter 생성자는 FileReader 생성자와 달리 FileZNotFoundException이 아니라 IOException이 발생한다.
따라서 IOException을 처리하는 catch절 하나로 try 블록 안에서 발생하는 모든 익셉션을 처리할 수 있다.


3) 한꺼번에 여러 문자를 출력하는 write 메소드
파라미터로 받은 char 배열의 모든 문자를 파일로 출력한다.

writer.write(arr);

- arr 배열에 있는 모든 문자들을 출력한다.


4) 파일에 원래 있던 내용을 유지하며 뒤에 추가로 쓰기

파일을 열 때 원래 있는 파일의 내용을 유지하고 싶으면 FileWriter 생성자의 2번째 파라미터로 true 값을 넘겨준다.

FileWriter writer = new FileWriter("output.txt", true); 

이렇게 생성한 FileWriter 객체를 이용하여 파일에 데이터를 쓰면 원래 있던 파일의 내용 뒤에 새로 쓰는 내용이 추가된다.



--------------------------------------------------------------------------------------------------------------------------------


이진 데이터를 파일에 읽고/쓰는 클래스 (p440 참조)

3. FileOutputStream 
- 바이트 데이터를 파일로 출력하는 클래스. char 타입이 아닌 데이터를 파일에 쓸 때 사용.
- FileWriter 클래스와 비슷하나 write 메소드는 파라미터를 문자가 아니라 바이트 데이터로 취급한다.


1) FileOutputStream 클래스를 이용해서 바이트 데이터를 파일에 쓰는 프로그램

import java.io.*;
class OutputStreamExample1 {
    public static void main(String args[]) {
       FileOutputStream out = null;
       try {
           out = new FileOutputStream("output.dat"); // 파일을 연다.
           byte arr[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 };  // 20 byte 배열
           for (int cnt = 0; cnt < arr.length; cnt++)  // 파일에 반복해서 byte타입 데이터를 쓴다.
               out.write(arr[cnt]);
       }
       catch (IOException ioe) {
           System.out.println("파일로 출력할 수 없습니다.");
       }
       finally {
          try {
               out.close(); // 파일을 닫는다.
          }          
          catch (Exception e) {
          }
       }
    }
}

2) 결과
위에서 입력한 byte수와 일치하는 20 byte 크기의 output.dat라는 파일이 생성된다.

이 파일은 문자 데이터가 아니기 때문에 텍스트 에디터로는 읽을 수 없다. 
이 파일을 읽기 위해서는 아래의 FileInputStream을 이용해서 바이트 데이터를 읽는 프로그램을 만들어야 한다.



--------------------------------------------------------------------------------------------------------------------------------


4. FileInputStream 
- 파일로부터 바이트 데이터 읽는 클래스. char 타입이 아닌 byte 데이터를 읽을 수 있다.

while (true) {
int data = inputStream.read(); // 데이터를 읽어서
if (data<0) break; // -1이 되면 반복을 중단하고
byte b = (byte) data; // 아니면 byte 타입으로 캐스트
}

※ FileWriter와 기본 문법은 같으나 char이 아니라 byte로 취급하는 것이 다르다.

한꺼번에 여러 byte를 받는 read 메소드의 경우 역시 byte 배열을 파라미터로 받는다.

byte arr = new byte[16]; // byte 타입의 배열 생성
int num = inputStream.read(arr);


예제) FileInputStream 클래스를 이용하여 파일 내용을 16바이트씩 읽어 각 바이트를 16진수로 만들어서 출력하는 프로그램. (실무에서 유용)

1) 파일 내용을 읽어서 16진수로 출력하는 프로그램

import java.io.*;

class FileDump {
public static void main(String args[]) {
if (args.length < 1) {
System.out.println("Usage: java FileDump <filename>");
return;
}
FileInputStream in = null;
try {
in = new FileInputStream(args[0]);    // 파일을 연다.
byte arr[] = new byte[16];             // byte 타입으로 배열 생성
while (true) {
int num = in.read(arr);            // 파일로부터 16비트를 읽는다.
if (num < 0)
break;
for (int cnt = 0; cnt < num; cnt++)
System.out.printf("%02X ", arr[cnt]);
System.out.println();
}
} catch (FileNotFoundException fnfe) {
System.out.println(args[0] + " 파일이 존재하지 않습니다.");
} catch (IOException ioe) {
System.out.println(args[0] + " 파일을 읽을 수 없습니다.");
} finally {
try {
in.close();   // 파일을 닫는다.
} catch (Exception e) {
}
}
}
}

2) 결과
실행할 때 output.dat의 경로명을 입력해줘야만 실행된다.







Posted by netyhobby
,