SKILL/JAVA

자바 파일 입/출력 개념 정리 (출처: http://blog.daum.net/clamp83/51)

Jedy_Kim 2017. 12. 19. 08:55
728x90

입력(Input)과 출력(Output)은 어떤 방향으로의 데이터의 흐름(Stream)을 말하는 것이다. 

java.io 패키지는 입·출력에 관련된 많은 클래스를 제공한다.



File

File 클래스는 파일 또는 디렉토리에 대한 정보를 제공하는 클래스이다. path란 파일의 경로를 말하는 것으로 파일이 될 수도 있고 디렉토리도 될 수 있다.


path가 디렉토리: "c:\", "c:\Think\"

path가 파일: "abc.txt", "c:\Think\HelloJava.java"


File 클래스의 유용한 생성자

public File(String pathname)

pathname을 경로로 하는 파일 객체를 만든다.

public File(String parent, String child)

'parent + child'를 경로로 하는 파일 객체를 만든다.

public File(File parent, String child)

'parent(부모 파일) + child'를 경로로 하는 파일 객체를 만든다.



 

File f=new File("c:\\abc.txt");

File f=new File("c:\\", "abc.txt");

File f=new File("c:\\");

 

문자 '\'는 다른 문자와 더해져서 특수한 기능을 수행하는 문자로 자기 자신을 나타내고자 할 때는 두 개를 사용해야 한다. 하나만 사용하면 에러가 발생한다.


아래 코드를 실행해 보자.

 

System.out.println("잘 자\n내 꿈꿔~~");

 

다음과 같이 출력될 것이다.

 

잘 자

내 꿈꿔~~

 

'\n'은 두 개의 문자로 이루어져 있지만 하나의 문자로 취급된다. '\n'은 커서를 다음 줄 맨 앞으로 옮겨주는 역할을 하는 문자이다. 이와 같은 문자들을 Escape 문자라고 한다.

 

알아두기

 

Escape 문자

\n -> 개행 문자

\t -> tab키를 누른 것 처음 여러 칸 띄움

\\ -> '\'를 나타낸다.

\"  -> 큰따옴표(")를 나타낸다.

 

 

 

 File 클래스의 유용한 메소드 1

 

public boolean canRead(), public boolean canWrite()

읽을 수 있거나(can Read), 쓸 수 있는(can Write) 파일이면 true를, 아니면 false를 반환한다.

public boolean createNewFile() throws IOException

this가 존재하지 않는 파일이면 새 파일을 만들고 true를 반환하다. this가 존재하는 파일이면 false를 반환한다.

public static File createTempFile(String prefix, String suffix)

                                                       throws IOException

파일 이름이 prefix이고 확장자는 suffix인 임시파일을 임시(Temp)디렉토리에 만든다.

예) File a = File.createTempFile("abc",".txt");

public static File createTempFile( tring prefix, String suffix, File directory)

                                                       throws Exception

임시 파일을 주어진 directory에 생성한다.

public boolean delete()

파일을 삭제한다. 디렉토리면 비어 있어야 삭제할 수 있다. 삭제가 성공적이면 true를 아니면 false를 반환한다.

public void deleteOnExit()

JVM이 종료될 때(프로그램이 끝날 때) 파일을 삭제하도록 요청한다.

public boolean exists()

파일이 존재하면 true를, 아니면 false를 반환한다.

 

 

다음 예제는 파일이 존재하지 않으면 파일을 만드는 예제이다.

 

File1.java

 

import! java.io.*;

 

public class File1{

  public static void main(String[] args){

    File f=new File("c:\\abc.txt");

 

    if(f.exists())                                   // 파일이 존재하면

      System.out.println("파일이 존재합니다.");

    else {                                         // 피일이 존재하지 않으면

      try{

        f.createNewFile();                         // 파일을 만든다.

        System.out.println("파일을 만들었습니다.");

      }

      catch(IOException e){}

    }

  }

}

 


 

출력 결과

 

파일을 만들었습니다.

 


 

 

 File 클래스의 유용한 메소드 2

 

public String getName(), public String getParent(), public String getPath()

각각 파일의 이름, 파일이 있는 디렉토리의 경로, 파일의 경로를 반환한다.

public boolean isDirectory()

this가 디렉토리이면 true를, 아니면 false를 반환한다.

public boolean isFile()

this가 파일이면 true를, 아니면 false를 반환한다.

public boolean isHidden()

숨겨진 파일이면 true를, 아니면 false를 반환한다.

public long lastModified()

마지막으로 수정된 날짜를 long으로 반환한다.

public long length()

파일의 크기(bytes)를 반환한다.

 

 

File2.java

 

import! java.io.*;

 

public class File2{

  public static void main(String[] args){

    File f=new File("C:\\autoexec.bat");

 

    System.out.println(f.isFile());                      // 파일이므로 true

    System.out.println("이름: "+f.getName());          // 파일 이름

    System.out.println("디렉토리: "+f.getParent());     // 파일이 있는 디렉토리

    System.out.println("경로: "+f.getPath());           // 파일의 경로

    System.out.println("크기: "+f.length()+" bytes");    // 파일의 길이

  }

}


 

출력 결과

 

true

이름: autoexec.bat

디렉토리: C:\

경로: C:\autoexec.bat

크기: 274 bytes

 


 

 

 File 클래스의 유용한 메소드 3

 

public String[] list()

this가 디렉토리라면 this안에 있는 파일들을 String 배열로 반환한다.

this가 디렉토리가 아니라면 null을 반환한다.

public File[] listFiles()

this가 디렉토리라면 this안에 있는 파일들을 File 배열로 반환한다.

this가 디렉토리가 아니라면 null을 반환한다.

public boolean mkdir()

this의 이름을 가진 디렉토리를 만든다.

public boolean renameTo(File dest)

파일 이름을 dest로 바꾼다.

public boolean setReadOnly()

파일 속성을 읽기 전용으로 정한다.

 

다음 예제는 'C:\' 안에 있는 디렉토리와 파일을 모두 출력하는 예제이다.

 

 

File3.java

 

import! java.io.File;

 

public class File3{

  public static void main(String[] args){

    File f=new File("c:\\");

 

    File[] fs=f.listFiles();          // 파일 목록을 읽어온다.

 

    for(int i=0; i<fs.length; i++){

      if(fs[i].isDirectory())

        System.out.print("디렉토리: ");

      else

        System.out.print("파일: ");

 

      System.out.println(fs[i]);

    }

  }

}


 

출력 결과

 

