입출력 기능과 성능을 향상시키는 클래스들 (p444 참조)


FileReader, FileWriter, FileInputStream, FileOutputStream 외에 입출력 기능과 성능을 향상시키는 클래스
(java.io 패키지에 속해는 클래스)

1. 프리미티브 타입의 데이터 입출력 DataInputStream, DataOutputStream

DataInputStream 프리미티브 타입의 데이터를 입력하는 클래스
DataOutputStream 프리미티브 타입의 데이터를 출력하는 클래스

char 타입과 byte 타입이 아닌 다른 프리미티브 타입 데이터를 읽고 쓰는 경우에 사용.
자체적으로 파일을 읽고 쓰는 기능은 없기 때문에 FileOutputStream, FileInputStream과 함께 사용.

1) 프리미티브 타입의 데이터를 파일로 출력하기 (FileOutputStream)
먼저 FileOutputStream 객체를 생성한 뒤 그 객체를 생성자 파라미터로 삼아 DataOutputStream 객체를 생성한다.

FileOutputStream out1 = new FileOutputStream("output.dat");
DataOutputStream out2 = new DataOutputStream(out1);


2) 프리미티브 타입의 데이터를 파일로부터 읽기 (FileInputStream)
먼저 FileInputStream 객체를 생성한 뒤 그 객체를 생성자 파라미터로 삼아 DataInputStream 객체를 생성한다.
FileInputStream int1 = new FileInputStream("input.dat");
DataInputStream in2 = new DataIntputStream(in1);

out.writeUTF("Hello.java"); // 문자열을 읽는 메소드
String str = in.readUTF(); // 문자열을 쓰는 메소드


2. 객체 입출력 ObjectInputStreamObjectOutputStream

ObjectInputStream 프리미티브 타입과 레퍼런스 타입의 데이터를 입력하는 클래스
ObjectOutputStream 프리미티브 타입과 레퍼런스 타입의 데이터를 출력하는 클래스

객체를 읽고 쓰는 경우에 사용. 데이터를 저장하는 기능, 읽는 기능이 없어 FileOutputStream, FileInputStream과 함께 사용.

1) ObjectOutputStream 클래스를 이용하여 객체 출력
객체를 스트림으로 만들어서 출력하는 클래스. 데이터를 파일에 저장하는 기능이 없으므로 FileOutputStream 객체를 생성하여 ObjectOutputStream 클래스의 생성자 파라미터로 넘겨줘야 한다.

FileOutputStream out1 = new FileOutputStream("output.dat");
ObjectOutputStream out2 = new ObjectOutputStream(out1);

객체를 출력하는 메소드
out2.writeObject(obj); // 직렬화 객체만 출력 가능하다.

객체의 직렬화 : 객체를 스트림으로 만드는 것
직렬화 가능한 클래스인지 아닌지는 객체를 생성하는데 사용한 클래스로 결정.


2) ObjectInputStream 클래스를 이용하여 객체 읽기
스트림 형태로 읽어들인 객체를 프로그램에서 사용할 수 있는 객체로 만드는 클래스. FileInputStream과 함께 사용하면 파일에 저장된 객체를 프로그램에서 다시 읽어서 사용 가능하다. FileInputStream 객체를 생성해서 ObjectInputStream 생성자 파라미터로 넘겨줘야 한다.

FileInputStream in1 = new FileInputStream("input.dat");
ObjectInputStream in2 = new ObjectInputStream(in1);

위와 같이 객체 생성 후에는 ObjectInputStream 클래스의 readObject 메소드로 파일에 저장된 객체를 읽을 수 있다.
Object는 자바의 최상위 슈퍼클래스로, Object 클래스 타입으로 리턴된 객체를 원래 클래스 타입으로 사용하려면 캐스트 연산을 겨쳐 원래 타입 변수에 대입해야 한다.

GregorianCalendar obj = (GregorianCalendar) in2.readObject(); 


3. 버퍼를 이용한 입출력 성능 향상 BufferedReaderBufferedInputStream 

파일 입출력에 사용되는 FileReader, FileWriter, FileInputStream, FileOutputStream 클래스는 read, write 메소드를 호출할 때마다 파일로부터 직접 데이터를 읽거나 쓰기 때문에 잦은 보조기억장치 접근으로 프로그램 성능을 떨어뜨린다. 이를 해결 위헤 필요한 데이터를 미리 한꺼번에 읽어두거나, 출력할 데이터를 모았다가 한꺼번에 출력하는 클래스가 Bufferd 클래스.

