Download oop11

Document related concepts
no text concepts found
Transcript
제 11주 파일과 스트림
(Files and Streams)
제 11주 목표
• 텍스트 파일을 읽고 텍스트 파일에 쓰는 법을 배움
• 텍스트 형식과 이진데이터 형식에 대해 이해하게 됨
• 순차 파일과 임의접근 파일에 대해 이해하게 됨
• 직렬화를 통해 객체를 저장하는 법을 배움
객체지향프로그래밍
강원대학교
1/58
텍스트 파일을 읽는 법
FileReader reader = new FileReader("input.txt");
Scanner in = new Scanner(reader);
String in.next
String in.nextLine
int in.nextInt
double in.nextDouble
in.close();
객체지향프로그래밍
강원대학교
2/58
텍스트 파일에 쓰는 법
PrintWriter out = new PrintWriter("output.txt");
• 파일이 이미 존재하는 경우 기존 내용이 지워짐
• 파일이 존재하지 않는 경우 새 파일이 만들어짐
out.println(29.95);
out.println(new Rectangle(5, 10, 15, 25));
out.println("Hello, World!");
out.close();
객체지향프로그래밍
강원대학교
3/58
A Sample Program
내 마음은 호수요
그대 저어오오
나는 그대의 흰 그림자를 안고
옥같은 그대의 뱃전에 부서지리라
내 마음은 촛불이요
그대 저 문을 닫아주오
나는 그대의 비단 옷자락에 떨며
최후의 한방울도 남김없이 타오리다
/*
/*
/*
/*
/*
/*
···
1
2
3
4
5
6
*/
*/
*/
*/
*/
*/
객체지향프로그래밍
내 마음은 호수요
그대 저어오오
나는 그대의 흰 그림자를 안고
옥같은 그대의 뱃전에 부서지리라
내 마음은 촛불이요
강원대학교
4/58
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
{
객체지향프로그래밍
강원대학교
5/58
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)
{
객체지향프로그래밍
강원대학교
6/58
File LineNumberer.java
34:
35:
36:
37: }
System.out.println("Error processing file:"
+ exception);
}
}
객체지향프로그래밍
강원대학교
7/58
File Dialog Boxes
객체지향프로그래밍
강원대학교
8/58
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
객체지향프로그래밍
강원대학교
9/58
명령줄 인자
(Command line arguments)
• java LineNumberer input.txt numbered.txt
• args[0]는 “input.txt”,
• args[1]은 “numbered.txt”
if(args.length >= 1)
inputFileName = args[0];
객체지향프로그래밍
강원대학교
10/58
텍스트 형식과 이진데이터 형식
(Text and Binary Formats)
• 데이터를 저장하는 두 가지 방법
– 텍스트 형식 (Text format)
– 이진데이터 형식 (Binary format)
• 텍스트를 한 글자씩 입출력하기 위해서는
– java.io.Reader, java.io.Writer를 사용
• 이진데이터를 한 바이트씩 입출력하기 위해서는
– java.io.InputStream, java.io.OutputStream을
사용
객체지향프로그래밍
강원대학교
11/58
텍스트 형식과 이진데이터 형식
(Text and Binary Formats)
객체지향프로그래밍
강원대학교
12/58
텍스트 형식
• 사람이 읽을 수 있는 형식
• 정수 12345는 '1' '2' '3' '4' '5' 의 문자들로 표현
됨
• 텍스트 형식 데이터의 입출력을 위해서는
Reader와 Writer 클래스를 사용
FileReader reader = new FileReader("input.txt");
FileWriter writer = new FileWriter("output.txt");
* FileReader, FileWriter는 각각 Reader와 Writer의 서브클래스임
객체지향프로그래밍
강원대학교
13/58
텍스트 형식 파일에서 한 글자 읽기
• read 메소드
– 다음 문자를 int 타입으로 반환
– end_of_file의 경우 정수 -1 반환
Reader reader = . . .;
int next = reader.read();
char c;
if (next != -1)
c = (char) next;
객체지향프로그래밍
강원대학교
14/58
텍스트 형식 파일에 한 글자 쓰기
• write 메소드
void write(int c) Writes a single character
Writer writer = . . .;
char c = ‘a’;
writer.write((int)c);
// 붉은 색 부분 생략 가능
// 생략하는 경우 자동형변환이 일어남
// 자동형변환 = implicite type conversion
// byte -> short -> int -> long -> float -> double
// char -> int
객체지향프로그래밍
강원대학교
15/58
이진데이터 형식
(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");
객체지향프로그래밍
강원대학교
16/58
이진데이터 파일에서 한 바이트 읽기
• read 메소드
– 다음 바이트를 int 타입으로 반환
– end_of_file의 경우 정수 -1 반환
InputStream in = . . .;
int next = in.read();
byte b;
if (next != -1)
b = (byte) next;
객체지향프로그래밍
강원대학교
17/58
암호화 프로그램
(An Encryption Program)
• Caesar cipher
– 1에서 25 사이 숫자 중에서 암호화 키를 선택
– 암호화 키만큼 각 글자를 이동
– 예: 만약 키가 3이라면 A는 D로, B는 E로, . . .
객체지향프로그래밍
강원대학교
18/58
An Encryption Program
 암호를 풀기 위해서는 음수의 암호화 키를 사용
객체지향프로그래밍
강원대학교
19/58
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);
}
객체지향프로그래밍
강원대학교
20/58
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
*/
객체지향프로그래밍
강원대학교
21/58
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
{
객체지향프로그래밍
강원대학교
22/58
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
*/
객체지향프로그래밍
강원대학교
23/58
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);
}
}
}
객체지향프로그래밍
강원대학교
24/58
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;
객체지향프로그래밍
강원대학교
25/58
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();
객체지향프로그래밍
강원대학교
26/58
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);
}
}
객체지향프로그래밍
강원대학교
27/58
임의 접근과 순차 접근
(Random Access vs. Sequential Access)
file pointer
객체지향프로그래밍
강원대학교
28/58
임의접근파일
(RandomAccessFile)
• 파일을 열 때 모드를 지정함
– Reading only ("r")
– Reading and writing ("rw")
RandomAccessFile f = new RandomAcessFile("bank.dat","rw");
• file pointer를 옮기는 법
f.seek(n);
객체지향프로그래밍
강원대학교
29/58
RandomAccessFile
• file pointer의 현재 위치를 알아보는 법
long n = f.getFilePointer();
// of type "long" because files can be very large
• 파일의 크기를 알아보는 법 (바이트 단위로)
fileLength = f.length();
객체지향프로그래밍
강원대학교
30/58
A Sample Program
• bank account들을 임의접근파일에 저장
• 텍스트 형식으로 저장한다면?
• 1001번 계좌에 100원을 저축하면
객체지향프로그래밍
강원대학교
31/58
A Sample Program
• 이진테이터 형식으로 저장한다면?
– 각 저장소는 고정 길이를 가짐
– 데이터 저장이 간단함
– 특정 계좌 위치를 찾기가 쉬움
객체지향프로그래밍
강원대학교
32/58
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
}
객체지향프로그래밍
강원대학교
33/58
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);
}
객체지향프로그래밍
강원대학교
34/58
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());
}
객체지향프로그래밍
강원대학교
35/58
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;
}
객체지향프로그래밍
강원대학교
36/58
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
*/
객체지향프로그래밍
강원대학교
37/58
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;
}
객체지향프로그래밍
강원대학교
38/58
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
객체지향프로그래밍
강원대학교
39/58
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
}
객체지향프로그래밍
강원대학교
40/58
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;
객체지향프로그래밍
강원대학교
41/58
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;
객체지향프로그래밍
강원대학교
42/58
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
객체지향프로그래밍
강원대학교
43/58
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);
강원대학교
44/58
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;
}
}
객체지향프로그래밍
강원대학교
45/58
File BankDatatester.java
52:
53:
54:
55:
56:
57: }
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
finally
{
data.close();
}
}
객체지향프로그래밍
강원대학교
46/58
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
객체지향프로그래밍
강원대학교
47/58
객체 스트림
(Object Streams)
• 객체를 있는 그대로 입출력하기 위해 사용
• 객체 내부의 데이터를 일일이 저장하고 읽어들
이는 작업을 하지 않아도 됨
• 객체 전체를 ArrayList에 넣어 한꺼번에 저장할
수도 있음
• 이진데이터 형식으로 저장하므로 stream을 사용
함
객체지향프로그래밍
강원대학교
48/58
BankAccount 객체를 파일에 쓰기
• object output stream은 각 객체의 모든 인스턴
스 필드를 저장함
BankAccount b = . . .;
ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream("bank.dat"));
out.writeObject(b);
객체지향프로그래밍
강원대학교
49/58
BankAccount 객체 읽어오기
• readObject 메소드는 Object 타입을 반환함
• 캐스팅이 필요함
ObjectInputStream in = new ObjectInputStream(
new FileInputStream("bank.dat"));
BankAccount b = (BankAccount) in.readObject();
• readObject 메소드는 확인예외인
ClassNotFoundException을 던짐
객체지향프로그래밍
강원대학교
50/58
객체들을 모아서 저장하기
• Write
ArrayList<BankAccount> a = new ArrayList<BankAccount>();
// BankAccount 객체들을 a에 넣음
out.writeObject(a);
• Read
ArrayList<BankAccount> a = (ArrayList<BankAccount>)
in.readObject();
객체지향프로그래밍
강원대학교
51/58
Serializable
•
Serializable 인터페이스를 구현한 객체만이
object stream을 통해 입출력될 수 있음
class BankAccount implements Serializable
{
. . .
}
•
Serializable 인터페이스는 아무런 메소드도 갖지
않음
• 표준 라이브러리의 많은 클래스들은 Serializable
인터페이스를 구현하고 있음
객체지향프로그래밍
강원대학교
52/58
Serializable
• 직렬화(Serialization)
– 스트림 안에서 각 객체는 일련번호를 부여받
음
– 만약 한 객체가 두 번 저장되면 일련 번호만
두 번 기록됨
객체지향프로그래밍
강원대학교
53/58
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
{
객체지향프로그래밍
강원대학교
54/58
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));
객체지향프로그래밍
강원대학교
55/58
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();
}
객체지향프로그래밍
강원대학교
56/58
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;
}
객체지향프로그래밍
강원대학교
57/58
Output
First Program Run
1001:20100.0
1015:10000.0
Second Program Run
1001:20200.0
1015:10000.0
객체지향프로그래밍
강원대학교
58/58
Related documents