디렉토리: c:\My Documents

....

디렉토리: c:\j2sdk1.4.0

...

파일: c:\abc.txt

 


 

 

혼자 해보기

 Alone13_1.java

위 예제 'File3.java'을 응용하여 특정 디렉토리의 내용을 보여주는 프로그램을 만들어보자. 파일의 속성이 함께 출력되도록 해보자.

 

출력 결과 예시

 

java  Alone13_1  c:\ ??

 

디렉토리: c:\My Documents

....

디렉토리: c:\j2sdk1.4.0

...

파일: c:\abc.txt  크기: 30kbyte  숨김: 아니오  날짜: ...

 


 

 

 

Stream

파일로부터 읽기(Input), 또는 파일에 쓰기(Output)를 하기 위해서는 스트림에 대하여 알아야 한다. 스트림이란 '흐름'을 뜻하는 단어인데, 데이터가 흘러서 어떤 대상에 도달하는 과정, 즉 데이터의 흐름을 스트림이라고 한다. 여기서 말하는 대상은 파일 또는 네트워크 등이 된다.


스트림은 지극히 추상적 의미이므로 입·출력을 표현하고 이해하는데 다소 어려움이 있다. 하지만 스트림을 객체로 생각한다면 데이터 흐름을 구체적으로 표현할 수 있고, 또한 이해하기도 쉽다. [그림 13-1]은 Input 또는 Output을 담당하는 스트림 객체를 표현한 것이다. 어떤 대상으로부터 데이터를 읽어오거나, 어떤 대상에게 데이터를 출력할 때, 직접 대상에 접근하지 않고 스트림 객체를 이용한다. 따라서 프로그램에서는 스트림 객체로부터 데이터를 얻거나, 스트림 객체에게 데이터를 넘겨주면 그만이다. 나머지는 스트림 객체가 알아서 해준다.

 

 

InputStream과 OutputStream

스트림 객체들은 크게 Input을 담당하는 스트림과 Output을 담당하는 스트림으로 구분할 수 있다. 이들의 최상위 클래스는 각각 InputSteam과 OutputStream이다.

 

InputStream과 OutputStream는 다음과 같이 추상클래스로 정의되어 있다.

 

public abstract class InputStream{...}

public abstract class OutputStream{...}

 

자신은 객체가 될 수 없지만 객체가 될 수 있는 자식 클래스들이 있다. 이들 자식 클래스들은 byte 단위로 입·출력한다. 왜냐하면 이 두 클래스의 메소드들이 byte 단위로 읽거나 쓰기 때문이다.

 

 

 InputStream 주요 메소드

 

public abstract int read() throws IOException;

스트림으로부터 다음의 1byte를 읽어와서 int로 반환한다. 파일의 모든 데이터를 읽어왔거나 더 이상 읽어 올 데이터가 없으면 -1을 반환한다.

public int read(byte b[]) throws IOException

스트림으로부터 다수의 byte를 읽어와서 b에 대입한다.

실제로 읽어온 byte 수를 반환하거나, 읽어 올 것이 없으면 -1을 반환한다.

public int read(byte b[], int off, int len) throws IOException

스트림으로부터 len 만큼의 byte를 읽어와서 b[off]부터 차례대로 대입한다.

실제로 읽어온 byte 수를 반환하거나, 읽어 올 것이 없으면 -1을 반환한다.

public void close() throws IOException

스트림을 닫는다. 스트림과 관련된 시스템 자원(메모리)을 반납한다.

 

 

 

☞ OutputStream의 주요 메소드

 

public abstract void write(int b) throws IOException;

b를 byte로 형 변환하여 스트림에 출력한다. 1 byte를 기록한다.

public void write(byte b[]) throws IOException

바이트 배열 b를 스트림에 출력한다.

public void write(byte b[], int off, int len) throws IOException

b[off]부터 b[len+off-1]까지의 데이터를 스트림에 출력한다.

public void close() throws IOException

스트림을 닫는다. 스트림과 관련된 시스템 자원(메모리)을 반납한다.

 

 

 

FileInputStream과 FileOutputStream

이 두 클래스는 파일에 입·출력할 수 있는 스트림이다.

 

FileOutputSteam은 OutputStream을 상속하는 클래스로 파일에 데이터를 출력하는 기능을 제공한다.

 

 

 FileOutputStream의 유용한 생성자

 

public FileOutputStream(String name) throws FileNotFoundException

name(파일이름)에 쓰기 위한 스트림 객체를 만든다. 파일이 존재하지 않으면 새로 만들고 파일이 존재하면 지우고 새로 만든다. name이 디렉토리이거나 어떤 이유에서 파일을 만들 수 없다면 예외가 발생한다.

public FileOutputStream(File file) throws FileNotFoundException

file에 쓰기 위한 스트림 객체를 만든다.

public FileOutputStream(String name, boolean append)

name(파일)에 쓰기 위한 스트림 객체를 만든다. 파일이 존재할 때 append가 true이면 기존의 데이터를 지우지 않고 추가한다. append가 false이면 기존의 파일을 지우고 새로 만든다.

public FileOutputStream(File file, boolean append)

file에 쓰기 위한 스트림 객체를 만든다. 파일이 존재할 때 append가 true이면 기존의 데이터를 지우지 않고 추가한다. append가 false이면 기존의 파일을 지우고 새로 만든다.

 

 

FileOutputStream은 OutputStream을 상속하였으므로 OutputStream의 메소드를 모두 가지고 있다. FileOutputStream 객체에게 데이터를 건네주면 FileOutputStream 객체가 알아서 파일에 출력한다.

 

다음 예제는 파일에 대문자를 출력하는 예제이다.

 

File4.java

 

import! java.io.*;

 

public class File4{

  public static void main(String[] args) throws Exception{     // 예외 던지기

    FileOutputStream fos=new FileOutputStream("c:\\알파벳.txt");

    

    for(int i='A'; i<='Z'; i++)

      fos.write(i);       // fos에게 데이터를 보내면 fos는 파일에 출력한다.

 

      fos.close();          // 스트림은 다 쓴 후에 닫아주는 것이 좋다.

  }

}


 

 

메모장 프로그램으로 '알파벳.txt'을 열어보면 A부터 Z까지의 대문자가 기록되어 있을 것이다.

 

 

알아두기

 

영문자와 한글