BufferedInputStream 바이트 입력 스트림을 버퍼링. 
BufferedOutputStream 바이트 출력 스트림을 버퍼링.
BufferedReader 문자 입력 스트림을 버퍼링.
BufferedWriter 문자 출력 스트림을 버퍼링.

각각 FileReader, FileWriter, FileInputStream, FileOutputStream 클래스와 함께 사용한다.


1) BufferedInputStream 클래스의 사용 방법
BufferdInputStream의 생성자 파라미터로 FileInputStream 객체를 넘겨줘야 한다.

FileInputStream in1 = new FileInputStream("input.dat");
BufferdInputStream in2 = new BufferdInputStream(in1);

예제) BufferdInput 클래스를 이용하여 성능을 향상시킨 FileDump 프로그램
import java.io.*;
class FileDump {
    public static void main(String args[]) {
        if (args.length < 1) {
            System.out.println("Usage: java FileDump <filename>");
            return;
        }
        BufferedInputStream in= null;  // 이 두 부분만 추가해주면 된다.
        try {
            in = new BufferedInputStream(
                      new FileInputStream(args[0]));
            byte arr[] = new byte[16];
            while (true) {
                int num = in.read(arr);
                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) BufferedWriter 클래스의 사용 방법
BufferdWriter의 생성자 파라미터로 FileWriter 객체를 생성하여 넘겨줘야 한다.

FileWriter writer1 = new FileWriter("output.dat");
BufferdWriter writer2 = new BufferdWriter(writer1);

BufferedWiter 클래스의 메소드는 write 메소드와 똑같으므로 객체를 생성하는 부분만 수정하면 나머지 부분은 그대로 사용할 수 있다.

예제) Bufferdwriter 클래스를 이용하여 출력성능을 향상시킨 프로그램
import java.io.*;
class WriterExample1 {
    public static void main(String args[]) {
        BufferedWriter writer = null;  // 이 두 부분만 추가해주면 된다.
        try {
            writer = new BufferedWriter(
                         new FileWriter("output.txt"));
            char arr[] = { '뇌', '를', ' ', '자', '극', '하', '는', ' ', 'J', 'a', 'v', 'a' };
            for (int cnt = 0; cnt < arr.length; cnt++)
                writer.write(arr[cnt]);
        }
        catch (IOException ioe) {
            System.out.println("파일로 출력할 수 없습니다.");
        }
        finally {
            try {
                writer.close();
            }          
            catch (Exception e) {
            }
        }
    }
}

※ 버퍼가 다 차기 전까지는 파일에 실제로 데이터를 쓰지 않기 때문에 한 프로그램이 파일에 데이터를 쓰는 동안 다른 프로그램이 그 파일의 내용을 사용하려고 하면 문제가 생길 수 있음.

4. 텍스트의 각 행에 번호를 매기면서 읽는 클래스 LineNumberReader

텍스트를 읽어들일 때 행 번호를 붙이면서 읽는 기능의 클래스. FileReader 클래스와 함께 사용하면 행 번호를 붙여가며 텍스트를 읽을 수 있다.

LineNumberReader 텍스트 파일의 각 행에 번호를 붙여가면서 읽는 클래스

FileReader reader1 = new FileReader("input.txt");
LineNumberReader reader2 = new LineNumberReader(reader1);

이렇게 생성된 LineNumberReader 객체에 대해 readLine 메소드를 호출하면 텍스트 파일을 한 줄씩 읽을 수 있다.

String str = reader2.readLine(); // 텍스트 한 줄을 읽어서 리턴하는 메소드
이 메소드는 파일 끝에 도달하여 읽을 행이 없으면 null을 리턴한다.

int num = reader2.getLineNumber(); // 바로 전에 읽은 행 번호를 리턴하는 메소드



4. 데이터를 포멧해서 출력하는 클래스 PrintWriter, PrintStream

PrintWriter, PrintStream 클래스의 유사성
둘 다 비슷한 기능으로 PrintWriter가 나중에 만들어져서 유용. 하지만 PrintStream을 써야할 때도 있다.

(1) PrintWriter
데이터를 포멧해서 파일로 출력하는 클래스. 먼저 PrintWriter 객체를 생성해야 한다.

PrintWriter writer = new PrintWriter("output.txt"); // 생성자 안에서 파일을 연다.

print, println, printf 메소드를 호출하여 데이터를 출력할 수 있다. 
write 메소드와 달리 데이터를 그대로 출력하는 것이 아니라 문자열로 바꾸거나 포멧하여 출력한다.

1) print : 문자데이터가 아니면 그 데이터를 문자 데이터로 만들어서 출력
writer.print(12); // "12"라는 문자열 출력
writer.print(10000L); // "10000"라는 문자열 출력

2) println :데이터를 출력한 다음에 줄바꿈 문자를 출력

