13. 입 / 출력프로그래밍 일반적으로입출력은파일로부터데이터를읽어오거나파일에데이터를쓰는작업을말합니다. 자바에서입출력은파일입출력은물론이고인터넷에있는 URL도파일처럼입출력할수있는강력한 API를제공합니다. 그러나기능이뛰어난만큼다루기어려운점도있습니다. 따라서많은사람들이입출력관련 API를사용할때어려움을겪는것이사실입니다. 입출력을이용한프로그램을개발할때, 무엇보다도 API문서를잘살펴보는것이매우중요합니다. 13장의주요내용입니다. - 노드스트림클래스와필터스트림클래스 - 바이트스트림클래스와문자스트림클래스 - 파일 (File) 과 URL - RandomAccessFile - Serialization
Java 자바야놀자 13.1. 스트림 (Streams) 입출력을이해하기전에스트림이라는용어부터알아야합니다. 스트림은 source에서, sink로의데이터흐름을말합니다. source는데이터흐름의출발점이며, sink는데이터흐름이끝나는지점을의미합니다. source로부터나오는데이터흐름입력스트림이라고하며, sink로의데이터흐름을출력스트림이라고합니다. 예를들어 c:\temp\in.txt 파일을읽는프로그램을개발하려면 in.txt 파일이입력스트림이되고, 반대로 out.txt 파일에무언가를쓰려고하면그파일이출력스트림이되는것입니다. source와 sink를합해서노드라고하는데, 노드의종류로는디스크상의파일, 메모리, 또는스레드나프로세스사이에서채널역할을하는파이프등이있습니다. 디스크파일이나메모리영역과같은노드에서읽거나쓰는스트림을노드스트림 (Node Stream) 이라합니다. 일단스트림에서데이터를읽으려면노드스트림이필요한데, 노드스트림을통해서만노드로부터데이터를읽거나쓸수있기때문입니다. 자바는입출력을수행할때문자 (char) 단위스트림과바이트 (byte) 단위스트림형식을 지원합니다. 다음표와같이문자자료의입출력은 Reader 와 Writer 에의해이루어지고, 바이트자료의 입출력은 InputStream 과 OutputStream 에의해이루어집니다. Byte Streams Character Streams Source Streams InputStream Reader Sink Streams OutputStream Writer 13.1.1. 노드스트림 앞에서도잠깐언급한바와같이자바에서는 3 가지종류의노드 ( 파일, 메모리, 파이프 ) 를 지원하는데각노드와연결될수있는클래스는다음표와같습니다. File Memory : Array Byte Streams FileInputStream FileOutputStream ByteArrayInputStream ByteArrayOutputStream Memory : String - Pipe PipedInputStream PipedOutputStream Character Streams FileReader FileWriter CharArrayReader CharArrayWriter StringReader StringWriter PipedReader PipedWriter
Chapter 입 / 출력프로그래밍 13 입출력수행을위해노드와연결하려면앞의표에있는클래스의객체를생성하면됩니다. 그다음각클래스에정의되어있는메서드를이용하여원하는작업을수행합니다. 다음은노드스트림의사용예를보인것입니다. FileReader input = new FileReader("c:\in.txt"); input.read(); 앞의예를보면 "c:\in.txt" 파일을읽기위해노드스트림인 FileReader객체를생성했습니다. FileReader 클래스의메서드들을이용하면파일에서데이터를읽을수있습니다. 예를들어 FileReader 클래스에는 read() 메서드가있는데, 이를호출하면파일로부터데이터를읽어올수있습니다. 노드스트림클래스들을이용하면데이터를읽거나쓸수있습니다. FileReader 클래스의 read() 메서드는다음과같습니다. public int read() throws IOException : 파일로부터한문자를읽어리턴합니다. public int read(char[] cbuf) throws IOException : 파일로부터최대 cbuf 크기만큼읽어 cbuf에저장하고, 읽은문자의수를리턴합니다. public int read(char[] cbuf, int offset, int length) throws IOException : 파일로부터데이터를읽어 cbuf의 offset 인덱스위치부터 length 개수만큼 cbuf에저장하고읽은문자의수를리턴합니다. 먼저텍스트파일의내용을읽어화면에출력하는예를보겠습니다. ReadFileExample.java 1: import java.io.fileinputstream; 2: import java.io.filenotfoundexception; 3: import java.io.ioexception; 4: 5: public class ReadFileExample { 6: 7: public static void main(string[] args) { 8: FileInputStream fis = null; 9: 10: try { 11: // 입력스트림객체생성 12: fis = new FileInputStream("in.txt"); 13: 14: // 입력한데이터를저장할변수선언 15: byte[] buffer = new byte[256]; 16: 17: int readcount = fis.read(buffer); // 처음블록을읽는다. 18: 19: while(readcount!= -1) { 20: String data = new String(buffer, 0, readcount); 21: System.out.println(data); 22: 23: readcount = fis.read(buffer); // 다음블록을읽는다.
Java 자바야놀자 24: } 25: 26: } catch (FileNotFoundException e) { 27: System.out.println(" 파일이존재하지않습니다."); 28: } catch (IOException e) { 29: System.out.println(e.getMessage()); 30: } finally { 31: if(fis!=null) 32: try {fis.close();} catch(exception e){} 33: } 34: } 35: } String data = new String(buffer, 0, readcount); 위의코드에서 buffer 의내용을출력하기위해 String 객체로생성합니다. String 객체생 성시 buffer 의내용에서 0 번인덱스부터 readcount 개수만큼만문자열로생성해야마지 막직전에읽었던내용이다시출력되는현상을방지할수있습니다. 예제를이클립스에서실행시키려면 in.txt 파일을프로젝트폴더에작성하세요. in.txt 파일 은 src 폴더또는패키지폴더안에넣으면안됩니다. in.txt 파일이없으면실행이안됩 니다. 위의예제는파일로부터데이터를읽을때 byte 단위로읽어문자열객체로생성합니다. in.txt 파일의내용이한글을포함할경우출력되는데이터의일부가깨질수있습니다. 파 일이한글을포함한다면 FileReader 를이용하면됩니다. 다음코드는 FileReader 클래스를이용하여데이터를읽고지정한파일에내용을출력하 는프로그램입니다. in.txt 파일을읽어 out.txt 파일에내용을복사합니다. NodeStreamExample.java 1: import java.io.filereader; 2: import java.io.filewriter; 3: import java.io.ioexception; 4: 5: public class NodeStreamExample { 6: public static void main(string[] args) {
Chapter 입 / 출력프로그래밍 13 7: FileReader input = null; 8: FileWriter output = null; 9: try { 10: String infile = "in.txt"; 11: String outfile = "out.txt"; 12: input = new FileReader(inFile); 13: output = new FileWriter(outFile); 14: 15: char[] buffer = new char[128]; 16: 17: int readcount = input.read(buffer); 18: while ( readcount!= -1 ) { 19: output.write(buffer, 0, readcount); 20: readcount = input.read(buffer); 21: } 22: System.out.println(" 파일이복사되었습니다."); 23: } catch (IOException e) { 24: e.printstacktrace(); 25: } finally { 26: if(input!= null) 27: try {input.close();} catch (IOException e) {} 28: if(output!= null) 29: try {output.close();} catch (IOException e) {} 30: } 31: } 32: } 위의예제코드를실행하면 out.txt 파일이생성됩니다. 내용은 in.txt 파일에작성한내용 과동일합니다. 이클립스에서예제코드를실행시켰다면, 실행후생성되는 out.txt 파일이 이클립스의패키지익스플로러에나타나게하려면프로젝트를 Refresh(F5) 해야합니다.
Java 자바야놀자 13.1.2 필터스트림 필터스트림 (Filter Stream) 은처리스트림 (Processing Stream) 이라고도하며다른객체를 둘러싸는역할을합니다. 필터스트림들을사용하는이유는노드스트림의부족한기능을보완하여좀더정밀한입출력을하기위해서입니다. 예들들어 FileReader클래스의노드스트림은파일에서텍스트를읽어올때한문자씩읽는낮은수준의메서드 (read() 메서드 ) 만가지고있는반면, BufferedReader클래스등의필터스트림은줄단위로읽어 String으로반환하는고급메서드 (readline() 메서드 ) 를포함하고있기때문에좀더편리하게입출력작업을할수있는것입니다. 다음표는필터스트림클래스를나타낸것입니다. Type Byte Streams Character Streams Buffering Data conversion Filtering Converting bytes character Object Serialization BufferedInputStream BufferedOutputStream DataInputStream DataOutputStream FilterInputStream FilterOutputStream - ObjectInputStream ObjectOutputStream BufferedReader BufferedWriter - FilterReader FilterWriter InputStreamReader OutputStreamWriter - Counting LineNumberInputStream LineNumberReader Printing PrintStream PrintWriter FilterXxx 클래스는추상 (abstract) 클래스이며다른필터클래스들의상위클래스입니 다. 사용자정의필터스트림클래스를만들때사용할수있습니다.
Chapter 입 / 출력프로그래밍 13 다음은필터스트림의사용예를보인것입니다. FileReader input = new FileReader("c:\in.txt"); BufferedReader bufinput = new BufferedReader(input); bufinput.readline(); 앞의예에서 BufferedReader클래스의인자로 FileReader클래스의객체가사용되었습니다. 이렇게 BufferedReader클래스를사용하면 readline() 메서드를이용하여데이터를라인단위로읽을수있습니다. 다음프로그램은앞의예제와같이파일을복사하는프로그램입니다. 앞프로그램과다른 점은문자단위로읽지않고, BufferedReader 와 BufferedWriter 를이용하여라인단위로 입 / 출력처리를합니다. FilterStreamExample.java 1: import java.io.bufferedreader; 2: import java.io.bufferedwriter; 3: import java.io.filereader; 4: import java.io.filewriter; 5: import java.io.ioexception; 6: 7: public class FilterStreamExample { 8: public static void main(string[] args) { 9: FileReader input = null; 10: FileWriter output = null; 11: BufferedReader bufinput = null; 12: BufferedWriter bufoutput = null; 13: try { 14: String infile = "in.txt"; 15: String outfile = "out2.txt"; 16: 17: input = new FileReader(inFile); 18: output = new FileWriter(outFile); 19: 20: bufinput = new BufferedReader(input); 21: bufoutput = new BufferedWriter(output); 22: 23: String line; 24: line = bufinput.readline(); 25: while ( line!= null ) { 26: bufoutput.write(line, 0, line.length()); 27: bufoutput.newline(); 28: line = bufinput.readline(); 29: } 30: System.out.println(inFile + " >> " + outfile); 31: } catch (IOException e) { 32: e.printstacktrace(); 33: } finally {
Java 자바야놀자 34: if(bufinput!= null) 35: try {bufinput.close();} catch (IOException e) {} 36: if(bufoutput!= null) 37: try {bufoutput.close();} catch (IOException e) {} 38: } 39: } 40: } 이예제에서는 FileReader 와 FileWriter 클래스외에 BufferedReader 와 BufferedWriter 클래스가사용되었는데 BufferedReader 와 BufferedWriter 클래스가필터스트림클래스에 해당됩니다. 사용자가원하는필터스트림클래스를만들려면 FilterXxx( 예 : FilterReader) 형식의 abstract 클래스를상속받아구현할수있습니다. 자바에서의입출력은노드스트림이나필터스트림중에서상황에맞는스트림을선택하여사용합니다. 특히자바에서는다양한입출력 API를제공하기때문에자주 API 문서를참고해야합니다. 또, 어떤클래스가노드스트림이고어떤클래스가필터스트림인지암기할필요는없고 API문서에서사용할클래스생성자가노드스트림역할을하는지필터스트림역할을하는지를구별하면됩니다. 필터스트림클래스와노드스트림클래스가같이사용됐을경우 finally 블록에서는어플리케이션과가장가까이있는스트림, 즉필터스트림만닫아줘도됩니다. 다음표는노드스트림클래스에해당하는 FileInputStream 클래스의생성자입니다. 생성자와설명 FileInputStream(File file) 파일시스템에서주어진파일객체에의해지정된파일의연결을열어 FileInputStream 객체를생성합니다. FileInputStream(FileDescriptor fdobj) 파일시스템에서주어진파일기술자객체에의해지정된파일의연결을열어 FileInputStream 객체를생성합니다. FileInputStream(String name) 파일시스템에서주어진파일명으로파일의연결을열어 FileInputStream 객체를생성합니다. 다음표는필터스트림클래스에해당하는 DataInputStream 클래스의생성자입니다. 생성자와설명 DataInputStream(InputStream in) 지정된기본 InputStream 을사용하는 DataInputStream 을생성합니다. 위의두스트림클래스생성자의인자를주의해서보세요. FileInputStrem클래스의경우 3개의생성자가있습니다. FileInputStrem클래스의생성자인자는모두파일과관련된것들입니다. 그리고이들생성자는파일에직접연결을열기때문에노드스트림임을알수있습니다. 그러나 DataInputStream클래스의생성자인자로노드스트림인 InputStream 클래스의객체가사용되었습니다. 이렇게생성자의인수로다른스트림이오는클래스들을필터스트림클래스라고부릅니다.
Chapter 입 / 출력프로그래밍 13 13.2. 입 / 출력클래스 13.2.1. 바이트스트림클래스 다음그림은자주사용되는바이트스트림들의상속관계를나타낸것입니다. 모든클래스 들을다나타내진않았습니다. 더자세한내용을 API 문서를참고하세요.
Java 자바야놀자 FileInputStream 과 FileOutputStream 이클래스들은파일입력및출력에사용되는노드스트림클래스입니다. 객체를생성할때 FileInputStream 클래스는파일이읽기가능한상태여야하며, FileOutputStream 클래스는 파일이없으면새로운파일을생성하고, 있으면기존파일을덮어쓰게됩니다. FileInputStream infile = new FileInputStream("in.txt"); FileOutputStream outfile = new FileOutputStream("out.txt"); 다음프로그램은앞의파일복사예제를 FileInpuStream 과 FileOutputStream 클래스를 사용하여작성한것입니다. FileIOExample.java 1: import java.io.fileinputstream; 2: import java.io.filenotfoundexception; 3: import java.io.fileoutputstream; 4: import java.io.ioexception; 5: 6: public class FileIOExample { 7: public static void main(string [] args) { 8: String infile = "in.txt"; 9: String outfile = "out3.txt"; 10: 11: FileInputStream fis = null; 12: FileOutputStream fos = null; 13: 14: try { 15: fis = new FileInputStream(inFile); 16: fos = new FileOutputStream(outFile); 17: int readbyte = 0; 18: while ((readbyte = fis.read())!= -1) { 19: fos.write(readbyte); 20: } 21: System.out.println(inFile + " >> " + outfile); 22: } catch (FileNotFoundException e) { 23: System.out.println(" 파일이존재하지않습니다."); 24: } catch (IOException e) { 25: System.out.println(e.getMessage()); 26: } finally { 27: if(fis!=null) 28: try { fis.close(); } catch (IOException e) { } 29: if(fos!=null) 30: try { fos.close(); } catch (IOException e) { } 31: } 32: } 33: }
Chapter 입 / 출력프로그래밍 13 FileIOExample 예제프로그램은노드스트림인 FileInputStream 과 FileOuputStream 만을 사용하고있습니다. read() 와 write() 메서드는 1 바이트를읽고쓰는메서드입니다. DataInputStream 과 DataOutputStream 이클래스는필터스트림으로 Primitive 형데이터를읽거나쓸때사용합니다. 자바에서사 용하는여러가지데이터유형을쉽게입출력처리하기위한많은메서드를가지고있습니 다. 다음프로그램은 DataInputStream 클래스를이용하여파일에 " 이름 ", " 사번 ", " 나이 " 를읽 고쓰는예입니다. DataIOExample.java 1: import java.io.datainputstream; 2: import java.io.dataoutputstream; 3: import java.io.fileinputstream; 4: import java.io.filenotfoundexception; 5: import java.io.fileoutputstream; 6: import java.io.ioexception; 7: 8: public class DataIOExample { 9: public static void main(string [] args) { 10: String outfile = "employee.txt"; 11: 12: FileOutputStream fos = null; 13: DataOutputStream dos = null; 14: try { 15: fos = new FileOutputStream(outFile); 16: dos = new DataOutputStream(fos); 17: dos.writeutf(" 허현준 "); 18: dos.writeutf("41456"); 19: dos.writeint(30); 20: dos.writeutf(" 정준수 "); 21: dos.writeutf("41457"); 22: dos.writeint(31); 23: System.out.println(" 데이터가저장되었습니다."); 24: } catch (FileNotFoundException e) { 25: System.out.println(" 파일이존재하지않습니다."); 26: } catch (IOException e) { 27: System.out.println(e.getMessage()); 28: } finally { 29: if(dos!=null) 30: try { dos.close(); } catch (IOException e) { } 31: } 32:
Java 자바야놀자 33: System.out.println("\n 저장된데이터를불러옵니다."); 34: FileInputStream fis = null; 35: DataInputStream dis = null; 36: try { 37: fis = new FileInputStream(outFile); 38: dis = new DataInputStream(fis); 39: System.out.println(" 이름 : " + dis.readutf()); 40: System.out.println(" 사번 : " + dis.readutf()); 41: System.out.println(" 나이 : " + dis.readint()); 42: System.out.println(" 이름 : " + dis.readutf()); 43: System.out.println(" 사번 : " + dis.readutf()); 44: System.out.println(" 나이 : " + dis.readint()); 45: } catch (FileNotFoundException e) { 46: System.out.println(" 파일이존재하지않습니다."); 47: } catch (IOException e) { 48: System.out.println(e.getMessage()); 49: } finally { 50: if(dis!=null) 51: try { dis.close(); } catch (IOException e) { } 52: } 53: } 54: } 이예제프로그램은 DataInputStream 클래스와 DataOutputStream 클래스의사용형태를 잘보여주고있습니다. 이처럼기본데이터타입의입출력에는 DataInputStream 클래스와 DataOutputStream 클래스를사용합니다.
Chapter 입 / 출력프로그래밍 13 13.2.2. 문자스트림클래스 앞에서설명한 InputStream, OutputStream은바이트단위로입출력동작을수행하지만한글의경우 2바이트이기때문에바이트단위처리시글자가깨질수있습니다. 따라서이러한문제점을없애기위해자바에서는문자나문자열을다룰때, 유니코드 (16bit-Unicode) 방식을제공하고있습니다. 유니코드를사용하는입출력클래스를 Reader와 Writer라고부르며, 이들 Reader와 Writer 클래스들을사용하면자동으로바이트가유니코드화되므로한글같은 2 바이트문자도처리할수있습니다. 다음그림은자주사용되는문자스트림클래스들의상속도를나타낸것입니다.
Java 자바야놀자 InputStreamReader 와 OutputStreamWriter - 이클래스는 byte 스트림 (InputStream, OutputStream) 과 char 스트림 (Character Reader, Writer 사이의인터페이스역할을합니다. InputStreamReader 는 byte 단위입력스트림을 char 단위입력스트림으로변환하며 OutputStreamWriter 는 char 단위출력스트림을 byte 단위출력스트림으로변환합니다. FileReader 와 FileWriter - 이클래스는노드스트림클래스이며 FileInputStream 이나 FileOutputStream 과같은역할을하 는데, 바이트단위가아닌유니코드문자단위로파일입 / 출력처리를합니다. BufferedReader 와 BufferedWriter - 이클래스는필터스트림클래스이며입출력효율을증가시켜줍니다. StringReader 와 StringWriter - 이클래스는노드스트림클래스이며문자열객체를읽고쓰는데사용합니다. PipedReader 와 PipedWriter - 이클래스는스레드사이의통신을위한연결통로로사용됩니다. 다음프로그램은키보드에서문자열을입력받아파일에저장하는예입니다. StringInputExample.java 1: import java.io.bufferedreader; 2: import java.io.bufferedwriter; 3: import java.io.filenotfoundexception; 4: import java.io.fileoutputstream; 5: import java.io.ioexception; 6: import java.io.inputstreamreader; 7: import java.io.outputstreamwriter; 8: 9: public class StringInputExample { 10: public static void main(string [] args) { 11: String outfile = "out4.txt"; 12: InputStreamReader isr = null; 13: BufferedReader br = null; 14: 15: FileOutputStream fos = null; 16: OutputStreamWriter osw = null; 17: BufferedWriter bw = null; 18:
Chapter 입 / 출력프로그래밍 13 19: String inputstring; 20: System.out.println(" 파일에저장할내용을입력한다음 Ctrl+Z 를누르세요."); 21: 22: try { 23: isr = new InputStreamReader(System.in); 24: br = new BufferedReader(isr); 25: 26: fos = new FileOutputStream(outFile); 27: osw = new OutputStreamWriter(fos); 28: bw = new BufferedWriter(osw); 29: 30: while((inputstring = br.readline())!= null) { 31: bw.write(inputstring + "\n"); 32: } 33: } catch (FileNotFoundException e) { 34: System.out.println(" 파일이존재하지않습니다."); 35: } catch (IOException e) { 36: System.out.println(e.getMessage()); 37: } finally { 38: if(br!=null) 39: try { br.close(); } catch (IOException e) { } 40: if(bw!=null) 41: try { bw.close(); } catch (IOException e) { } 42: } 43: } 44: } 이프로그램이실행될때저장할문장을입력한다음 Ctrl+Z( 유닉스시스템에서는 Ctrl+D) 를눌러스트림의끝을알려줍니다.
Java 자바야놀자 예제코드에서 InputStreamReader가사용되었습니다. InputStreamReader 클래스는필터스트림클래스입니다. 따라서 InputStreamReader의인자로 System.in을주었습니다. API문서를살펴보면 System.in이 InputStream임을알수있습니다.( 앞에서설명했지만, InputStream은노드스트림입니다.) BufferedReader클래스는내부적으로버퍼를이용해서입출력의성능을극대화시키기위해서사용합니다. readline() 메서드는줄단위로읽는메서드입니다. 이예에서는엔터키를누르기전까지사용자가입력한내용을한꺼번에읽습니다. 사용자의입력을한번에읽어오고입출력성능을높이기위해 BufferedReader클래스를사용하였습니다. finally 블록의 close() 메서드는 open된파일을닫아줍니다. 스트림을닫을때에는어플리케이션과가장가까운스트림을닫아줘야합니다. 위예제에서출력스트림객체 fos, osw, bw 중에서 bw 객체는반드시닫아야입력한내용이파일에저장됩니다. fos와 osw 객체를 close() 하더라도 bw 객체를 close() 하지않으면파일에입력한내용이저장되지않습니다. 이예제코드에서파일에저장되는데이터의입출력스트림단위를 char 단위로하려면아 래의코드를 bw = new BufferedWriter(osw); 다음과같이변경하면됩니다. bw = new BufferedWriter(new FileWriter(outFile)); 다음그림은 InputStreamReader 의생성자를나타낸것입니다. 생성자와설명 InputStreamReader(InputStream in) 디폴트문자셋을사용하여 InputStreamReader 객체를생성합니다. InputStreamReader(InputStream in, Charset cs) 주어진문자셋을사용하여 InputStreamReader 객체를생성합니다. InputStreamReader(InputStream in, CharsetDecoder dec) 주어진문자셋디코더를사용하여 InputStreamReader 객체를생성합니다. InputStreamReader(InputStream in, String charsetname) 주어진문자셋이름을사용하여 InputStreamReader 객체를생성합니다. 이외에도많은입 / 출력 API 들이있으나, 사용방법은위에서설명한내용과크게다르지 않습니다.
Chapter 입 / 출력프로그래밍 13 13.3. 입출력과관련된클래스들 13.3.1. 파일 (File) 객체 이제구체적으로파일을다루는법에대해서알아보겠습니다. 앞의예에서는파일을지정할때, 파일이름을문자열형태로주었습니다. 물론그런방법으로파일을지정할수도있지만, 자바에서제공하는 File클래스를이용할수도있습니다. 파일클래스는단순하게파일을지정하는목적으로만사용되는것은아니고매우다양한 API가있습니다. 이를이용하면파일과관련된대부분작업을수행할수있습니다. 다음코드는 File 객체를생성하는방법을기술한것입니다. 파일객체는파일만가리키는것 은아니고디렉터리도지칭할수있음을기억하기바랍니다. File somefile, somedir, otherfile; somefile = new File("c:\autoexec.bat"); somedir = new File("c:\"); otherfile = new File(someDir, "config.sys"); 다음은파일클래스의자주사용되는메서드입니다. 파일이름과관련된메서드 String getname() : 파일이름을반환합니다. String getpath() : 파일경로를반환합니다. String getabsolutepath() : 파일의절대경로를반환합니다. String getparent() : 파일이속한경로를반환합니다. boolean renameto(file newname) : 파일명을변경합니다. 변경하고자하는파일이이미존재할경우나, 접근권한등의이유로파일명이변경되지않으면 false를반환합니다. boolean delete() : 파일을삭제합니다. 삭제되지않으면 false를반환합니다. 파일정보를알아내는메서드 long lastmodified() : 마지막으로수정된날짜를 long 형으로반환합니다. long length() : 파일길이를반환합니다. 파일을테스트하는메서드 boolean exist() : 파일의존재여부를알아냅니다. 파일이있으면 true, 없으면 false를반환합니다. boolean canwrite() : 쓰기권한을가졌는지알아봅니다. 쓰기가능하면 true를반환합니다. boolean canread() : 읽을권한이있는지를알아봅니다. 읽기가능하면 true를반환합니다. boolean isfile() : 파일인지알아봅니다. 파일이면 true를반환하고, 디렉터리폴더이면 false를반환합니다. boolean isdirectory() : 디렉터리인지알아봅니다. 디렉터리이면 true를반환합니다.
Java 자바야놀자 boolean isabsolute() : 절대경로를가졌는지알아봅니다. 디렉터리관련메서드 boolean mkdir() : 새로운디렉터리를만듭니다. 디렉터리생성에실패하면 false 를반환합니다. String[] list() : 디렉터리내의파일또는디렉터리를반환합니다. 다음프로그램은 C 드라이브의루트디렉터리내에있는파일및디렉터리목록을보여주 는예제입니다. FileExplorerExample.java 1: import java.io.file; 2: import java.text.dateformat; 3: import java.text.numberformat; 4: import java.util.date; 5: 6: public class FileExplorerExample { 7: 8: public static void main(string[] args) { 9: 10: File mydir = new File("C:/"); 11: 12: File[] listing = mydir.listfiles(); 13: 14: for(int i=0;i<listing.length;++i) { 15: File file = listing[i]; 16: 17: System.out.print(file.getName() + "\t"); 18: 19: if(file.isfile()) { 20: NumberFormat f = NumberFormat.getInstance(); 21: DateFormat df = DateFormat.getDateInstance(); 22: 23: System.out.print(f.format(file.length()/1024)+"Kbyte\t"); 24: System.out.print(df.format(new Date(file.lastModified()))); 25: }else { 26: System.out.print(" 폴더 "); 27: } 28: System.out.println(); 29: } 30: } 31: } 이예제는 C 드라이브루트디렉터리의파일목록에서파일일경우에는파일의크기와마지 막수정된날짜를출력하고디렉터리일경우에는 폴더 라고출력합니다.
Chapter 입 / 출력프로그래밍 13 13.3.2. URL 객체 파일클래스가로컬컴퓨터에있는파일을참조한다면인터넷상에있는주소 (URL) 를참조할 수있는클래스도있는데바로 URL 클래스입니다. URL 클래스는 java.net 패키지에있습 니다. 다음은 URL 클래스에서자주사용되는생성자와메서드입니다. 생성자 생성자와설명 URL(String spec) String 표현으로부터 URL 객체를생성합니다. URL(String protocol, String host, int port, String file) 프로토콜, 호스트이름, 포트번호그리고파일이름으로 URL 객체를생성합니다. URL(String protocol, String host, int port, String file, URLStreamHandler handler) 프로토콜, 호스트이름, 포트번호, 파일이름그리고 URL 스트림핸들러로 URL 객체를생성합니다. URL(String protocol, String host, String file) 프로토콜, 호스트이름그리고파일이름으로 URL 객체를생성합니다.
Java 자바야놀자 URL(URL context, String spec) 주어진컨텍스트와 spec 으로 URL 객체를생성합니다. URL(URL context, String spec, URLStreamHandler handler) 주어진컨텍스트와 spec, 그리고 URL 스트림핸들러로 URL 객체를생성합니다. 메서드 리턴타입 Object int String String String int String URLConnection InputStream 메서드와설명 getcontent() URL 이가진컨텐츠를반환합니다. getdefaultport() URL 의포트번호를반환합니다. 지정하지않았다면 -1 을반환합니다. 이메서드는 jdk1.4 에추가되었습니다. getport() 메서드와다른점은 ' 기본포트를사용할경우기본포트번호를출력한다 ' 는것입니다. 예를들어 http 프로토콜을이용한 URL 에접속했을경우기본포트를사용하기때문에 URL 객체생성시포트번호를지정하지않았다면 getport() 메서드는 -1 을반환하지만 getdefaultport() 메서드는 80 번을반환합니다. getfile() URL 의파일 ( 폴더 ) 명을반환합니다. gethost() URL 의호스트이름을반환합니다. getpath() URL 의패스를반환합니다. getport() URL 의포트번호를반환합니다. 지정하지않았다면 -1 을반환합니다. getprotocol() 프로토콜을반환합니다. openconnection() URLConnection 객체를반환합니다. openstream() 입력스트림객체를반환합니다. 다음프로그램은 URL 클래스를이용하여인터넷상의원하는페이지를읽어오는예입니다. GetHTMLExample.java 1: import java.io.filenotfoundexception; 2: import java.io.fileoutputstream; 3: import java.io.ioexception; 4: import java.io.inputstream; 5: import java.net.malformedurlexception; 6: import java.net.url; 7: 8: public class GetHTMLExample {
Chapter 입 / 출력프로그래밍 13 9: public static void main(string [] args) { 10: String urlstr = "http://www.javaspecialist.co.kr/";// 접속할사이주주소 11: 12: String file = "html.txt"; // 접속한내용을저장할파일명 13: byte [] inputstring = new byte[1024]; 14: 15: URL url = null; 16: try { 17: url = new URL(urlStr); 18: } catch (MalformedURLException e) { 19: System.out.println("URL 주소가형식에맞지않습니다."); 20: return; 21: } 22: 23: InputStream is = null; 24: try { 25: is = url.openstream(); 26: } catch (IOException e) { 27: System.out.println(" 주소를열지못했습니다."); 28: return; 29: } 30: 31: FileOutputStream fos = null; 32: try { 33: fos = new FileOutputStream(file); 34: while(is.read(inputstring, 0, inputstring.length)!= -1) { 35: fos.write(inputstring); 36: } 37: 38: System.out.println("Path: "+url.getpath()); 39: System.out.println("Protocol: "+url.getprotocol()); 40: System.out.println("Port:"+url.getPort()); 41: System.out.println("DefaultPort:"+url.getDefaultPort()); 42: System.out.println("File:"+url.getFile()); 43: 44: System.out.println(file+" 파일을열어보세요."); 45: } catch (FileNotFoundException e) { 46: System.out.println(" 파일이존재하지않습니다."); 47: } catch (IOException e) { 48: System.out.println(e.getMessage()); 49: } finally { 50: if(fos!= null) 51: try { fos.close(); } catch (IOException e) { } 52: } 53: } 54: }
Java 자바야놀자 URL url = null; try { url = new URL(urlStr); } catch (MalformedURLException e) { System.out.println("URL 주소가형식에맞지않습니다."); return; } 위코드는 URL 을이용하여 URL 클래스의인스턴스를생성합니다. InputStream is = null; try { is = url.openstream(); } catch (IOException e) { System.out.println(" 주소를열지못했습니다."); return; } openstream() 메서드를호출하면 InputStream 객체가반환됩니다. 이후 InputStream 객 체를사용한다면인터넷상의 URL 을마치로컬컴퓨터의파일처럼다룰수있습니다. FileOutputStream fos = null; try { fos = new FileOutputStream(file); while(is.read(inputstring, 0, inputstring.length)!= -1) { fos.write(inputstring); } 읽은데이터를파일에쓰기위해 FileOutputStream 객체를생성합니다. 이러한작업을응 용한다면원하는사이트의문서를브라우저없이조회할수있을것입니다.
Chapter 입 / 출력프로그래밍 13 System.out.println("Path: "+url.getpath()); System.out.println("Protocol: "+url.getprotocol()); System.out.println("Port:"+url.getPort()); System.out.println("DefaultPort:"+url.getDefaultPort()); System.out.println("File:"+url.getFile()); 위코드는 URL 클래스의주요메서드들을테스트한예입니다. 13.3.3. RandomAccessFile 지금까지살펴본입출력클래스는순차적으로데이터를읽습니다. 즉, 데이터를읽다가다시앞으로돌아가서같은데이터를읽는등의작업을할수없습니다. 그런데이러한방법을제공하는입출력클래스가바로 RandomAccessFile클래스입니다. 사용법은다음과같습니다. RandomAccessFile raf = new RandomAccessFile("c:\config.sys", "rw"); 생성자의첫번째인자는오픈하고자하는파일명입니다. 이때파일이름은문자열형태로사용할수도있지만, 앞에서설명한파일객체형태로사용할수도있습니다. 두번째인자는오픈한파일을어떻게접근할것인가하는접근모드를나타냅니다. "r" 과 "rw" 를사용할수있으며 "r" 은읽기전용, "rw" 는읽기와쓰기가가능한모드로오픈합니다. RandomAccessFile 클래스가제공하는유용한메서드는다음과같습니다. long getfilepointer() // 현재의 file pointer의위치를알아냄. void seek(long position) // 원하는위치로 file pointer를움직임. long length() // file의 size를알아냄. 다음프로그램은순차파일이아닌임의의파일관리를위한예를보인것입니다. LogWriteExample.java 1: import java.io.filenotfoundexception; 2: import java.io.ioexception; 3: import java.io.randomaccessfile; 4: import java.util.date; 5: 6: public class LogWriteExample { 7: public static void main(string [] args) { 8: String filename = "runtime.log"; 9: String mode = "rw"; 10: 11: RandomAccessFile raf = null; 12: try { 13: raf = new RandomAccessFile(fileName, mode); 14:
Java 자바야놀자 15: raf.seek(raf.length()); 16: 17: raf.writeutf(new Date().toString()+"\n"); 18: System.out.println(fileName + " 에현재시간이기록되었습니다."); 19: } catch (FileNotFoundException e) { 20: System.out.println(" 파일이존재하지않습니다."); 21: } catch (IOException e) { 22: System.out.println(e.getMessage()); 23: } finally { 24: if(raf!=null) 25: try { raf.close(); } catch (IOException e) { } 26: } 27: } 28: } 이프로그램은실행할때마다실행한시간을로그기록으로남깁니다. raf = new RandomAccessFile(fileName, mode); RandomAccessFile 객체를생성할때의접근모드는 "rw" 는파일을읽기 / 쓰기전용으로 오픈합니다. raf.seek(raf.length()); seek(raf.length()) 는파일포인터를파일의맨뒤로보냅니다. length() 메서드는파일의길이를리턴하며, seek() 메서드는원하는위치로파일포인터를보내주는메서드입니다. 파일이름에서알수있듯이, 이파일은로그 (log) 파일을기록하는예입니다. 즉, 파일의뒷부분에데이터가계속기록되는형태입니다. raf.writeutf(new Date().toString()+"\n"); 이코드는현재시간을알아내서그시간을파일에저장합니다. writeutf() 메서드는 16 비트유니코드문자를 8 비트문자로변경하여저장하는메서드입니다. 메모장에서열면그내용을알수없습니다. 그러나이클립스또는 글등의문서편집기를이용하여한글완성형으로열면그내용을확인할수있습니다.
Chapter 입 / 출력프로그래밍 13 13.4. 객체직렬화 13.4.1. Serializable 인터페이스 객체직렬화 (Object Serialization) 는파일입출력에있어서중요하면서많이사용됩니다. 객체직렬화는생성된객체가스트림을통해이동하는것을의미합니다. 자바에서는메모리에서생성된객체를파일에저장해서객체에영속성을부여하거나, 소켓을통해객체를다른 JVM 환경으로이동시키는것을객체직렬화라고합니다. 객체직렬화에사용되는클래스는 Serializable 이라는인터페이스를반드시 implements 해야합니다. 그런데이인터페이스에는구현할메서드가없습니다. Serializable 인터페이스를 implements하는것은, 이클래스가 Serialization이가능함을나타내는표시일뿐입니다. 이러한인터페이스들을 Marker 인터페이스라고부릅니다. 다음프로그램은 Customer 클래스의객체를저장하기위해 Serializable 인터페이스를구 현한예입니다. Customer.java 1: import java.io.serializable; 2: 3: public class Customer implements Serializable { 4: private String name; 5: private char gender; 6: private String email; 7: private int birthyear; 8: 9: public Customer(String name, char gender, String email, int birthyear) { 10: this.name = name; 11: this.gender = gender; 12: this.email = email; 13: this.birthyear = birthyear; 14: } 15: 16: @Override 17: public String tostring() { 18: return "Customer [name=" + name + ", gender=" + gender + ", email=" + email + ", birthyear=" + birthyear + "]"; 19: } 20: } 중요한점은실제객체가 Serialization될때, 데이터부분만 Serialization된다는것입니다. 즉, 앞의 Person클래스객체를파일로저장할때, 실제로저장되는것은 name, gender, email, birthyear 멤버변수데이터만저장되고, 생성자나메서드코드는저장되지않습니다.
Java 자바야놀자 Customer 클래스의객체를파일에저장예제를통해직렬화에대해서알아보겠습니다. WriteCustomerExample.java 1: import java.io.fileoutputstream; 2: import java.io.ioexception; 3: import java.io.objectoutputstream; 4: 5: public class WriteCustomerExample { 6: 7: public static void main(string [] args) { 8: Customer cust1 = new Customer(" 허현정 ", 'M', "heojk2@daum.net", 21); 9: Customer cust2 = new Customer(" 허현준 ", 'M', "loid@gmail.com", 20); 10: 11: FileOutputStream fos = null; 12: ObjectOutputStream oos = null; 13: try { 14: fos = new FileOutputStream("customer.ser"); 15: oos = new ObjectOutputStream(fos); 16: 17: oos.writeobject(cust1); 18: oos.writeobject(cust2); 19: System.out.println("Customer 데이터가저장되었습니다."); 20: } catch (IOException e) { 21: System.out.println(e.getMessage()); 22: } finally { 23: if(oos!=null) 24: try { oos.close(); } catch (IOException e) { } 25: } 26: 27: } 28: } 파일에출력하기위해 FileOutputStream객체를생성합니다. 그리고객체를저장하기위해필터스트림인 ObjectOutputStream객체를생성합니다. 객체를저장할수있는 writeobject() 메서드는필터스트림인 ObjectOutputStream에있습니다. 따라서메서드를사용하려면 ObjectOutputStream 필터스트림클래스를적용할수밖에없습니다. ( 입출력클래스의적용은대부분이런방법으로이루어집니다.) ObjectOutputStream에 Customer 클래스의인스턴스를저장합니다. 저장된파일은직렬화된파일이기때문에텍스트에디터로는내용을알아볼수없습니다.
Chapter 입 / 출력프로그래밍 13 다음프로그램은앞의 WriteMyObject 프로그램을실행했을때생성되는 customer.ser 파 일을읽어저장되어있는 Person 객체의데이터를출력하는예입니다. ReadCustomerExample.java 1: import java.io.fileinputstream; 2: import java.io.filenotfoundexception; 3: import java.io.ioexception; 4: import java.io.objectinputstream; 5: 6: public class ReadCustomerExample { 7: 8: public static void main(string [] args) { 9: FileInputStream fis = null; 10: ObjectInputStream ois = null; 11: try { 12: fis = new FileInputStream("customer.ser"); 13: ois = new ObjectInputStream(fis); 14: 15: Customer cust1 = (Customer)ois.readObject(); 16: Customer cust2 = (Customer)ois.readObject(); 17: System.out.println(cust1.toString()); 18: System.out.println(cust2.toString()); 19: 20: } catch (FileNotFoundException e) { 21: System.out.println(" 파일이존재하지않습니다."); 22: } catch (IOException e) { 23: System.out.println(e.getMessage()); 24: } catch (ClassNotFoundException e) { 25: System.out.println(e.getMessage()); 26: } finally { 27: if(ois!=null) 28: try { ois.close(); } catch (IOException e) { } 29: } 30: } 31: } 파일로부터읽기위해 FileInputStream객체를생성합니다. 그리고객체를읽기위해필터스트림인 ObjectInputStream객체를생성합니다. 객체를읽을수있는메서드인 readobject() 메서드는필터스트림인 ObjectInputStream에존재합니다. readobject() 메서드는 Customer 객체에 customer.ser파일의객체를불러들입니다. readobject() 메서드의결과를 Customer 클래스로형변환하고있는데, 이는 readobject() 메서드의반환형이 Object형이기때문에실제저장되어있는클래스인 Customer 클래스로형변환이필요한것입니다.
Java 자바야놀자 13.4.2. transient 이키워드는 Serializable 과함께알아두면유용합니다. transient 키워드는직렬화되지 않는객체멤버변수를포함한클래스를직렬화시킬때나특정변수를직렬화에서제외시 키고자할때사용하는제한자입니다. 1: public class MyClass implements Serializable { 2: public transient Thread mythread; 3: private String customerid; 4: private int total; 5: } 이예에서스레드객체는직렬화가불가능한객체이므로 transient 키워드로선언한것입니 다. 만일 transient 키워드가생략되면 MyClass 클래스는직렬화안됩니다. 1: public class MyClass implements Serializable { 2: public transient Thread mythread; 3: private transient String customerid; 4: private int total; 5: } 이예에서는 MyClass 의객체를직렬화시킬때 customerid 는직렬화에서제외한다는뜻입니다. String 클래스는직렬화가능하므로 transient 키워드를생략해도 MyClass 는직렬화됩니다. 다음코드는직렬화제외되는변수를 transient 로지정한예입니다. Account 클래스의 password 필드는직렬화에서제외시키기위해 transient 로지정했습니다. 비밀번호필드 등은보안상의이유로도직렬화에서제외되어야할것입니다. Account.java 1: import java.io.serializable; 2: 3: public class Account implements Serializable { 4: 5: String accountno; 6: String username; 7: int balance; 8: transient String password; 9: 10: public Account(String accountno, String username, int balance, String password) { 11: super(); 12: this.accountno = accountno; 13: this.username = username;
Chapter 입 / 출력프로그래밍 13 14: this.balance = balance; 15: this.password = password; 16: } 17: public String tostring() { 18: return accountno + "[" + username + ", " + password + "] : " + balance; 19: } 20: } SaveAccountExample.java 1: import java.io.fileoutputstream; 2: import java.io.objectoutputstream; 3: 4: public class SaveAccountExample { 5: 6: public static void main(string[] args) throws Exception { 7: FileOutputStream fos = new FileOutputStream("account.ser"); 8: ObjectOutputStream oos = new ObjectOutputStream(fos); 9: Account a1 = new Account("111-12-45678", " 홍길동 ", 10000, "1224"); 10: System.out.println(a1); 11: oos.writeobject(a1); 12: System.out.println(" 데이터가저장되었습니다."); 13: oos.close(); 14: } 15: } SaveAccountExample 클래스는 Account 클래스를직렬화시키는예입니다. 예제를실행시키면 account.ser 파일이생성됩니다. 생성된파일을메모장에서열었을때 아래의그림처럼전체저장된내용이무엇인지정확히알수없습니다. ReadAccountExample 클래스는 account.ser 파일에저장된 Account 객체를불러와서 출력하는예입니다. ReadAccountExample.java 1: import java.io.fileinputstream; 2: import java.io.objectinputstream; 3: 4: public class ReadAccountExample { 5: 6: public static void main(string[] args) throws Exception { 7: FileInputStream fis = new FileInputStream("account.ser");
Java 자바야놀자 8: ObjectInputStream ois = new ObjectInputStream(fis); 9: Account a2 = (Account)ois.readObject(); 10: System.out.println(a2); 11: ois.close(); 12: } 13: } 실행결과에서보는바와같이 password 필드에해당하는부분은 null 로출력된것을알수 있습니다. Account 클래스의 password 변수는 transient 로선언되었으므로직렬화시 해당변수의정보가저장되지않습니다. 13.4.3. serialversionuid 만일 Account 클래스가변경되면어떻게될까요? Account 클래스에새로운필드또는메서드가추가되거나아니면기존의필드또는메서드가삭제되어클래스가변경될수도있을것입니다. 직렬화가능한클래스의구조가변경된다면클래스구조가변경되기전에직렬화시킨데이터를불러오지못할수도있습니다. 다음의실행결과는 Account 객체를직렬화시켜데이터를저장한다음 Account 클래스에새로운필드를추가 (String newfield;) 하고 ReadAccountExample 클래스를실행시킬때발생하는예외를보여주고있습니다. serialversionuid 필드가정의되지않은상태에서데이터가저장되어있다면새로운멤버 변수를추가했을때직렬화된데이터를불러올경우위와같은예외발생할것입니다. 나중에클래스가변경되더라도이전에직렬화했었던데이터를정상적으로불러오게하기위해서는아래와같이멤버변수를추가해야합니다. JVM은클래스의구조가다르더라도 serialversionuid의값이같다면클래스의구조가다르더라도같은클래스로간주할것입니다. 새로운멤버변수를추가하고실행했을때위와같은예외가발생한다면예외메시지에서발견할수있는 stream classdesc serialversionuid의값을이용해클래스의 serialversionuid 값을설정하면됩니다. private static final long serialversionuid = 5004258855763033943L
Chapter 입 / 출력프로그래밍 13 클래스를처음만들때라면 serialversionuid의값은 long 형값의범위에포함된다면어떤값도상관없습니다. 다만다른클래스의 serialversionuid 값과중복되지않으면됩니다. 그렇더라도가능하다면이클립스에서생성시켜주는값을이용하는것을권장합니다. 물론이미데이터가직렬화되어있는상태라면실행시발생하는예외에서 UID값을찾을수있습니다. InvalidClassException 예외메시지의오른쪽을보면 UID 값이두개가있는것을확인할수있습니다. 두 UID 값중왼쪽 UID 값을이용해 serialversionuid 값을지정한다면이미직렬화된데이터도클래스의구조가바뀌더로읽을수있습니다. 직렬화가능한클래스를정의할경우 serialversionuid 필드를선언하는것을잊지마세 요. 다음은 Account 클래스에 serialversionuid 필드를선언한것입니다. 앞의코드에 7 라인 만추가했습니다. 값은클래스들끼리중복되지않고, long 형범위안에포함되는정수값이 면모두가능합니다. Account.java 1: import java.io.serializable; 2: 3: public class Account implements Serializable { 4: 5: private static final long serialversionuid = 5004258855763033943L; 6: 7: String accountno; 8: String username; 9: int balance; 10: transient String password; 11: String newfield; 12: 13: public Account(String accountno, String username, int balance, String password) { 14: super(); 15: this.accountno = accountno; 16: this.username = username; 17: this.balance = balance; 18: this.password = password; 19: } 20: public String tostring() { 21: return accountno + "[" + username + ", " + password + "] : " + balance; 22: } 23: }
Java 자바야놀자 13.5. 고객관리프로그램 III( 데이터저장하기 ) 고객의정보를관리하는프로그램을고객의정보를저장하도록수정하겠습니다. 객체직렬 화를이용하여 ArrayList 객체를파일에저장한다음프로그램이시작되면파일에저장되 어있는정보를로드하여다시조회할수있도록합니다. 13.5.1. Customer 클래스 Customer 클래스는직렬화가능한객체가되도록 Serializable 인터페이스를 implements 해야합니다. Customer.java 1: import java.io.serializable; 2: 3: public class Customer implements Serializable { 4: 5: private static final long serialversionuid = -4205785232581803172L; 6: 7: private String name; 8: private char gender; 9: private String email; 10: private int birthyear; 11: 12: public Customer(String name, char gender, String email, int birthyear) { 13: super(); 14: this.name = name; 15: this.gender = gender; 16: this.email = email; 17: this.birthyear = birthyear; 18: } 19: 20: public String getname() { 21: return name; 22: } 23: public void setname(string name) { 24: this.name = name; 25: } 26: public char getgender() { 27: return gender; 28: } 29: public void setgender(char gender) { 30: this.gender = gender; 31: } 32: public String getemail() {
Chapter 입 / 출력프로그래밍 13 33: return email; 34: } 35: public void setemail(string email) { 36: this.email = email; 37: } 38: public int getbirthyear() { 39: return birthyear; 40: } 41: public void setbirthyear(int birthyear) { 42: this.birthyear = birthyear; 43: } 44: 45: @Override 46: public String tostring() { 47: return "Customer [name=" + name + ", gender=" + gender + ", email=" + email + ", birthyear=" + birthyear + "]"; 48: } 49: } 13.5.2. CustomerManager 클래스 다음코드는 CustomerManager 클래스입니다. 진하게작성된부분이 7 장예제코드에추 가된부분입니다. CustomerManager.java 1: import java.io.fileinputstream; 2: import java.io.filenotfoundexception; 3: import java.io.fileoutputstream; 4: import java.io.ioexception; 5: import java.io.objectinputstream; 6: import java.io.objectoutputstream; 7: import java.util.arraylist; 8: import java.util.scanner; 9: 10: public class CustomerManager { 11: 12: // 고객정보를저장할자료구조선언 13: static ArrayList<Customer> custlist = new ArrayList<>(); 14: 15: // 리스트정보를조회하기위해인덱스를필요로함 16: static int index = -1; 17: 18: static int count = 0;//custList.size() 19: 20: // 기본입력장치로부터데이터를입력받기위해 Scanner 객체생성 21: static Scanner scan = new Scanner(System.in); 22:
Java 자바야놀자 23: public static void main(string[] args) { 24: readcustomerdata(); 25: while(true) { 26: count = custlist.size(); 27: System.out.printf("\n[INFO] 고객수 : %d, 인덱스 : %d\n", count, index); 28: System.out.println(" 메뉴를입력하세요."); 29: System.out.println("(I)nsert, (P)revious, (N)ext, " + 30: "(C)urrent, (U)pdate, (D)elete, (S)ave, (Q)uit"); 31: System.out.print(" 메뉴입력 : "); 32: String menu = scan.next(); 33: menu = menu.tolowercase(); // 입력한문자열을모두소문자로변환 34: switch(menu.charat(0)) { 35: case 'i': 36: System.out.println(" 고객정보입력을시작합니다."); 37: insertcustomerdata(); 38: System.out.println(" 고객정보를입력했습니다."); 39: break; 40: case 'p' : 41: System.out.println(" 이전데이터를출력합니다."); 42: if(index <= 0) { 43: System.out.println(" 이전데이터가존재하지않습니다."); 44: }else { 45: index--; 46: printcustomerinfo(index); 47: } 48: break; 49: case 'n' : 50: System.out.println(" 다음데이터를출력합니다."); 51: if(index >= count-1) { 52: System.out.println(" 다음데이터가존재하지않습니다."); 53: }else { 54: index++; 55: printcustomerinfo(index); 56: } 57: break; 58: case 'c' : 59: System.out.println(" 현재데이터를출력합니다."); 60: if( (index >= 0) && (index < count)) { 61: printcustomerinfo(index); 62: }else { 63: System.out.println(" 출력할데이터가선택되지않았습니다."); 64: } 65: break; 66: case 'u' : 67: System.out.println(" 데이터를수정합니다."); 68: if( (index >= 0) && (index < count)) { 69: System.out.println(index + " 번째데이터를수정합니다."); 70: updatecustomerdata(index); 71: }else { 72: System.out.println(" 수정할데이터가선택되지않았습니다.");
Chapter 입 / 출력프로그래밍 13 73: } 74: break; 75: case 'd' : 76: System.out.println(" 데이터를삭제합니다."); 77: if( (index >= 0) && (index < count)) { 78: System.out.println(index + " 번째데이터를삭제합니다."); 79: deletecustomerdata(index); 80: }else { 81: System.out.println(" 삭제할데이터가선택되지않았습니다."); 82: } 83: break; 84: case 's' : 85: savecustomerdata(); 86: break; 87: case 'q' : 88: System.out.println(" 프로그램을종료합니다."); 89: scan.close(); //Scanner 객체를닫아준다. 90: System.exit(0); // 프로그램을종료시킨다. 91: break; 92: default : 93: System.out.println(" 메뉴를잘못입력했습니다."); 94: }//end switch 95: }//end while 96: }//end main 97: 98: public static void insertcustomerdata() { 99: System.out.print(" 이름 : "); 100: String name = scan.next(); 101: System.out.print(" 성별 (M/F) : "); 102: char gender = scan.next().charat(0); 103: System.out.print(" 이메일 : "); 104: String email = scan.next(); 105: System.out.print(" 출생년도 : "); 106: int birthyear = scan.nextint(); 107: 108: // 입력받은데이터로고객객체를생성 109: Customer cust = new Customer(name, gender, email, birthyear); 110: 111: // 고객객체를 ArrayList 에저장 112: custlist.add(cust); 113: } 114: 115: // 고객데이터출력 116: public static void printcustomerinfo(int index) { 117: Customer cust = custlist.get(index); 118: System.out.println("==========CUSTOMER INFO================"); 119: System.out.println(" 이름 : " + cust.getname()); 120: System.out.println(" 성별 : " + cust.getgender()); 121: System.out.println(" 이메일 : " + cust.getemail()); 122: System.out.println(" 출생년도 : " + cust.getbirthyear());
Java 자바야놀자 123: System.out.println("======================================="); 124: } 125: 126: //index 위치의고객정보를삭제합니다. 127: public static void deletecustomerdata(int index) { 128: custlist.remove(index); 129: } 130: 131: //index 위치의고객정보를수정합니다. 132: public static void updatecustomerdata(int index) { 133: Customer cust = custlist.get(index); 134: System.out.println("---------UPDATE CUSTOMER INFO----------"); 135: System.out.print(" 이름 (" + cust.getname() + ") :"); 136: cust.setname(scan.next()); 137: 138: System.out.print(" 성별 (" + cust.getgender() + ") :"); 139: cust.setgender(scan.next().charat(0)); 140: 141: System.out.print(" 이메일 (" + cust.getemail() + ") :"); 142: cust.setemail(scan.next()); 143: 144: System.out.print(" 출생년도 (" + cust.getbirthyear() + ") :"); 145: cust.setbirthyear(scan.nextint()); 146: } 147: 148: @SuppressWarnings("unchecked") 149: public static void readcustomerdata() { 150: String filename = "customer.data"; 151: 152: FileInputStream fis = null; 153: ObjectInputStream ois = null; 154: try { 155: fis = new FileInputStream(fileName); 156: ois = new ObjectInputStream(fis); 157: 158: custlist = (ArrayList<Customer>)ois.readObject(); 159: } catch (FileNotFoundException e) { 160: System.out.println(" 파일이존재하지않습니다."); 161: } catch (IOException e) { 162: System.out.println(e.getMessage()); 163: } catch (ClassNotFoundException e) { 164: System.out.println(e.getMessage()); 165: } finally { 166: if(ois!= null) 167: try{ois.close();} catch (IOException e) { } 168: } 169: } 170: 171: public static void savecustomerdata() { 172: String filename = "customer.data";
Chapter 입 / 출력프로그래밍 13 173: 174: FileOutputStream fos = null; 175: ObjectOutputStream oos = null; 176: 177: try { 178: fos = new FileOutputStream(fileName); 179: oos = new ObjectOutputStream(fos); 180: 181: oos.writeobject(custlist); 182: System.out.println(" 고객데이터가저장됐습니다."); 183: } catch (FileNotFoundException e) { 184: System.out.println(" 파일이존재하지않습니다."); 185: } catch (IOException e) { 186: System.out.println(e.getMessage()); 187: } finally { 188: if(oos!= null) 189: try { oos.close(); } catch(exception e){} 190: } 191: } 192: 193:}//end class
Java 자바야놀자 13.6. 마인드맵정리