자바는 모든 문자(char)를 2바이트로 취급한다고 알고 있다. 하지만 영문자는 1바이트로도 표현 가능하다. write('A')와 같이 char를 byte로 형 변환해도 데이터의 손실 없이 그대로 출력이 된다. 그러나 한글 같은 경우는 1바이트로는 표현이 안되기 때문에 write('한')과 같이 하면 형 변환할 때 데이터가 손실되어 '한'이 기록되지 않고 이상한 문자가 기록된다. 한글을 파일에 출력하는 방법은 나중에 살펴볼 것이다.

 

다음 예제는 이전 예제에서 작성한 파일인 '알파벳.txt'에 소문자를 추가하는 예제이다.

 

File5.java

 

import! java.io.*;

 

public class File5{

  public static void main(String[] args) throws Exception{

    // 파일을 추가 모드로 연다.

    FileOutputStream fos=new FileOutputStream("c:\\알파벳.txt", true);

 

    for(int i='a'; i<='z'; i++)

      fos.write(i);

 

    fos.close();

  }

}


 

 

FileInputSteam은 InputStream을 상속하는 클래스로 파일로부터 데이터를 읽어오는 기능을 제공한다.

 

 

 FileInputStream의 유용한 생성자

 

public FileInputStream(String name) throws FileNotFoundException

name(파일이름)으로부터 데이터를 읽어오기 위한 스트림 객체를 만든다. 파일이 존재하지 않으면 예외가 발생한다.

public FileInputStream(File file) throws FileNotFoundException

file로부터 데이터를 읽어오기 위한 스트림 객체를 만든다.

 

 

File6.java는 '알파벳.txt'에 있는 내용을 한 문자씩 읽어서 화면에 출력하는 예제이다.

 

File6.java

 

import! java.io.*;

 

public class File6{

  public static void main(String[] args) throws Exception{

    File f=new File("c:\\알파벳.txt");

    FileInputStream fis=new FileInputStream(f);

    char a;

 

    for(int i=0;i<f.length();i++){     // 파일의 크기만큼 읽어온다.

      

      // read()는 1byte를 읽어와서 int로 반환하므로 char로 형 변환한다.

      a=(char)fis.read();

    

      System.out.print(a);

    }

    fis.close();                    // 스트림을 닫는다.

  }

}


 

출력 결과

 

ABCDEF...YZabc...xyz

 


 

 

File7.java는 '알파벳.txt'에 있는 모든 문자를 읽어와 byte 배열에 기억시키고 화면에 출력하는 예제이다. 위 예제와 출력 결과가 같다.

 

File7.java

 

import! java.io.*;

public class File7{

  public static void main(String[] args) throws Exception{

    File f=new File("c:\\알파벳.txt");

    FileInputStream fis=new FileInputStream(f);

 

    int len=(int)f.length();      // 파일의 크기는 long이므로 int로 형 변환한다.

    byte[] b=new byte[len];    // 파일의 크기만큼 배열을 잡는다.

    fis.read(b);                // 파일로부터 데이터를 모두 읽어와 b에 기억시킨다.

    fis.close();

 

    for(int i=0;i<b.length;i++)             // 출력

       System.out.print((char)b[i]);

  }

}


 

 

 

Filter Stream

InputStream이나 OutputStream은 byte 단위로 읽고 쓰기를 하기 때문에 char, int ,double, String과 같은 것을 처리하려면 많은 어려움이 있다. 그러나 필터 스트림을 이용하면 수월하게 처리할 수 있다. 필터 스트림으로 FilterInputStream과 FilterOutputStream이 있다.

 

다음 그림은 FilterOutputStream을 예로 들어 필터 스트림의 위치를 나타낸 것이다.


위 그림에서 데이터의 흐름을 따라가 보면 다음과 같다.

 

① 데이터를 FilterOutputStream에게 넘겨준다.

② FilterOutputStream은 데이터를 FileOutputStream에게 넘겨준다.

③ FileOutputStream은 데이터를 파일에 출력한다.

 

필터 스트림의 생성자은 어떤 모습일까?

 

protected FilterInputStream(InputStream in)

public FilterOutputStream(OutputStream out)

 

생성자의 인수로 각각 InputStream 객체와 OutputStream 객체를 받고 있는데 이유는 필터 스트림 객체가 데이터를 Input/Output Stream 객체에게 넘겨주기 때문이다.

 

다음 예제를 보자.

 

File8.java

 

import! java.io.*;

 

public class File8{

  public static void main(String[] args) throws Exception{

    File f=new File("c:\\대문자.txt");                          // x1

    FileOutputStream fos=new FileOutputStream(f);             // x2

    FilterOutputStream filter=new FilterOutputStream(fos);      // x3

    

    for(int i='A'; i<='Z';i++)

      filter.write(i);                                          // x4

    

    filter.close();                   // 필터 스트림을 닫으면 fos는 자동으로 닫힌다.

  }

}


 

x1행은 파일 f를 선언한다. x2행은 파일(f)에 쓰기 위한 FileOutputStream의 객체 fos를 만든다. x3행은 fos에 데이터를 보내기 위한 FilterOutputStream의 객체 filter를 만든다. x4행은 filter에게 데이터를 전달한다. 그러면 데이터를 전달받은 filter는 fos에게 데이터를 넘겨주고 fos는 데이터를 파일(f)에 기록한다.

 

필터 스트림은 각각 InputStream과 OutputStream을 상속하기 때문에 물려받은 메소드를 가지고 있다. 그러나 필터 스트림에서 새로 추가된 메소드는 존재하지 않는다.

 

FilterOutputStream의 메소드를 보면 OutputStream에서 상속한 write(), write(byte b[]), write(byte b[], int off, int len)이외의 메소드는 눈을 씻고 찾아봐도 없다. 그렇다면 필터 스트림으로 int, long, String과 같은 데이터를 파일에 기록하지 못한다는 말이 아닌가? 맞다. FilterInputStream이나 FilterOutputStream으로는 어려운 일이다. 그러나 이들을 상속하는 자식 클래스를 사용하면 가능하다.

 

 

 

DataInputStream과 DataOutputStream

이 두 클래스는 각각 FilterInputStream과 FilterOutputStream을 상속한다. 그리고 각각 DataInput 인터페이스와 DataOutput 인터페이스를 구현한다. 다음은 이 두 클래스의 헤더 부분이다.

 

DataInputStream extends FilterInputStream implements DataInput

// FilterInputStream을 상속하고, DataInput을 구현한다.

 

DataOutputStream extends FilterOutputStream implements DataOutput

// FilterOutputStream을 상속하고, DataOutput을 구현한다.

 