3) printf : 주어진 포멧에 따라 데이터를 포멧하여 출력하는 메소드. 첫 번째 파라미터가 문자열이기만 하면 그 뒤에 오는 파라미터 수에는 제한이 없다. 첫 번째 파라미터는 나머지 파라미터들을 출력할 포멧을 지정하는 문자열로 사용된다.

writer.printf("%d년 %d월 %d일", 2006, 4, 19); // "2006년 4월 19일"라는 문자열을 출력.
writer.printf("파이 - %4.2f", Math.PI); // "파이 = 3.14"라는 문자열을 출력

※ 포맷명세자 : 포멧을 지시하는 역할을 하는 부분으로 %를 붙여서 사용. %d, %4.2f 부분은 그 뒤에 있는 파라미터 값으로 치환된다. 

%d 10진법 정수
%f 부동소수점
%s 문자열
%c 유니코드
%h 해쉬코드
%b True/False 논리형 데이터
%H, k, l 시(00~24, 0~23, 1~12)
%M 분
%S 초
%L 밀리세컨드
%p 오전/오후
%z GMT로부터 오프셋
%Z 시간대의 약식 표현
%s 1970.1.1 00:00:00으로부터 경과한 초
%Y,%y 년도(4자리, 2자리)
%B,%b,%m 월 이름, 약식표기
%d, %e 일
%A, %a 요일, 약식표기
%% %문자 출력
%n 줄바꿈 문자 출력

※ 아큐먼트 인덱스 : 순번에 $를 붙여 사용. 포맷문자열에 있는 포맷명세자는 그 뒤에 오는 파라미터로 치환되는 것이 기본이지만 % 다음에 순번과 $를 쓰면 순서를 바꿀 수도 있다. 날짜와 시간을 포맷할 때 유용하다.

writer.printf("%2$d년 %3$d월 %1$d일", 1, 1919, 3); // "1919년 3월 1일"이라는 문자열 출력
writer.printf("%1$d는 16진수로 %1$x.", 100); // "100은 16진수로 64."이라는 문자열 출력
%1$x : 다음에 오는 1번째 파라미터(1$)를 16진수로 포멧(%x)하라는 의미.

writer.printf("%1$tY년 %1$tm %1$td일", new GregorianCalendar()); // 날짜를 "YYYY년 mm월 dd일"포멧으로 출력
Calendar 타입의 객체가 표현하는 연월일 포맷 명세자극 %tY, %tm, %td인데, 이 포맷명세자에 아규먼트 인덱스를 지정하면 Calendar 객체 하나만 가지고도 연월일을 모두 포맷할 수 있다.


(2) PrintStream
데이터를 포멧해서 파일로 출력하는 구형 클래스. System.out.println, System.out.print, System.out.printf 메소드를 사용. System 클래스의 out 필드는 프로그램이 시작되기 전에 이미 PrintStream 객체를 가지고 있기 때문에 PrintStream 객체를 생성할 필요가 없다.



5. 파일 관리에 사용되는 File 클래스 (p470 참조)
File 클래스를 사용하려면 먼저 File 클래스의 객체를 생성해야 한다. 생성시에는 파일이나 경로명을 파라미터로 넘겨준다.

파라미터가 파일명인 경우
File file = new File("poem.txt");  // 현재 디렉토리의 poen.txt에 대한 File 객체 생성

파라미터가 경로명인 경우
File file = new File("c:\\work\\chap10); // C드라이브의 work 디렉토리 아래 chap10 폴더에 대한 File 객체 생성
※ c 다음 \가 2번인 이유는 자바의 문자열 리터럴 안에서는 역슬래쉬 \가 이스케이프 코드로 사용되기 때문. 
ex) \n(줄바꿈), \t(탭), \\(역슬래쉬 표시) 

File 객체에 파라미터로 넘긴 경로명이 저장되었으면, 다음 파일이나 디렉토리가 있는지 알려주는 exist 메소드를 호출한다.
boolean isThere = file.exists();  // 파일이 있는지 체크하여 있으면 true, 없으면 false로 리턴(boolean)

