Transcript oop12

제 12주 파일과 스트림
(Files and Streams)
제 12주 목표
• 텍스트 파일을 읽고 텍스트 파일에 쓰는 법을 배움
• 텍스트 형식과 이진데이터 형식에 대해 이해하게 됨
• 순차 파일과 임의접근 파일에 대해 이해하게 됨
• 직렬화를 통해 객체를 저장하는 법을 배움
객체지향프로그래밍
강원대학교
1
텍스트 파일을 읽는 법
File inputFile = new File("input.txt");
Scanner in = new Scanner(inputFile);
객체지향프로그래밍
강원대학교
2
텍스트 파일을 읽는 법
FileReader reader = new FileReader("input.txt");
Scanner in = new Scanner(reader);
File inputFile = new File("input.txt");
Scanner in = new Scanner(inputFile);
String in.next
String in.nextLine
int in.nextInt
double in.nextDouble
객체지향프로그래밍
강원대학교
3
텍스트 파일에 쓰는 법
PrintWriter out = new PrintWriter("output.txt");
• 파일이 이미 존재하는 경우 기존 내용이 지워짐
• 파일이 존재하지 않는 경우 새 파일이 만들어짐
out.println(29.95);
out.println(new Rectangle(5, 10, 15, 25));
out.println("Hello, World!");
out.close();
객체지향프로그래밍
강원대학교
4
A Sample Program
내 마음은 호수요
그대 저어오오
나는 그대의 흰 그림자를 안고
옥같은 그대의 뱃전에 부서지리라
내 마음은 촛불이요
그대 저 문을 닫아주오
나는 그대의 비단 옷자락에 떨며
최후의 한방울도 남김없이 타오리다
/*
/*
/*
/*
/*
/*
···
1
2
3
4
5
6
*/
*/
*/
*/
*/
*/
객체지향프로그래밍
내 마음은 호수요
그대 저어오오
나는 그대의 흰 그림자를 안고
옥같은 그대의 뱃전에 부서지리라
내 마음은 촛불이요
강원대학교
5
File LineNumberer.java
01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
17:
import
import
import
import
java.io.FileReader;
java.io.IOException;
java.io.PrintWriter;
java.util.Scanner;
public class LineNumberer
{
public static void main(String[] args)
{
Scanner console = new Scanner(System.in);
System.out.print("Input file: ");
String inputFileName = console.next();
System.out.print("Output file: ");
String outputFileName = console.next();
try
{
객체지향프로그래밍
강원대학교
6
File LineNumberer.java
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
FileReader reader = new FileReader(inputFileName);
Scanner in = new Scanner(reader);
PrintWriter out = new PrintWriter(outputFileName);
int lineNumber = 1;
while (in.hasNextLine())
{
String line = in.nextLine();
out.println("/* " + lineNumber + " */ " + line);
lineNumber++;
}
out.close();
}
catch (IOException exception)
{
객체지향프로그래밍
강원대학교
7
File LineNumberer.java
34:
35:
36:
37: }
System.out.println("Error processing file:"
+ exception);
}
}
객체지향프로그래밍
강원대학교
8
import java.io.File;
import java.io.PrintWriter;
import java.util.Scanner;
public class LineNumberer
{
public static void main(String[] args)
{
Scanner console = new Scanner(System.in);
System.out.print("Input file: ");
String inputFileName = console.next();
System.out.print("Output file: ");
String outputFileName = console.next();
File inputFile = new File(inputFileName);
Scanner in = new Scanner(inputFile);
PrintWriter out = new PrintWriter(outputFileName);
객체지향프로그래밍
강원대학교
9
int lineNumber = 1;
while (in.hasNextLine())
{
String line = in.nextLine();
out.println("/* " + lineNumber + " */ " + line)
;
lineNumber++;
}
in.close();
out.close();
}
}
객체지향프로그래밍
강원대학교
10
File Dialog Boxes
객체지향프로그래밍
강원대학교
11
File Dialog Boxes
JFileChooser chooser = new JFileChooser();
FileReader in = null;
if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION)
{ File selectedFile = chooser.getSelectedFile();
reader = new FileReader(selectedFile);
. . .
}
API
객체지향프로그래밍
강원대학교
12
Reading Words
while (in.hasNext())
{
String input = in.next();
System.out.println(input);
}
White space(space, tab, new line)는
하며 읽는 과정에서 제거됨
단어구분자 역할을
Mary
snow.
1729
c++
in.useDelimiter("[^A-Za-z]+");
regular expression (정규식)
객체지향프로그래밍
강원대학교
13
Processing Lines
String line = in.nextLine();
new line을 포함해 한 줄 읽어 new line을 빼고 반환
china
1338612968
India
1156897766
south Korea 48508972
int i = 0;
while (!Character.isDigit(line.charAt(i))) { i++ }
String countryName = line.subString(0, i);
String population = line.subString(i);
countryName = countryName.trim();
int populationValue = Integer.parseInt(population.trim());
객체지향프로그래밍
강원대학교
14
Reading Numbers
double value = in.nextDouble();
NoSuchElementException, NumberFormatException 가능
Exception을 피하려면
if (in.hasNextDouble())
{
double value = in.nextDouble());
}
객체지향프로그래밍
강원대학교
15
Reading Numbers
nextDouble, nextInt 메소드는 white space를 읽어들이지 않는다.
20091234
홍길동
2009
대장금
while (in.hasNextInt())
{
int strudentID = in.nextInt();
in.nextLine();
// new line을 지나감
String name = in.nextLine();
...
}
객체지향프로그래밍
강원대학교
16
Reading Characters
Scanner in = new Scanner( ... );
in.useDelimiter("");
while (in.hasNext())
{
char ch = in.next().charAt(0);
...
}
객체지향프로그래밍
강원대학교
17
명령줄 인자
(Command line arguments)
• java LineNumberer input.txt numbered.txt
• args[0]는 “input.txt”,
• args[1]은 “numbered.txt”
if(args.length >= 1)
inputFileName = args[0];
객체지향프로그래밍
강원대학교
18
텍스트 형식과 이진데이터 형식
(Text and Binary Formats)
• 데이터를 저장하는 두 가지 방법
– 텍스트 형식 (Text format)
– 이진데이터 형식 (Binary format)
• 텍스트를 한 글자씩 입출력하기 위해서는
– java.io.Reader, java.io.Writer를 사용
• 이진데이터를 한 바이트씩 입출력하기 위해서는
– java.io.InputStream, java.io.OutputStream을
사용
객체지향프로그래밍
강원대학교
19
텍스트 형식
• 사람이 읽을 수 있는 형식
• 정수 12345는 '1' '2' '3' '4' '5' 의 문자들로 표현
됨
• 텍스트 형식 데이터의 입출력을 위해서는
Reader와 Writer 클래스를 사용
FileReader reader = new FileReader("input.txt");
FileWriter writer = new FileWriter("output.txt");
* FileReader, FileWriter는 각각 Reader와 Writer의 서브클래스임
객체지향프로그래밍
강원대학교
20
텍스트 형식과 이진데이터 형식
(Text and Binary Formats)
객체지향프로그래밍
강원대학교
21
이진데이터 입출력
InputStream
File
InputStream
Object
InputStream
OutputStream
File
OutputStream
객체지향프로그래밍
Object
OutputStream
강원대학교
PrintStream
22
텍스트데이터 입출력
Reader
Writer
Input
StreamReader
Output
StreamWriter
FileReader
FileWriter
객체지향프로그래밍
강원대학교
PrintWriter
23
이진데이터 형식
(Binary Format)
• 데이터가 이진수 바이트들로 표현됨
• 정수 12345는 네 바이트(0 0 48 57)로 나타내짐
(48X256+57=12345)  256=2^8
• 메모리 공간을 더 효율적으로 사용함
• 입출력을 위해 InputStream과 OutputStream 클래
스를 사용함
FileInputStream inputStream
= new FileInputStream("input.bin");
FileOutputStream outputStream
= new FileOutputStream("output.bin");
객체지향프로그래밍
강원대학교
24
이진데이터 파일에서 한 바이트 읽기
• read 메소드
– 다음 바이트를 int 타입으로 반환
– end_of_file의 경우 정수 -1 반환
InputStream in = . . .;
int next = in.read();
byte b;
if (next != -1)
b = (byte) next;
객체지향프로그래밍
강원대학교
25
암호화 프로그램
(An Encryption Program)
• Caesar cipher
– 1에서 25 사이 숫자 중에서 암호화 키를 선택
– 암호화 키만큼 각 글자를 이동
– 예: 만약 키가 3이라면 A는 D로, B는 E로, . . .
객체지향프로그래밍
강원대학교
26
An Encryption Program
 암호를 풀기 위해서는 음수의 암호화 키를 사용