DataInput과 DataOutput은 기본 자료를 입·출력할 수 있는 메소드를 제공한다.

 

 

 DataInput 인터페이스의 유용한 메소드

 

boolean readBoolean() throws IOException;

byte readByte() throws IOException;

char readChar() throws IOException;

short readShort() throws IOException;

int readInt() throws IOException;

long readLong() throws IOException;

float readFloat() throws IOException;

double readDouble() throws IOException;

스트림으로부터 해당 데이터를 읽어와 반환한다.

String readUTF() throws IOException;

UTF-8(unicode의 일종) 형태로 문자열을 읽어와 String형으로 반환한다.

 

 

 

 DataOutput 인터페이스의 유용한 메소드

 

void write(int b) throws IOException;                 // b를 byte로 형 변환한다.

void writeBoolean(boolean v) throws IOException;

void writeByte(int v) throws IOException;            // v를 byte로 형 변환한다.

void writeChar(int v) throws IOException;            // v를 char로 형 변환한다.

void writeShort(int v) throws IOException;           // v를 short로 형 변환한다.

void writeInt(int v) throws IOException;

void writeLong(long v) throws IOException;

void writeFloat(float v) throws IOException;

void writeDouble(double v) throws IOException;

주어진 데이터를 스트림에 기록한다.

void writeUTF(String str) throws IOException;

문자열 str을 UTF-8 형태로 스트림에 기록한다.

 

DataInputStream과 DatatOutputStream의 생성자를 살펴보자.

 

public DataInputStream(InputStream in)

public DataOutputStream(OutputStream out)

 

이두 클래스는 필터 스트림을 상속하였기 때문에 역시 필터 스트림이다. 그리고 DataInput과 DataOutput 인터페이스를 구현하였으므로 기본 자료형 입출력도 할 수 있다.

 

이제 다음 예제를 해보자.

 

File9.java

 

import! java.io.*;

 

public class File9{

  public static void main(String[] args) throws Exception{

    File f=new File("c:\\홍길동.dat");

    FileOutputStream fos=new FileOutputStream(f);

    DataOutputStream dos=new DataOutputStream(fos);

 

    dos.writeUTF("홍길동");        // 문자열을 기록한다.

    dos.writeInt(20);              // int를 기록한다.

    dos.writeInt(180);             // int를 기록한다.

    dos.writeUTF("한국");         // 문자열을 기록한다.

 

    dos.close();

    System.out.println("파일이 작성되었습니다.");

  }

}


 

출력 결과

 

파일이 작성되었습니다.

 


 

 

아래 그림을 보고 다시 'File9.java'를 검토하자. 사용법을 익히는 것보다 개념 파악이 중요하다.


'홍길동.dat'으로부터 데이터를 읽어와 보자.

 

File10.java

 

import! java.io.*;

 

public class File10{

  public static void main(String[] args) throws Exception{

    File f=new File("c:\\홍길동.dat");

    FileInputStream fis=new FileInputStream(f);

    DataInputStream dis=new DataInputStream(fis);

    String 이름, 국적;

    int 나이, 키;

 

    // 읽을 때는 기록된 자료형대로 읽어오는 것이 중요하다.

    이름=dis.readUTF();

    나이=dis.readInt();

    키=dis.readInt();

    국적=dis.readUTF();

 

    dis.close();

 

    System.out.println("이름: "+이름);

    System.out.println("나이: "+나이);

    System.out.println("키: "+키);

    System.out.println("국적: "+국적);

  }

}


 

출력 결과

 

이름: 홍길동

나이: 20

키: 180

국적: 한국

 


 

 

  혼자 해보기

 Alone13_2.java

DataOuputStream을 이용하여 다음 데이터를 'stu.dat' 파일에 기록해보자.

 

홍길동  80  75  65  50

서광호  90 100 100 100

임순희  60  70  55  75

아지매  60  80  75  80

홍순희  80  70  90  85

박순길 100  80  90  85

 

※ 데이터는 이름(UTF), 국어(int), 영어(int), 수학(int), 과학(int) 점수 순이다.

 


 

 

  혼자 해보기

 Alone13_3.java

DataInputStream을 이용하여 'stu.dat' 파일의 데이터를 Student 클래스의 객체로 읽어와서 출력해보자.

 

class Student{

  String name;

  int kor;

  int eng;

  int mat;

  int sci;

  Student(){...}

  Student(String name, int kor, int eng, int mat, int sci){...}

  // get 메소드 정의

  // set 메소드 정의

}

 

출력 결과 예시

 

홍길동  80  75  65  50

서광호  90 100 100 100

임순희  60  70  55  75

아지매  60  80  75  80

홍순희  80  70  90  85

박순길 100  80  90  85

 


 

 

 

Character Streams

앞에서 배운 스트림들은 byte 단위로 입·출력하기 때문에 byte Stream이라고 한다. 바이트 스트림으로 문자(2byte)를 입·출력하는 것은 많은 조작을 필요로 할 것이다. 그래서 탄생한 스트림이 바로 Character Stream이다. 캐릭터 스트림는 문자 단위로 입출력하는 스트림으로 Reader와 Writer가 있다. Reader는 문자 입력을 담당하는 클래스이고 Writer는 문자 출력을 담당하는 클래스이다.

 

이 두 클래스는 다음과 같이 생겼다.

 

public abstract class Reader{...}     // 추상 클래스

public abstract class Writer{...}      // 추상 클래스

 

Reader와 Writer의 유용한 메소드는 다음과 같다.

 

 

 Reader 클래스의 유용한 메소드

 

public int read() throws IOException

스트림으로부터 한 문자(Character)를 읽어와 int로 반환한다. 더 이상 읽어올 것이 없다면 -1을 반환한다.

public int read(char cbuf[]) throws IOException

스트림으로부터 문자들(배열의 크기만큼)을 읽어와 문자형 배열 cbuf에 기억시킨다. 더 이상 읽어 올 것이 없다면 -1을 반환한다.

 

 

 Writer 클래스의 유용한 메소드

 

public void write(int c) throws IOException

문자 c를 스트림에 쓴다.

public void write(char cbuf[]) throws IOException

문자 배열 cbuf를 스트림에 쓴다.

public void write(String str) throws IOException

문자열 str을 스트림에 쓴다.

 

Reader나 Writer는 추상 클래스이므로 자체로는 객체가 될 수 없다. 따라서 이들을 상속하는 자식 클래스가 필요하고, 추상 메소드를 오버라이드 함으로써 객체가 될 수 있다.

 

