본문 바로가기

Learning/JAVA

자바의 입출력, StringTokenizer, ObjectStream(ObjectOutputStream, writeObject, Serializable), 예외처리 throws, File

  • input.txt라는 텍스트 파일을 만들어서 같은 패키지 안에 저장한다. TokenFileTest라는 클래스를 만들고 input.txt 파일을 읽어서 콘솔창에 출력한다. (TokenFileTest)
  • 파일 읽는 클래스는 FileInputStream, 콘솔창 출력은 print메소드를 이용한다.

  • 읽어들임: read()는 int형만 읽어들이기 때문에 다양한 형식을 읽어들이기 위해 Scanner가 나왔다. (자바 5부터) 파일을 읽을때 Scanner를 써도 상관없다. 한 줄로 읽어들일때는 Scanner를 이용한다.

  • 내보낼때: write()는 FileOutputStream과 함께 쓰며 파일형태로 출력한다. print()는 콘솔창에 출력한다.

  • 객체 만들고 read, 객체 만들고 write, 예외처리 꼭 해주기.

  • 예외처리 할때 작은 범위의 예외처리를 먼저 써줘야함. (순서를 바꾸면 오류남)

+input.txt 내용

10:20

23:5

8:7

12:67

4:9

2:6

34:23

11:22

15:16

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package ioTest;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class TokenFileTest {
    public static void main(String[] args) {
        try {
            //파일 경로를 정확하게 써주기
            FileInputStream fis=new FileInputStream("src\\ioTest\\input.txt");
            while(true) {
                int i = fis.read();
                if(i==-1break;
                System.out.print((char)i);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

+만약에 파일로 내보내려면? (TokenFileTest)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package ioTest;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class TokenFileTest {
    public static void main(String[] args) {
        try {
            //파일을 읽어들이는 객체 fis를 선언. 경로를 정확하게 써주기
            FileInputStream fis=new FileInputStream("src\\ioTest\\input.txt");
            //파일로 내보내는 객체 fos를 선언. 다음 경로에 txt파일이 만들어진다.
            FileOutputStream fos=new FileOutputStream("src\\iotest\\out.txt");
            while(true) {
                int i = fis.read();
                if(i==-1break;
                //System.out.print((char)i);
                //읽어들인 파일을 내보낼때 write.
                fos.write(i);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

+파일의 내용을 한 줄씩 읽어들이고 한줄로 출력하고 싶다면? 또한 기존 파일 내용 중 10:20형태를 10 20으로 출력하려면? (TokenFileTest2)

    • 한 줄을 읽어들일 수 있는 Scanner 이용.  Scanner에서 파일 경로만 써주면 문자열로 인식하므로 new File을 붙여서 파일임을 표시.

    • while에는 이 객체가 있는 동안 돌린다는 뜻으로 hasNext()메소드 이용.

    • 한 줄씩 읽어들이는 nextLine()메소드 이용.

    • 문자열에서 쓰이는 split 함수를 이용하여 중간의 ' : '을 제거. 

    • split 함수는 String 배열로 지정해야함. 

    • 배열이므로 for문을 돌려서 출력하기 

+16진수로 출력한다면?

    • String 배열은 바로 16진수로 바꿀 수 없다.

    • parseInt로 먼저 변환한 뒤 정수형 변수에 선언하고

    • 그 정수형 변수를 16진수로 출력하기

+16진수로 변환한 결과물을 파일로 내보낸다면?

    • Scanner로 한 문장씩 입력받았기에 파일로 내보낼때는 PrintStream를 이용한다.

    • ps=new printStream이렇게 객체를 하나 만들어준다. 

    • write를에는 정수형이나 바이트의 배열만 할당할 수 있으므로 문자를 내보낼 수 있는 메소드 print()를 사용해야 한다.

    • 객체명을 앞에 붙여준다. (ps.print() 와 같은 형식)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package ioTest;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Scanner;
 
public class TokenFileTest2 {
    public static void main(String[] args) {
            /*10:20을 10 20으로 출력하기
             *한줄을 읽어들일 수 있는 Scanner를 이용하기
             *문자열 split 함수를 이용하여 ':'을 제거
             */
            //지역변수는 초기값이 없으면 안된다.
            Scanner sfis=null
            //문자를 내보낼때는 PrintStream을 많이 쓴다.
            PrintStream ps=null;
            try {
                //new File을 안쓰면 파일이 아니라 문자열로 인식한다.
                sfis = new Scanner(new File("src\\ioTest\\input.txt")); 
                ps = new PrintStream("src\\ioTest\\hex.txt");
                while(sfis.hasNext()) { //이 객체가 있는 동안 돌린다는 뜻. hasNext()
                    String str = sfis.nextLine();
                    String[]tmp=str.split(":");
                    for(int i=0;i<tmp.length;i++) {
                        System.out.print(tmp[i]+"\t"); 
                        /*16진수로 출력
                         *String 배열은 바로 16진수로 바꿀 수 없다.
                         *parseInt로 먼저 변환한 뒤 정수형 변수에 선언하고
                         *그 정수형 변수를 16진수로 출력하기 
                         */
                        int v=Integer.parseInt(tmp[i]);
                        System.out.print(Integer.toHexString(v).toUpperCase()+"\t");
                        //write에는 int나 byte의 배열만 할당할 수 있다. 문자를 내보낼 수 없다.
                        ps.print(Integer.toHexString(v).toUpperCase()+"\t");
                    }
                    //if(i==-1) break; hasNext()에서는 없으면 false로 넘어가니까 지워도 상관없음
                    //System.out.print(str+"\t");
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } finally {
                sfis.close();
                ps.close();
            }
        } 
}

 


  • StringTokenizer는 split메소드를 클래스화 시킨 것. 기본은 공백으로 쪼개기. (TokenTest)

Class StringTokenizer: 

StringTokenizer st = new StringTokenizer("this is a test");

    while (st.hasMoreTokens()) {

        System.out.println(st.nextToken());

}

=>출력문: 기본은 공백으로 쪼개는 것. 

    this

    is

    a

    test

    • 문자열을 미리 선언한 뒤 StringTokenizer의 객체를 불러서 쪼갤 기준을 지정할 수도 있고, StringTokenizer 생성자의 인수로 문자열을 쓸 수도 있다.  그때에는 공백이 기준이 된다.

    • 토큰 수는 countTokens(), 출력은 nextToken()메소드를 사용한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package utilTest;
import java.util.StringTokenizer;
public class TokenTest {
    public static void main(String[] args) {
        String str="aaa@bbb@ccc@ddd.eee";
        StringTokenizer stk=new StringTokenizer(str, "@."); //"@."=@로도, 점(.)으로도 쪼갠다.
        while(stk.hasMoreTokens()) { //hasMoreElements랑 같은 뜻
            System.out.println("토큰 수: "+stk.countTokens());
            System.out.println(stk.nextToken());
        }
        System.out.println("=======");
        
        StringTokenizer stk1=new StringTokenizer("1 0 14 15 3 3 19");
        while(stk1.hasMoreTokens()) {
            System.out.println("토큰 수: "+stk1.countTokens());
            System.out.println(stk1.nextToken());
        }
    }
}

 


  • TokenFileTest2에서 split대신에 StringTokenizer 클래스를 이용하기 (TokenFileTest3)

    • 8진수로 변환하고 octal.txt 파일로 출력하기 

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package ioTest;
 
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.util.Scanner;
import java.util.StringTokenizer;
 
public class TokenFileTest3 {
    //input.txt파일을 읽어서
    //8진수로 변환하여 octal.txt파일로 출력하시오
    //단, StringTokenizer를 사용하기
    public static void main(String[] args) {
        Scanner sc=null;
        PrintStream pst=null;
        try {
            sc=new Scanner(new File("src\\ioTest\\input.txt"));
            pst=new PrintStream("src\\ioTest\\octal.txt");
            while(sc.hasNext()) {
                String str = sc.nextLine();
                StringTokenizer st=new StringTokenizer(str,":");
                while(st.hasMoreTokens()) { //Token이 있는 동안 
                    String tok=st.nextToken(); //Token하나를 가져와서 문자열 tok에 선언
                    int v=Integer.parseInt(tok);
                    System.out.print(Integer.toOctalString(v)+"\t");
                    pst.print(Integer.toOctalString(v)+"\t");
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            sc.close();
            pst.close();
        }
    }
}

 


  • 친구를 등록하고 파일로 출력하여 입력된 친구의 정보를 볼 수 있도록 만들기 (Friend, FriendMain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package ioTest;
import java.io.Serializable;
public class Friend implements Serializable{
    private String name;
    private String birth;
    private String addr;
    private String tel;
    //getter, setter 생성
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getBirth() {
        return birth;
    }
    public void setBirth(String birth) {
        this.birth = birth;
    }
    public String getAddr() {
        return addr;
    }
    public void setAddr(String addr) {
        this.addr = addr;
    }
    public String getTel() {
        return tel;
    }
    public void setTel(String tel) {
        this.tel = tel;
    }
    
}

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package ioTest;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Scanner;
public class FriendMain {
    //f의 값들을 Arraylist를 만들어서 저장시켜준다.
    //while문을 돌면 값들이 초기화가 되기 때문에 전역변수로 만들어주기 위해 맨 위에다가 쓴다.
    ArrayList<Friend>arr=new ArrayList<Friend>();
    File dir,file;
    @SuppressWarnings("unchecked")
    public FriendMain() throws IOException, ClassNotFoundException {
        dir=new File("src\\ioTest");
        file=new File(dir, "myFriend.txt");
        if(file.exists()) {//파일이 있으면
            ObjectInputStream ois=new ObjectInputStream(new FileInputStream(file));
            //Object은 반드시 캐스팅을 해줘야함
            arr=(ArrayList<Friend>)ois.readObject(); //ois파일을 읽어서 arr에 저장
        }else {
            file.createNewFile(); //파일 생성
        }
    }
    public void fileUse() throws FileNotFoundException, IOException {
        Scanner sc=new Scanner(System.in);
        while(true) {
            System.out.println("1.친구등록 2.친구보기 3.종료(저장)");
            int num=sc.nextInt();
            sc.nextLine(); //엔터를 치면 버려주기
            if(num==1) { //친구등록
                System.out.println("이름>>");
                String name=sc.nextLine();
                System.out.println("생일>>");
                String birth=sc.nextLine();
                System.out.println("주소>>");
                String addr=sc.nextLine();
                System.out.println("전화>>");
                String tel=sc.nextLine();
                //setter가 생성자 역할도 한다.
                //입력한 정보를 담을 때 f라는 객체를 이용한다.
                Friend f=new Friend();
                f.setAddr(addr);
                f.setBirth(birth);
                f.setName(name);
                f.setTel(tel);
                arr.add(f);
            }else if(num==2) { //친구보기
                for(Friend f:arr) {
                    System.out.println("이름: "+f.getName());
                    System.out.println("생일: "+f.getBirth());
                    System.out.println("주소: "+f.getAddr());
                    System.out.println("전화: "+f.getTel());
                }
            }else if(num==3) { //저장시켜놓고 종료하기
                //무엇을 저장하는가?
                //friend가 담긴 arraylist를 내보내야함. 객체를 어떻게 내보낼까?
                ObjectOutputStream oos=
                        new ObjectOutputStream(new FileOutputStream(file));
                //try-catch대신에 throws를 사용하기. 그 메소드를 호출하는 쪽에도 반드시 throws를 써주기
                //객체를 내보내는 writeObject메소드
                oos.writeObject(arr);
                System.out.println("종료");
                System.exit(0);
            }else { //입력오류
                System.out.println("입력오류");
            }
        }
    }
    public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
        FriendMain fm=new FriendMain();
        //생성자가 제일 먼저 실행되므로 ArrayList의 값들을 생성자에 저장시켜줘야한다.
        fm.fileUse();
    }
}

 


  • 파일 복사하기 (FileCopyTest)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package ioTest;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileCopyTest {
    public static void main(String[] args) {
        long millisecond=0;
        try{
        FileInputStream fis=new FileInputStream("src\\utilTest\\CapitalApp.java");
        FileOutputStream fos=new FileOutputStream("copy.txt");
            //파일 복사를 시작하기 전 시간
            millisecond=System.currentTimeMillis();
            int i;
            while((i=fis.read())!=-1) {
                fos.write(i);
            }
            //파일을 복사하는데 걸리는 시간 계산
            millisecond=System.currentTimeMillis()-millisecond;
        }catch(IOException e) {
            e.printStackTrace();
        }
        System.out.println("파일 복사하는 데: "+millisecond+" milliseconds 소요되었습니다.");
    }
}

출처: Do it 자바 프로그래밍 입문 (544p-파일복사하기)


  • 직렬화 테스트하기 (SerializationTest)

    • serial.out이라는 파일을 하나 만들어준다.

    • FriendMain에서는 ArrayList를 이용하여 한꺼번에 출력하였는데 여기서는 writeObject의 인수로 객체 하나씩 출력한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package ioTest;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
class Person implements Serializable {
    private static final long serialVersionUID=-1503252402544036183L;
    String name;
    //transient는 직렬화 시키지 말라는 뜻. transient를 쓰면 대표이사가 null이라 나옴
    //transient String job;
    String job;
    
    public Person() {}
    
    public Person(String name, String job) {
        this.name=name;
        this.job=job;
    }
    
    public String toString() {
        return name+","+job;
    }
}
public class SerializationTest {
    public static void main(String[] args) throws ClassNotFoundException {
        Person personAhn=new Person("안재용""대표이사");
        Person personKim=new Person("김철수""상무이사");
        
        try{
            FileOutputStream fos=new FileOutputStream("serial.out");
            ObjectOutputStream oos=new ObjectOutputStream(fos);
            oos.writeObject(personAhn);
            oos.writeObject(personKim);
        }catch(IOException e) {
            e.printStackTrace();
        }
        try{
            FileInputStream fis=new FileInputStream("serial.out");
            ObjectInputStream ois=new ObjectInputStream(fis);
            Person p1=(Person)ois.readObject();
            Person p2=(Person)ois.readObject();
            
            System.out.println(p1);
            System.out.println(p2);
        }catch(IOException e) {
            e.printStackTrace();
        }
    }
}

출처: Do it 자바 프로그래밍 입문 (550p-직렬화 테스트하기)


  • File과 관련된 예제 (FileExam)

    • 폴더를 만들고 텍스트 파일도 하나 만들어서 저장한다.

    • listFiles()는 파일을 배열형태로 돌려준다. 배열이므로 for문을 써서 File f에 대입한다.

    • lastModified()는 마지막에 수정한 날짜를 long형태로 알려준다.

    • long형태가 아닌 알아보기 쉬운 형태로 바꾸기 위해 prinf()메소드를 이용한다. prinf는 출력하는 형태를 지정할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package ioTest;
 
import java.io.File;
 
public class FileExam {
 
    public static void main(String[] args) {
        File f1=new File("c:\\windows\\system.ini");
        //getPath()는 경로, getParent()는 부모 경로, getName()은 파일의 이름
        System.out.println(f1.getPath()+"="+f1.getParent()+"="+f1.getName());
        String res="";
        if(f1.isFile()) res="파일";
        else if(f1.isDirectory()) res="디렉토리";
        System.out.println(f1.getPath()+"은 "+res+" 입니다.");
        
        File f2=new File("folder");
        if(f2.isFile()) res="파일";
        else if(f2.isDirectory()) res="디렉토리";
        System.out.println(f2.getPath()+"은 "+res+" 입니다.");
        
        if(!f2.exists()) {
            System.out.println("파일없음");
        }
        System.out.println("----서브 리스트----");
        File[]subFiles=f2.listFiles(); //파일을 배열형태로 알려준다.
        for(int i=0;i<subFiles.length;i++) {
            File f=subFiles[i];
            long t=f.lastModified(); //마지막에 수정한 날짜를 long형태로 알려준다.
            //long형태가 아닌 알아보기 쉬운 날짜 형태로 바꾸기 위해 printf로 출력하는 형태를 지정
            System.out.println(f.getName());
            System.out.println("파일 크기: "+f.length());
            System.out.printf("수정한 시간: %ty년  %tb %td %ta %tT\n", t,t,t,t,t);
            //20년 6월 09 화 15:00:50 
        }
    }
}

 


  • 꼭 Object형태로 내보내지 않아도 된다. File형태로 내보내도 된다. (CapitalApp2)

    • utilTest패키지에 CapitalApp이 저장되어 있다는 가정하에 ioTest패키지에 CapitalApp2 클래스를 생성한다.

    • CapitalApp.showMenu()를 선언하면 오류가 발생한다. utilTest패키지에 있는 showMenu의 접근제어자를 default(생략)가 아닌 public으로 바꿔준다. CapitalApp클래스도 마찬가지로 public으로 바꿔준다.

    • 나라와 수도를 입력한 해쉬맵을 파일에 저장하고 종료하는 메소드인 save()를 생성한다.

    • FileWriter로 file형태로 내보낸다.  

    • 중복을 허용하지 않는 Set의 <String>형태로 나라만 가져오고, iterator로 나라를 방문한다. 나라와 수도를 key와 value변수를 선언하여 가져오고 write를 이용하여 나라와 수도를 출력한다

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package ioTest;
 
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;
 
 
import utilTest.CapitalApp;
 
public class CapitalApp2 {
    private HashMap<StringString>map=new HashMap<StringString>();
    File dir,file;
    public CapitalApp2(){
        dir=new File("src\\ioTest");
        file=new File(dir,"myCapital.txt");
        map.clear();
        try {
        if(!file.exists()) { //파일 없음
            file.createNewFile(); //파일생성
            return;
         }
            //파일로부터 읽어오기 위해 만드는 스캐너
         Scanner scanner=new Scanner(file);
         while(scanner.hasNext()) {
             String country=scanner.next(); //나라
             String capital=scanner.next(); //수도
             map.put(country, capital);
         }
         scanner.close();
        }catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    private void input() {
        System.out.println("현재"+map.size()+" 개 나라와 수도 입력");
        while(true) {
            System.out.println("나라와 수도 입력(종료는 x)>>");
            String cont=CapitalApp.sc.next(); //나라
            if(cont.toUpperCase().equals("X")) break;
            if(map.containsKey(cont)==true) {
                System.out.println("이미 입력한 나라입니다.");
                continue;
            }
            String cap=CapitalApp.sc.next();
            map.put(cont,cap);
        }
    }
    
    private void quiz() {
        //Set: 중복을 허용하지 않는 자료구조
        Set<String> set=map.keySet();
        Object[]arr=set.toArray(); //toArray()를 이용하여 set을 배열형태로 변환
        while(true) {
            int n=(int)(Math.random()*map.size());
            //if(map.size()==0) return;
            //if(map.isEmpty()) return;
            //아무런 값도 입력하지 않은 상태에서 퀴즈풀기를 시도하면 오류가 뜬다.
            //try-catch문에 예외처리를 적어준다.
            String city="";
            try {
                city=(String)arr[n];
            }catch(ArrayIndexOutOfBoundsException e){
                System.out.println("map 이 비어 있습니다.");
                return;
            }
            String dosi=map.get(city);
            
            System.out.println(city+" 의 수도는? 종료는 x>>");
            String dap=CapitalApp.sc.next();
            if(dap.toLowerCase().equals("x")) {
                System.out.println("종료합니다.");
                break;
            }
            if(dap.equals(dosi)) {
                System.out.println("정답입니다.");
            }
            else {
                System.out.println("틀렸습니다.");
            }
        }
    }
    //해쉬맵을 파일에 저장하고 종료하는 메소드
    private void save() {
        FileWriter fw=null;
        try {
            fw=new FileWriter(file);
            Set<String> set=map.keySet(); //나라만 가져옴
            Iterator<String> it=set.iterator(); //나라를 방문하기 위해
            while(it.hasNext()) {
                String key=it.next(); //나라 가져옴
                String value=map.get(key); //수도를 가져옴
                fw.write(key+" "); //나라 출력
                fw.write(value+"\n"); //수도 출력
            }
            fw.close();
            System.out.println("종료");
            System.exit(0);
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("파일저장 오류");
        }
    }
    
    public static void main(String[] args) {
        CapitalApp2 ca2=new CapitalApp2();
        while(true) {
            CapitalApp.showMenu();
            int choice=CapitalApp.sc.nextInt();
            switch(choice) {
            case 1 : ca2.input(); break;
            case 2 : ca2.quiz(); break;
            case 3 : ca2.save(); break;
            defaultSystem.out.println("입력오류");
            }
        }
    }
}