객체지향프로그래밍
강원대학교
27
To Encrypt Binary Data
int next = in.read();
if (next == -1) done = true;
else
{
byte b = (byte) next;
byte c = encrypt(b); //call the method to encrypt the byte
out.write(c);
}
객체지향프로그래밍
강원대학교
28
File Encryptor.java
01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
17:
18:
import
import
import
import
import
import
java.io.File;
java.io.FileInputStream;
java.io.FileOutputStream;
java.io.InputStream;
java.io.OutputStream;
java.io.IOException;
/**
An encryptor encrypts files using the Caesar cipher.
For decryption, use an encryptor whose key is the
negative of the encryption key.
*/
public class Encryptor
{
/**
Constructs an encryptor.
@param aKey the encryption key
*/
객체지향프로그래밍
강원대학교
29
File Encryptor.java
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
public Encryptor(int aKey)
{
key = aKey;
}
/**
Encrypts the contents of a file.
@param inFile the input file
@param outFile the output file
*/
public void encryptFile(String inFile, String outFile)
throws IOException
{
InputStream in = null;
OutputStream out = null;
try
{
객체지향프로그래밍
강원대학교
30
File Encryptor.java
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
in = new FileInputStream(inFile);
out = new FileOutputStream(outFile);
encryptStream(in, out);
}
finally
{
if (in != null) in.close();
if (out != null) out.close();
}
}
/**
Encrypts the contents of a stream.
@param in the input stream
@param out the output stream
*/
객체지향프로그래밍
강원대학교
31
File Encryptor.java
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
public void encryptStream(InputStream in, OutputStream out)
throws IOException
{
boolean done = false;
while (!done)
{
int next = in.read();
if (next == -1) done = true;
else
{
byte b = (byte) next;
byte c = encrypt(b);
out.write(c);
}
}
}
객체지향프로그래밍
강원대학교
32
File Encryptor.java
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81: }
/**
Encrypts a byte.
@param b the byte to encrypt
@return the encrypted byte
*/
public byte encrypt(byte b)
{
return (byte) (b + key);
}
private int key;
객체지향프로그래밍
강원대학교
33
File EncryptorTester.java
01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
17:
import java.io.IOException;
import java.util.Scanner;
/**
A program to test the Caesar cipher encryptor.
*/
public class EncryptorTester
{
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
try
{
System.out.print("Input file: ");
String inFile = in.next();
System.out.print("Output file: ");
String outFile = in.next();
객체지향프로그래밍
강원대학교
34
File EncryptorTester.java
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28: }
29:
30:
System.out.print("Encryption key: ");
int key = in.nextInt();
Encryptor crypt = new Encryptor(key);
crypt.encryptFile(inFile, outFile);
}
catch (IOException exception)
{
System.out.println("Error processing file: "
+ exception);
}
}
객체지향프로그래밍
강원대학교
35
임의 접근과 순차 접근
(Random Access vs. Sequential Access)
file pointer
객체지향프로그래밍
강원대학교
36
임의접근파일
(RandomAccessFile)
• 파일을 열 때 모드를 지정함
– Reading only ("r")
– Reading and writing ("rw")
RandomAccessFile f = new RandomAcessFile("bank.dat","rw");
• file pointer를 옮기는 법
f.seek(n);
객체지향프로그래밍
강원대학교
37
RandomAccessFile
• file pointer의 현재 위치를 알아보는 법
long n = f.getFilePointer();
// of type "long" because files can be very large
• 파일의 크기를 알아보는 법 (바이트 단위로)
fileLength = f.length();
객체지향프로그래밍
강원대학교
38
A Sample Program
• bank account들을 임의접근파일에 저장
• 텍스트 형식으로 저장한다면?
• 1001번 계좌에 100원을 저축하면
객체지향프로그래밍
강원대학교
39
A Sample Program
• 이진테이터 형식으로 저장한다면?
– 각 저장소는 고정 길이를 가짐
– 데이터 저장이 간단함
– 특정 계좌 위치를 찾기가 쉬움
객체지향프로그래밍
강원대학교
40
A Sample Program
• 계좌정보를 RandomAccessFile에 저장!
• Account number: readInt and writeInt: 4 bytes
• Balance: readDouble and writeDouble: 8 bytes
• 파일에 들어 있는 계좌의 수를 알아내는 법
public int size() throws IOException
{
return (int) (file.length() / RECORD_SIZE);
// RECORD_SIZE is 12 bytes:
// 4 bytes for the account number and
// 8 bytes for the balance
}
객체지향프로그래밍
강원대학교
41
A Sample Program
• n 번째 계좌를 읽어 내는 법
public BankAccount read(int n)
throws IOException
{
file.seek(n * RECORD_SIZE);
int accountNumber = file.readInt();
double balance = file.readDouble();
return new BankAccount(accountNumber, balance);
}
객체지향프로그래밍
강원대학교
42
A Sample Program
• n번째 계좌를 파일에 적어 넣는 법
public void write(int n, BankAccount account)
throws IOException
{
file.seek(n * RECORD_SIZE);
file.writeInt(account.getAccountNumber());
file.writeDouble(account.getBalance());
}
객체지향프로그래밍
강원대학교
43
File BankData.java
001:
002:
003:
004:
005:
006:
007:
008:
009:
010:
011:
012:
013:
014:
015:
016:
017:
import java.io.IOException;
import java.io.RandomAccessFile;
/**
This class is a conduit to a random access file
containing savings account data.
*/
public class BankData
{
/**
Constructs a BankData object that is not associated
with a file.
*/
public BankData()
{
file = null;
}
객체지향프로그래밍
강원대학교
44
File BankData.java
018:
019:
020:
021:
022:
023:
024:
025:
026:
027:
028:
029:
030:
031:
032:
033:
034:
/**
Opens the data file.
@param filename the name of the file containing savings
account information
*/
public void open(String filename)
throws IOException
{
if (file != null) file.close();
file = new RandomAccessFile(filename, "rw");
}
/**
Gets the number of accounts in the file.
@return the number of accounts
*/
객체지향프로그래밍
강원대학교
45
File BankData.java
035:
036:
037:
038:
039:
040:
041:
042:
043:
044:
045:
046:
047:
048:
049:
050:
public int size()
throws IOException
{
return (int) (file.length() / RECORD_SIZE);
}
/**
Closes the data file.
*/
public void close()
throws IOException
{
if (file != null) file.close();
file = null;
}
객체지향프로그래밍
강원대학교
46
File BankData.java
051:
052:
053:
054:
055:
056:
057:
058:
059:
060:
061:
062:
063:
064:
065:
066:
/**
Reads a savings account record.
@param n the index of the account in the data file
@return a savings account object initialized with
// the file data
*/
public BankAccount read(int n)
throws IOException
{
file.seek(n * RECORD_SIZE);
int accountNumber = file.readInt();
double balance = file.readDouble();
return new BankAccount(accountNumber, balance);
}
/**
Finds the position of a bank account with a given
// number
객체지향프로그래밍
강원대학교
47
File BankData.java
067:
068:
069:
070:
071:
072:
073:
074:
075:
076:
077:
078:
079:
080:
081:
082:
@param accountNumber the number to find
@return the position of the account with the given
// number,
or -1 if there is no such account
*/
public int find(int accountNumber)
throws IOException
{
for (int i = 0; i < size(); i++)
{
file.seek(i * RECORD_SIZE);
int a = file.readInt();
if (a == accountNumber) // Found a match
return i;
}
return -1; // No match in the entire file
}
객체지향프로그래밍
강원대학교
48
File BankData.java
083:
084:
085:
086:
087:
088:
089:
090:
091:
092:
093:
094:
095:
096:
097:
098:
/**
Writes a savings account record to the data file
@param n the index of the account in the data file
@param account the account to write
*/
public void write(int n, BankAccount account)
throws IOException
{
file.seek(n * RECORD_SIZE);
file.writeInt(account.getAccountNumber());
file.writeDouble(account.getBalance());
}
private RandomAccessFile file;
객체지향프로그래밍
강원대학교
49
File BankData.java
099:
100:
101:
102:
103: }
public static final int INT_SIZE = 4;
public static final int DOUBLE_SIZE = 8;
public static final int RECORD_SIZE
= INT_SIZE + DOUBLE_SIZE;
객체지향프로그래밍
강원대학교
50
File BankDatatester.java
01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
17:
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Scanner;
/**
This program tests random access. You can access existing
accounts and deposit money, or create new accounts. The
accounts are saved in a random access file.
*/
public class BankDataTester
{
public static void main(String[] args)
throws IOException
{
Scanner in = new Scanner(System.in);
BankData data = new BankData();
try
객체지향프로그래밍
강원대학교
51
File BankDatatester.java
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
{
data.open("bank.dat");
boolean done = false;
while (!done)
{
System.out.print("Account number: ");
int accountNumber = in.nextInt();
System.out.print("Amount to deposit: ");
double amount = in.nextDouble();
객체지향프로그래밍
int position = data.find(accountNumber);
BankAccount account;
if (position >= 0) // 기존 계좌인 경우
{
account = data.read(position);
account.deposit(amount);
강원대학교
52
File BankDatatester.java
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
System.out.println("new balance="
+ account.getBalance());
}
else // 새 계좌를 추가하는 경우
{
account = new BankAccount(accountNumber,
amount);
position = data.size();
System.out.println("adding new account");
}
data.write(position, account);
System.out.print("Done? (Y/N) ");
String input = in.next();
if (input.equalsIgnoreCase("Y")) done = true;
}
}
객체지향프로그래밍
강원대학교
53
File BankDatatester.java
52:
53:
54:
55:
56:
57: }
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
finally
{
data.close();
}
}
객체지향프로그래밍
강원대학교
54
Output
Account number: 1001
Amount to deposit: 100
adding new account
Done? (Y/N) N
Account number: 1018
Amount to deposit: 200
adding new account
Done? (Y/N) N
Account number: 1001
Amount to deposit: 1000
new balance=1100.0
Done? (Y/N) Y
객체지향프로그래밍
강원대학교
55
객체 스트림
(Object Streams)
• 객체를 있는 그대로 입출력하기 위해 사용
• 객체 내부의 데이터를 일일이 저장하고 읽어들
이는 작업을 하지 않아도 됨
• 객체 전체를 ArrayList에 넣어 한꺼번에 저장할
수도 있음
• 이진데이터 형식으로 저장하므로 stream을 사용
함
객체지향프로그래밍
강원대학교
56
BankAccount 객체를 파일에 쓰기
• object output stream은 각 객체의 모든 인스턴
스 필드를 저장함
BankAccount b = . . .;
ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream("bank.dat"));
out.writeObject(b);
객체지향프로그래밍
강원대학교
57
BankAccount 객체 읽어오기
• readObject 메소드는 Object 타입을 반환함
• 캐스팅이 필요함
ObjectInputStream in = new ObjectInputStream(
new FileInputStream("bank.dat"));
BankAccount b = (BankAccount) in.readObject();
• readObject 메소드는 확인예외인
ClassNotFoundException을 던짐
객체지향프로그래밍
강원대학교
58
객체들을 모아서 저장하기
• Write
ArrayList<BankAccount> a = new ArrayList<BankAccount>();
// BankAccount 객체들을 a에 넣음
out.writeObject(a);
• Read
ArrayList<BankAccount> a = (ArrayList<BankAccount>)
in.readObject();
객체지향프로그래밍
강원대학교
59
Serializable
•
Serializable 인터페이스를 구현한 객체만이
object stream을 통해 입출력될 수 있음
class BankAccount implements Serializable
{
. . .
}
•
Serializable 인터페이스는 아무런 메소드도 갖지
않음
• 표준 라이브러리의 많은 클래스들은 Serializable
인터페이스를 구현하고 있음
객체지향프로그래밍
강원대학교
60
Serializable
• 직렬화(Serialization)
– 스트림 안에서 각 객체는 일련번호를 부여받
음
– 만약 한 객체가 두 번 저장되면 일련 번호만
두 번 기록됨
객체지향프로그래밍
강원대학교
61
File Serialtester.java
01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
import
import
import
import
import
import
java.io.File;
java.io.IOException;
java.io.FileInputStream;
java.io.FileOutputStream;
java.io.ObjectInputStream;
java.io.ObjectOutputStream;
/**
This program tests serialization of a Bank object.
If a file with serialized data exists, then it is
loaded. Otherwise the program starts with a new bank.
Bank accounts are added to the bank. Then the bank
object is saved.
*/
public class SerialTester
{
객체지향프로그래밍
강원대학교
62
File Serialtester.java
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
public static void main(String[] args)
throws IOException, ClassNotFoundException
{
Bank firstBankOfJava;
File f = new File("bank.dat");
if (f.exists())
{
ObjectInputStream in = new ObjectInputStream
(new FileInputStream(f));
firstBankOfJava = (Bank) in.readObject();
in.close();
}
else
{
firstBankOfJava = new Bank();
firstBankOfJava.addAccount(new
BankAccount(1001, 20000));
객체지향프로그래밍
강원대학교
63
File Serialtester.java
34:
firstBankOfJava.addAccount(new
BankAccount(1015, 10000));
35:
36:
37:
38:
39:
40:
}
// Deposit some money
BankAccount a = firstBankOfJava.find(1001);
a.deposit(100);
System.out.println(a.getAccountNumber()
+ ":" + a.getBalance());
a = firstBankOfJava.find(1015);
System.out.println(a.getAccountNumber()
+ ":" + a.getBalance());
41:
42:
43:
44:
45:
46:
47:
48:
49: }
ObjectOutputStream out = new ObjectOutputStream
(new FileOutputStream(f));
out.writeObject(firstBankOfJava);
out.close();
}
객체지향프로그래밍
강원대학교
64
Bank.java
public class Bank implements Serializable
{
public Bank()
{
accounts = new ArrayList<BankAccount>();
}
public void addAccount(BankAccount a)
public double getTotalBalance()
public int count(double atLeast)
public BankAccount find(int accountNumber)
public BankAccount getMaximum()
private ArrayList<BankAccount> accounts;
}
객체지향프로그래밍
강원대학교
65
Output
First Program Run
1001:20100.0
1015:10000.0
Second Program Run
1001:20200.0
1015:10000.0
객체지향프로그래밍
강원대학교
66