이들을 상속하는 주요 자식 클래스는 다음과 같다.

 

// 문자 단위로 입·출력할 수 있는 스트림

public class InputStreamReader extends Reader{...}

public class OutputStreamWriter extends Writer{...}

 

// 한 줄씩 입·출력할 수 있는 스트림

public class BufferedReader extends Reader{...}

public class BufferedWriter extends Writer {...}

 

 

 

InputStreamReader와 OutputStreamWriter

이 두 클래스는 각각 Reader와 Writer를 상속한다. 따라서 문자 입·출력이 가능하다.

 

InputStreamReader와 OutputStreamWriter의 주요 생성자는 다음과 같다.

 

public InputStreamReader(InputStream in)

public OutputStreamWriter(OutputStream out)

 

생성자를 보면 알겠지만 이들은 필터 스트림의 위치와 같은 위치에 있다. 다음 그림은 파일에 문자 데이터를 기록하는 과정을 나타낸 그림이다.


File11.java

 

import! java.io.*;

 

public class File11{

  public static void main(String[] args) throws Exception{

    

    // Character Output Stream

    FileOutputStream fos=new FileOutputStream("c:\\char.txt");

    OutputStreamWriter osw=new OutputStreamWriter(fos);

 

    osw.write('한'); // 한 문자를 스트림에 보낸다.

    osw.write('글');

 

    osw.close();

 

    // Character Input Stream

    FileInputStream fis=new FileInputStream("c:\\char.txt");

    InputStreamReader isr=new InputStreamReader(fis);

 

    System.out.println((char)isr.read());      // 한 문자를 읽어온다.

    System.out.println((char)isr.read());

    isr.close();

  }

}

 


 

출력 결과

 

 


 

 

 

BufferedReader와 BufferedWriter

이 두 클래스는 각각 Reader와 Writer를 상속한다. 이 클래스들은 내부적으로 버퍼(buffer)를 사용하기 때문에 한 줄씩 입출력할 수 있다.

 

BufferedReader와 BufferedWriter의 주요 생성자는 다음과 같다.

 

public BufferedReader(Reader in)

public BufferedWriter(Writer out)

 

생성자를 보면 알겠지만 이들 객체는 Writer객체 또는 Reader객체 앞에 있다. 다음 그림은 파일에 문자 데이터를 기록하는 과정을 나타낸 그림이다.


 BufferedReader의 유용한 메소드

 

public String readLine() throws IOException

스트림으로부터 한 줄을 읽어와 문자열로 반환한다. 읽어 올 것이 없으면 null을 반환한다.

 

 

 BufferedWriter의 유용한 메소드

 

public void write(String str) throws IOException

문자열 str을 스트림에 출력한다.

public void flush() throws IOException

버퍼에서 남은 데이터를 강제로 스트림에 출력한다.

public void newLine() throws IOException

줄 구분자line separator)를 스트림에 출력한다. 개행 문자('\n')를 출력하는 것이라고 생각하면 된다.

 

 

write 메소드를 호출하여도 데이터가 스트림에 그 즉시 출력되는 것은 아니다. 출력하고자 하는 데이터는 먼저 버퍼에 기억된다. 나중에 때가 되면 버퍼에 있는 데이터를 스트림으로 출력하는 것이다. 따라서 버퍼에 있는 데이터를 스트림에 곧바로 출력하려면 flush를 호출하여야 한다.

 

 

File12.java

 

import! java.io.*;

 

public class File12{

  public static void main(String[] args) throws Exception{

    FileOutputStream fos=new FileOutputStream("c:\\char.txt");

    OutputStreamWriter osw=new OutputStreamWriter(fos);

    BufferedWriter bw=new BufferedWriter(osw);

    

    bw.write("안녕하세요.");       // 문자열을 스트림에 출력한다.

    bw.newLine();                // 줄 구분자를 출력한다.

    bw.write("반갑습니다.^^");

    bw.newLine();

 

    bw.close();

 

    FileInputStream fis=new FileInputStream("c:\\char.txt");

    InputStreamReader isr=new InputStreamReader(fis);

    BufferedReader br=new BufferedReader(isr);

 

    System.out.println(br.readLine());  // 한 줄씩 읽어온다.

    System.out.println(br.readLine());

 

   br.close();

  }

}


 

출력 결과

 

안녕하세요.

반갑습니다.^^

 


 

 

다음 예제는 파일에서 한 줄씩 읽어와 화면에 출력하는 예제이다.

 

File13.java

 

import! java.io.*;

 

public class File13{

  public static void main(String[] args) throws Exception{

    FileInputStream fis=new FileInputStream("c:\\autoexec.bat");

    InputStreamReader isr=new InputStreamReader(fis);

    BufferedReader br=new BufferedReader(isr);

    String s;

 

    // 한 줄씩 읽어서 화면에 출력한다.

    // readLine()은 읽어올 문자가 없다면 null을 반환한다.

    while((s=br.readLine()) != null)  // s가 null이 아닐 동안 반복

      System.out.println(s);

 

    br.close();

  }

}


 

 

 

FileReader와 FileWriter

이 두 클래스는 각각 InputSreamReader와 OutputStreamReader를 상속하는 클래스로, 파일에 문자 입·출력을 제공하는 편리한 클래스이다.

 

FileReader을 이용하면 'File13.java'가 'File14.java'와 같이 간단히 해결된다.

 

File14.java

 

import! java.io.*;

 

public class File14{

  public static void main(String[] args) throws Exception{

    FileReader fr=new FileReader("c:\\autoexec.bat");

    BufferedReader br=new BufferedReader(fr);

    String s;

 

    while((s=br.readLine())!=null)

      System.out.println(s);

 

    br.close();

  }

}

 


 

 

 

System.in으로부터 데이터 얻어오기

java.lang.System 클래스의 in은 다음과 같이 선언되어 있다.

 

public final static InputStream in= nullInputStream();

 

in은 이미 열려있는 InputStream으로 보통 키보드로부터 입력을 받을 때 사용한다.

 

다음 예제는 키보드로부터 1byte를 읽어 오는 예제이다.

 

Keyboard1.java

 

import! java.io.*;

 

public class Keyboard1{

  public static void main(String[] args) throws IOException{

    System.out.println("한 문자를 입력하고 엔터 키를 누르시오.");

    int r=System.in.read();                                 // byte 단위 입력

    System.out.println("누르신 문자는 "+(char)r+" 입니다.");

  }

}


 

출력 결과

 

한 문자를 입력하고 엔터 키를 누르시오.