경로명이 파일인지 디렉토리인지 알고 싶을 때에는 isFile, isDirectory 메소드 사용하면 된다.
boolean isFile = file.isFile();  // 파일인지 체크
boolean isDir = file.isDirectory();  // 디렉토리인지 체크

File클래스의 다음 메소드를 호출하여 파일 또는 디렉토리의 정보를 알아낼 수 있다.
String name = file.getName() // 이름 리턴
long size = file.length()      // 크기를 리턴
long time = file.lastModified()    // 최종 수정일시 리턴
boolean readMode = file.canRead() // 읽기 가능 여부를 리턴
boolean writeMode = file.canWrite() // 쓰기 가능 여부를 리턴
boolean hiddenMode = file.isHidden() // 숨김 여부를 리턴
String parent = file.getParent(); // 부모 디렉토리 경로명을 리턴

Files childs[] = file.listFiles();  // 서브 디렉토리와 파일들의 목록을 리턴


예제) 현재 디렉토리의 서브디렉토리와 파일 목록을 출력하는 프로그램
import java.io.*;
import java.util.*;

class FileExample1 {
public static void main(String args[]) {
File file = new File(".");      // 현재 디렉토리 경로명을 가지고 File 객체를 생성
File arr[] = file.listFiles();
for (int cnt = 0; cnt < arr.length; cnt++) {
String name = arr[cnt].getName(); // 이름 가져오기
if (arr[cnt].isFile()) // 파일인지 체크
System.out.printf("%-25s %7d ", name, arr[cnt].length()); // 크기 체크
else
System.out.printf("%-25s   <DIR> ", name);
long time = arr[cnt].lastModified();  // 서브 디렉토리와 파일들의 목록을 가져옴
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTimeInMillis(time);
System.out.printf("%1$tF %1$tT %n", calendar);
}
}
}
결과) 현재 클래스가 실행된 디렉토리 내용을 출력
.classpath                    483 2016-01-07 09:51:37 
.project                      381 2015-12-09 15:33:56 
.settings                   <DIR> 2015-12-24 16:03:28 
about_class                 <DIR> 2016-01-07 09:14:20 
bin                         <DIR> 2016-01-07 12:41:13 
oracle                      <DIR> 2016-01-06 10:03:20 
output.dat                     20 2016-01-07 17:10:39 
src                         <DIR> 2016-01-05 17:15:06 


Flie 클래스를 이용하여 임시 파일을 생성하는 방법 (creatNewFile)

File file1 = new File("poem.txt");
file1.createNewFile(); // 파일을 새롭게 생성

File file2 = new File("c:\\doc\\회의록.txt");
file2.delete(); // 파일 삭제

File file1 = new File(c:\\올빼미");
file1.mkdir(); // 디렉토리 생성

File file2 = new File("두루미");
file2.delete(); // 디렉토리 삭제


creatTempFile 임시 파일을 만드는데 사용되는 메소드
정적 메소드이므로 File 객체를 생성하지 않고도 호출 가능. 파라미터로는 파일 이름 일부만 넘겨주면 된다.

File tmpFile = file.createTempFile("tmp", ".txt", "tmpDir);
tmp로 시작하고, .txt로 끝나는 임시 파일을, tmpDir이라는 디렉토리에 생성

File Writer writer = new FileWriter(tmpFile);
생성자를 이용하여 파일을 연다.

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


1) 파일을 생성하여 텍스트를 넣는 프로그램 


import java.io.*;

public class WriteExample1 {


public static void main(String[] args) {

FileWriter writer = null;


try {

writer = new FileWriter("C:/study/test.txt");

writer.write("stream으로 작성한 메세지\n");     // IOException

writer.write("FileReader는 읽기 FileWriter는 쓰기"); // IOException

}

catch (IOException e) {

System.out.println(e.getMessage());

}

finally {

try {

writer.close();

}

catch (Exception e) {

}

}

}

}

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

2) 파일을 읽는 프로그램 


import java.io.*;

public class ReadExample1 {


public static void main(String[] args) {

FileReader reader = null;


try {

reader = new FileReader("c:/study/test.txt");

while (true) {

int data = reader.read(); // IOException

if (data == -1)

break;

System.out.print((char) data);

}

}


catch (FileNotFoundException e) {

System.out.println("파일이 없습니다.");

}


catch (IOException e) {

System.out.println("입력오류");

}


finally {

try {

reader.close();

}

catch (Exception e) {

}

}


}

}







Posted by netyhobby
,