Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
제 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