a

누르신 문자는 a 입니다.

 


 

 

BufferedReader를 이용하면 키보드로부터 한 줄을 읽어올 수 있다.

 

Keyboard2.java

 

import! java.io.*;

 

public class Keyboard2{

  public static void main(String[] args) throws IOException{

    System.out.println("한 줄 입력하고 엔터 키를 누르시오.");

    InputStreamReader isr=new InputStreamReader(System.in);

    BufferedReader br=new BufferedReader(isr);

    

    String r=br.readLine();

    

    System.out.println("\n\n입력하신 문자열: "+r);

  }

}


 

출력 결과

 

한 줄 입력하고 엔터 키를 누르시오.

철수야 놀자...

 

입력하신 문자열: 철수야 놀자...

 


 

다음 예제는 키보드로부터 한 줄씩 읽어서 파일(c:\abc.txt)에 출력하는 예제이다. "eof"를 입력하고 Enter Key를 누르면 파일을 만들고 프로그램이 끝난다.

 

Keyboard3.java

 

import! java.io.*;

public class Keyboard3{

  public static void main(String[] args) throws IOException{

    InputStreamReader isr=new InputStreamReader(System.in);

    BufferedReader br=new BufferedReader(isr);   // 키보드 입력을 위한 스트림

 

    FileWriter fw=new FileWriter("c:\\abc.txt");

    BufferedWriter bw=new BufferedWriter(fw);    // 파일에 기록하기 위한 스트림

    

    System.out.println("내용을 입력하세요(끝:eof)..");

    String data;

 

    while (true){                   // 계속 반복

      data=br.readLine();        // 키보드로부터 한 줄을 읽어와 data에 기억시킨다.

      if(data.equals("eof"))break;   // "eof"를 입력하면 while을 빠져 나온다.

        bw.write(data);           // 파일에 data를 기록한다.

        bw.newLine();

     }

 

     bw.close();

     System.out.println("파일이 만들어졌습니다.");

  }

}


 

 

혼자 해보기

 Alone13_4.java

키보드로부터 세 정수를 읽어와 합계와 평균을 구하는 프로그램을 만들어보자.

 

 

출력 결과 예시

 

첫 번째 정수?

60 ??

두 번째 정수?

70 ??

세 번째 정수?

80 ??

 

<결과>

합계: 210

평균: 70

 


 

 

 

PrintStream과 PrintWriter

이 두 스트림은 출력(인쇄) 스트림으로 많은 부분에서 비슷한 기능을 가진다. 각종 기본 자료를 문자열 형태로 스트림에 출력하며 자동 flush 기능이 있다. 또 내부에서 예외를 처리하기 때문에 예외를 발생시키지 않는다. 예외 발생 여부를 알고싶다면 checkError 메소드를 호출하여 알 수 있다. 이 두 스트림의 주요 차이점으로는 자동 flush 기능이 설정된 상태에 PrintStream은 println을 호출하거나 개행 문자('\n')를 포함한 문자열을 출력하면 자동으로 flush하지만 PrintWriter는 println을 호출할 때만 자동으로 flush한다는 것이다.

 

사실은 PrintStream은 독자도 모르게 계속 사용해 온 것이다. 자바를 배우기 시작하면서 바로 사용하는 System.out이 PrintStream 객체이다.

 

PrintStream과 PrintWriter는 기능 면이나 메소드 면에서 큰 차이가 없으므로 PrintWriter만 살펴보자.

 

 

 PrintWriter 클래스의 유용한 생성자

 

public PrintWriter(Writer out, boolean autoFlush)

Writer 객체 out으로 데이터를 출력하는 객체를 만든다. autoFlush가 true이면 자동으로 flush한다.

public PrintWriter(OutputStream out, boolean autoFlush)

OutputStream 객체 out으로 데이터를 출력하는 객체를 만든다. autoFlush가 true이면 자동으로 flush한다.

 

 

 PrintWriter 클래스의 유용한 메소드

 

public void flush()

버퍼에서 남은 데이터를 스트림에 강제로 출력한다.

public void print(boolean b),

public void print(int I),

public void print(float f),

public void print(char s[]),

public void print(char c),

public void print(long l),

public void print(double d),

public void print(String s)

스트림에 각종 자료를 출력한다.

public void println()

스트림에 줄 구분자(개행 문자)를 출력한다.

public void println(boolean b),

public void println(int I),

public void println(float f),

public void println(char s[]),

public void println(char c),

public void println(long l),

public void println(double d),

public void println(String s)

스트림에 각종 자료를 출력하고 줄 구분자를 출력한다.

public boolean checkError()

에러 여부를 체크한다. 에러가 있으며 true를 반환한다.

 

 

다음 예제는 BufferedReader와 PrintWriter를 이용하여 각각 System.in과 System.out으로 입·출력하는 것이다. 실행하면 사용자가 입력한 내용을 그대로 화면에 출력해준다.

 

PWriter1.java

 

import! java.io.*;

 

public class PWriter1{

  public static void main(String[] args) throws IOException{

 

    BufferedReader br=new BufferedReader(new InputStreamReader(System.in));

    PrintWriter pw=new PrintWriter(System.out, true);  // 자동 flush 기능

  

    String s;

    pw.println("문자를 입력해 보세요.");

    while(!(s=br.readLine()).equals(""))  // 빈 문자열을 입력하면 조건이 거짓이 된다.

      pw.println(s);

 

    br.close();

    pw.close();

  }

}


 

출력 결과

 

문자를 입력해 보세요.

안녕하세요?

안녕하세요?

누구냐?

누구냐?

헐!!!

헐!!!

 


 

 

BufferedReader와 PrintWriter은 네트워크 프로그래밍(채팅 프로그래밍)에서 많이 사용된다.

 

 

 

RandomAccessFile

이 클래스는 임의 접근 파일에 데이터의 읽기·쓰기를 지원하는 클래스이다. 임의 접근 파일이란 파일에 기록된 데이터를 바이트 배열로 생각하여 임의의 위치에 있는 데이터를 읽거나 쓰기를 할 수 있는 파일을 말한다. 임의 접근 파일에는 파일 포인터(file pointer)라는 커서가 존재하는데 이 커서를 옮겨가며 데이터를 읽거나 쓸 수 있다.


RandomAccessFile은 DataInput과 DataOutput을 구현하기 때문에 기본 자료형 데이터를 읽거나 쓸 수 있다. 다음은 RandomAccessFile의 헤더 부분이다.

 

public class RandomAccessFile implements DataOutput, DataInput

 

 

 RandomAccessFile의 유용한 생성자

 

public RandomAccessFile(String name, String mode)

public RandomAccessFile(File file, String mode)

주어진 파일(name, file)을 여는데 주어진 접근모드(mode)로 연다.

 

접근 모드는 "r", "rw", "rws", "rwd" 가 있다.

 

접근 모드(mode)

설 명

"r"

읽기 전용으로 파일을 연다. 파일에 쓰기를 하면 IOException이 발생한다.

"rw", "rws", "rwd"

읽기·쓰기 모드로 파일을 연다. 파일이 존재하지 않으면 파일을 새로 만든다.

[표 13-1] RandomAccessFile의 Access Mode

 

 

 RandomAccessFile의 유용한 메소드

 

public native long getFilePointer() throws IOException;

파일 포인터의 위치를 반환한다.

public native void seek(long pos) throws IOException;

파일 포인터를 pos로 이동시킨다.

public native long length() throws IOException;

파일의 길이를 반환한다.

DataInput으로부터 상속받은 메소드

readBoolean(), readByte(), readChar(), readShort(), readInt(), readLong(),

readFloat(), readDouble(), readUTF()

해당 자료를 읽어온다.

DataOutput으로부터 상속받은 메소드

write(int b), writeBoolean(boolean v), writeByte(int v), writeChar(int v),

writeShort(int v), writeInt(int v), writeLong(long v), writeFloat(float v),

writeDouble(double v), writeUTF(String str)

해당 자료를 파일에 출력한다.

 

 

다음 예제는 파일을 만들고 데이터를 기록하는 예제이다.

 

RAF1.java

 

import! java.io.*;

 

public class RAF1{

  public static void main(String[] args) throws Exception{

    File f=new File("c:\\raf1.txt");

    RandomAccessFile raf=new RandomAccessFile(f,"rw");  // 읽기·쓰기

 

    int a=10;

    double b=12.34;

    String c="abc";

 

    raf.writeInt(a);

    raf.writeDouble(b);

    raf.writeUTF(c);

 

    raf.close();

    System.out.println("파일이 만들어졌습니다.");

  }

}


 

 

다음 예제는 위에서 작성한 파일로부터 데이터를 순차적으로 읽어 오는 예제이다.

 

RAF2.java

 

import! java.io.*;

 

public class RAF2{

  public static void main(String[] args) throws Exception{

    File f=new File("c:\\raf1.txt");

    RandomAccessFile raf=new RandomAccessFile(f,"r");  // 읽기 모드

 

    System.out.println("파일로부터 읽습니다.");

    System.out.println(raf.readInt());

    System.out.println(raf.readDouble());

    System.out.println(raf.readUTF());

 

    raf.close();

  }

}


 

출력 결과

 

파일로부터 읽습니다.

10

12.34

abc

 


 

 

다음 예제는 파일 포인터의 위치를 이동시키면서 일기·쓰기를 해보는 것이다.

 

RAF3.java

 

import! java.io.*;

 

public class RAF3{

  public static void main(String[] args) throws Exception{

    File f=new File("c:\\raf1.txt");

    RandomAccessFile raf=new RandomAccessFile(f,"rw");

    String s="홍길동";

 

    System.out.println("파일의 끝에 데이터를 추가합니다.");

    long len=raf.length();              // 파일의 길이를 구한다.

    raf.seek(len);                     // 파일 포인터를 파일의 끝으로 이동시킨다.

    raf.writeUTF(s);                   // 데이터 기록

 

    System.out.println("방금 기록한 데이터를 읽어옵니다.");

    raf.seek(len);       // len은 데이터를 기록하기 전의 파일 포인터의 위치이다.

    System.out.println(raf.readUTF());

 

    System.out.println("맨 처음 데이터를 읽어옵니다.");

    raf.seek(0);                 // 파일 포인터를 파일의 처음으로 이동시킨다.

    System.out.println(raf.readInt());

 

    raf.close();

  }

}


 

출력 결과

 

파일의 끝에 데이터를 추가합니다.

방금 기록한 데이터를 읽어옵니다.

홍길동

맨 처음 데이터를 읽어옵니다.

10

 


 

 

 

객체 직렬화(Object Serialization)

스트림은 하나의 관을 통해 일렬로 데이터를 전달하기 때문에 비트들의 연속으로 구성된 기본 자료형 데이터를 스트림에 전달하는 것은 그렇게 어렵지 않다. 하지만 데이터의 집합으로 구성된 객체를 스트림에 출력하려면 객체를 구성하는 데이터를 일렬로 배열시킨 뒤 스트림에 기록해야할 것이다. 이와 같은 과정을 객체 직렬화(serialization)라고 한다. 반대로 직렬화 된 데이터를 원래 모습의 객체로 복원하는 것을 직렬해제(deserialization)라고 한다. 객체 직렬화란 한마디로 객체를 스트림에 출력하는 것을 말하고 직렬해제란 스트림으로부터 객체를 얻어오는 것을 말한다.

 

자바의 객체는 직렬화 될 수 있는 객체와 직렬화 될 수 없는 객체로 구분된다. 직렬화 될 수 있는 객체를 예로 들면, String, StringBuffer, Fame, Applet! 등이 있다. API 문서에서 이들 클래스를 찾아보면 Serializable이라는 인터페이스를 implement하고 있음을 알 수 있다. 즉, 직렬화 될 수 있는 클래스는 Serializable 인터페이스를 implement한다. 반대로 직렬화 될 수 없는 클래스는 Serializable 인터페이스를 implement하지 않는다.

 

아래에 있는 Hi 클래스로부터 생성되는 객체, h는 직렬화 될 수 있는 객체이다.

 

class Hi implements java.io.Serializable{

  int a;

  String b;          // String 객체는 직렬화 될 수 있다.

}

 

Hi h=new Hi();      // h는 직렬화 될 수 있다.

 

그런데 Hi 클래스는 Serializable 인터페이스의 추상 메소드를 구현하고 있지 않다. 어찌된 것일까? 사실 Serializable는 추상 메소드를 하나도 가지고 있지 않는다. Serializable의 역할은 단순히 클래스가 직렬화 될 수 있음을 표시하는 것이기 때문이다.

 

 

 

ObjectInput과 ObjectOutput

이들은 각각 DataInput과 DataOutput을 상속하는 인터페이스로 기본 자료형뿐만 아니라 객체형 데이터를 스트림에 입·출력할 수 있는 메소드를 제공한다.

 

ObjectInput은 readObject()라는 메소드를 제공하는데 이 메소드는 스트림으로부터 객체를 읽어오는 역할을 한다. ObjectOutput은 writeObject()라는 메소드를 제공하며 이 메소드는 스트림에 객체를 출력하는 역할을 한다.

 

스트림으로부터 객체를 읽어오는 ObjectInput의 멤버 메소드

 

public Object readObject() throws ClassNotFoundException, IOException;

 

스트림에 객체를 출력하는 ObjectOutput의 멤버 메소드

 

public void writeObject(Object obj) throws IOException;

 

ObjectInput과 ObjectOutput은 인터페이스이므로 자체로는 객체가 될 수 없다. 그러나 이들을 구현하는 클래스, ObjectInputStream과 ObjectOutputStream이 있으므로 걱정이(?) 없다. 상속 관계가 조금은 복잡하지만 그렇게 어렵지 않으므로 차근차근 살펴보자.

 

 

 

ObjectOutputStream

이 놈은 OutputStream을 상속하며 동시에 ObjectOutput을 구현하는 클래스로 객체를 직렬화 하여 Stream에 출력하는 역할을 한다.

 

이 클래스의 생성자는 다음과 같다.

 

public ObjectOutputStream(OutputStream out) throws IOException

 

ObjectOutputStream의 위치를 그림으로 그려본다면 다음 그림과 같을 것이다.



다음은 객체를 파일에 출력하는 예제이다.

 

Serialize1.java

 

import! java.io.*;

 

class Man implements Serializable{  // Man 클래스의 객체는 직렬화 될 수 있다.

  String 이름;

  int 나이;

  double 키;

}

 

public class Serialize1{

  public static void main(String[] args) throws Exception{

 

    FileOutputStream fos=new FileOutputStream("c:\\obj.dat");

    ObjectOutputStream oos=new ObjectOutputStream(fos);

 

    Man m = new Man();

    m.이름 = "김민경";

    m.나이 = 26;

    m.키 = 168.0;

 

    oos.writeObject(m);          // 객체를 스트림에 출력한다.

 

    oos.close();

    System.out.println("객체를 파일에 출력하였습니다.");

  }

}


 

 

 

ObjectInputStream

이 놈은 InputStream을 상속하며 동시에 ObjectInput을 구현하는 클래스로 스트림으로부터 객체를 읽어오는 역할을 한다.

 

이 클래스의 생성자는 다음과 같다.

 

public ObjectInputStream(InputStream in) throws IOException

 

 

다음은 이전 예제에서 만들었던 파일로부터 객체를 읽어오는 예제이다.

 

Serialize2.java

 

import! java.io.*;

 

public class Serialize2{

  public static void main(String[] args) throws Exception{

    FileInputStream fis=new FileInputStream("c:\\obj.dat");

    ObjectInputStream ois=new ObjectInputStream(fis);

    

    Man m;

    

    m=(Man)ois.readObject();          // x1

    

    ois.close();

    

    System.out.println(m.이름);

    System.out.println(m.나이);

    System.out.println(m.키);

  }

}


 

출력 결과

 

박철수

25

175.5

 


 

 

x1행을 보자. readObjet는 스트림으로부터 객체를 읽어와 Object형으로 반환하기 때문에 Man형으로 형 변환해야 한다.

 

 

 

 

연습 문제

 

 

1. 키보드로부터 이름, 국어, 영어, 수학, 과학 점수를 얻어와서 Student형 객체에 대입하고 파일에 기록해보자.

 

파일 이름: students.dat

사용할 스트림: ObjectOutputStream

 

class Student{

  String name;                   // 이름

  int[] record = new int[4];      // 점수 배열

  int total;                       // 총점

  float avg;                      // 평균

  String grade;                   // 학점

  // 생성자 정의

  // get과 set 메소드 정의

  // 총점, 평균, 학점을 반환하는 메소드 정의

}

 

학점은 다음 표를 참고한다.

 

점수

학점

90~100

A

80~ 89

B

70~ 79

C

60~ 69

D

 0~ 59

F

 

실행 결과 예시

 

이름, 국어, 영어, 수학, 과학을 순서대로 입력하세요.(eof: 입력 종료)

홍길동 50 70 85 90 ??

김흥수 90 80 60 40

박철수 60 70 50 95

...

eof

 

<파일의 내용>

  Student형 객체1(이름, 국어, 영어, 수학, 과학, 총점, 평균, 학점)

  Student형 객체2(이름, 국어, 영어, 수학, 과학, 총점, 평균, 학점)

  Student형 객체3(이름, 국어, 영어, 수학, 과학, 총점, 평균, 학점)

  ...

 


 

 

2. 1번 문제에서 생성된 파일 'students.dat'로부터 객체들을 읽어와서 평균의 내림차순으로 정렬해보자.

 

실행 결과 예시

 

 이름   국어  영어  수학  과학  총점  평균  학점  순위

홍길동   50    70    85    90   295   73.8   C     1

박철수   60    70    50    95   275   68.8   D     2

김흥수   90    80    60    40   270   67.5   D     3

...

 

 


 

 

 

3. 1번 문제에서 생성된 파일 'students.dat'로부터 객체들을 읽어와서 평균의 오름차순으로 정렬하여 파일 'orderByAvg.dat'에 기록해보자.

 

사용할 스트림: BufferedWriter

 

파일의 내용 예시

 

김흥수   90    80    60    40   270   67.5   D

박철수   60    70    50    95   275   68.8   D

홍길동   50    70    85    90   295   73.8   C

...

 


 

 

4. 1번 문제에서 생성된 파일 'students.dat'로부터 객체들을 읽어와서 이름의 오름차순으로 정렬하여 파일 'orderByName.dat'에 기록해보자.

 

사용할 스트림: PrinterWriter

 

파일의 내용 예시

 

김흥수   90    80    60    40   270   67.5   D

박철수   60    70    50    95   275   68.8   D

홍길동   50    70    85    90   295   73.8   C

...

 


 

 

 

5. 1번 문제에서 생성된 파일 'students.dat'로부터 객체들을 읽어와서 수학점수의 오름차순으로 정렬하여 파일 'orderByMat.dat'에 기록해보자.

 

사용할 스트림: RandomAccessFile

 

 

파일의 내용 예시

 

박철수   60    70    50    95   275   68.8   D

김흥수   90    80    60    40   270   67.5   D

홍길동   50    70    85    90   295   73.8   C

...

















반응형