1 / 24

14. 직렬화와 파일 입출력

14. 직렬화와 파일 입출력. 객체 저장. 직렬화를 사용한다 . 그 데이터를 만들어낸 자바 프로그램에서만 사용한다면 납작해진 ( 직렬화된 ) 객체가 저장된 파일을 만든다 . 그리고 나중에 파일을 열 때는 프로그램에서 직렬화된 객체를 읽어서 다시 살아 숨쉬는 , 힙에 들어있는 형태의 객체로 만들면 된다 . 일반 텍스트 파일로 저장한다 . 데이터를 다른 프로그램에서도 사용한다면 다른 프로그램에서도 파싱할 수 있도록 적당한 구분자를 써서 파일에 저장한다 .

jera
Download Presentation

14. 직렬화와 파일 입출력

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 14. 직렬화와 파일 입출력

  2. 객체 저장 직렬화를 사용한다. 그 데이터를 만들어낸 자바 프로그램에서만 사용한다면 납작해진 (직렬화된) 객체가 저장된 파일을 만든다. 그리고 나중에 파일을 열 때는 프로그램에서 직렬화된 객체를 읽어서 다시 살아 숨쉬는, 힙에 들어있는 형태의 객체로 만들면 된다. 일반 텍스트 파일로 저장한다. 데이터를 다른 프로그램에서도 사용한다면 다른 프로그램에서도 파싱할 수 있도록 적당한 구분자를 써서 파일에 저장한다. ex> 탭으로 각 필드를 구분하면 나중에 스프레드시트나 DB어플리케이션 등에서도 그 파일을 이용할 수 있다. Head First JAVA

  3. 객체 직렬화(저장) 방법 (1/2) “MyGame.ser”이라는 파일이 존재하지 않으면 자동으로 새로 만들어짐 FileOutputStream을 만든다. FileOutputStreamfileStream = new FileOutputStream(“MyGame.ser”); ObjectOutputStream을 만든다. ObjectOutputStreamos = new ObjectOutputStream(fileStream); 객체를 저장한다. os.writeObject(characterOne); os.writeObject(characterTwo); os.writeObject(characterThree); ObjectOutputStream을 닫는다. os.close(); FileOutputStream은 파일에 연결하는 방법을 알고 있다 ObjectOutputStream을 사용하면 객체를 저장할 수 있는데 파일에 직접 연결할 수는 없고 보조 객체가 필요하다. 이런 과정을 한 스트림을 다른 스트림과‘연쇄(chain)’한다고 부름. 참조되는 객체를 직렬화하고 “MyGame.ser”에 저장 맨 위에 있는 스트림을 닫으면 그 밑에 있는 스트림도 모두 자동으로 닫힘. Head First JAVA

  4. 객체 직렬화(저장) 방법 (2/2) 객체를 눌러준다(직렬화) 전달 ObjectOutputStream(연쇄 스트림) 객 체 연쇄 객체를 바이트 형태로 저장 011010010110111001 011010010110111001 FileOutputStream(연결 스트림) 파 일 Head First JAVA

  5. 직렬화된 객체 (1/5) 힙 안에 들어있는 객체 직렬화된 객체 00100101 00100101 01000110 01000110 width height Foo.ser FoomyFoo = new Foo(); myFoo.setWidth(37); myFoo.setHeight(70); FileOutputStreamfs = new FileOutputStream(“foo.ser”); ObjectOutputStreamos = new ObjectOutputStream(fs); os.writeObject(myFoo); 힙에 들어있는 객체는 상태(객체의 인스턴스 변수 값)가 있다. 이 값이 바로 어떤 클래스에 속하는 여러 인스턴스를 서로 구분할 수 있게 해 주는 역할을 한다. 직렬화된 객체에는 인스턴스 변수 값이 저장되어 있다. 나중에 다시 원상태로 복구하면 힙 안에 이전과 똑같은 내용을 가진 인스턴스를 만들어낼 수 있다. Head First JAVA

  6. 직렬화된 객체 (2/5) 객체가 직렬화되면 인스턴스 변수로 참조되는 모든 객체 또한 자동으로 직렬화된다. “Fido” name dogs col String Dog[] Collar Dog 객체 Kennel 객체 Dog 객체 size name col foof barf int String Collar Dog Dog Collar 객체 Dog 객체 Dog[] 배열 객체 Head First JAVA

  7. 직렬화된 객체 (3/5) 클래스를 직렬화할 수 있게 하고 싶다면 Serializable인터페이스를 구현해야 한다. import java.io.*; // Serializable이 java.io 패키지에 들어 있음 public class Box implementsSerializable { private intwidth; private intheight; public voidsetWidth(int w) { width = w; } public voidsetHeight(int h) { height = h; } public static void main (String[] args) { Box myBox = new Box(); myBox.setWidth(50); myBox.setHeight(20); try { FileOutputStreamfs = newFileOutputStream(“foo.ser”); ObjectOut[utStreamos = newObjectOutputStream(fs); os.writeObject(myBox); os.close(); } catch(Exception ex) { ex.printStackTrace(); } } } 구현해야 하는 메소드는 없지만 ‘implements Serializable’ 이라고 하면 이 유형의 객체는 직렬화할 수 있다는 것을 알 수 있음 “foo.ser”이라는 이름의 파일이 있으면 그 파일에 연결하고 그렇지 않으면 그 이름을 가지는 파일을 새로 만든다. 입출력 부분에서 예외를 던질 수 있음 연결스트림에 연쇄되는 ObjectOutputStream을 만들고 나서 그 객체를 저장하라는 명령을 내림 Head First JAVA

  8. 직렬화된 객체 (4/5) 객체를 저장할 때 그 객체와 관련된 것들이 모두 제대로 직렬화되지 않으면 그 직렬화는 제대로 완료되지 않는다. import java.io.*; public class Pond implementsSerializable { private Duck duck = new Duck(); public static void main (String[] args) { Pond myPond = new Pond(); try { FileOutputStreamfs = newFileOutputStream(“Pond.ser”); ObjectOut[utStreamos = newObjectOutputStream(fs); os.writeObject(myPond); os.close(); } catch(Exception ex) { ex.printStackTrace(); } } } public class Duck { // duck 클래스 } Pond 클래스에는 Duck 인스턴스 변수 한 개가 있음 Duck 클래스는 Serializable을 구현하지 않기 때문에 Pond 객체를 직렬화하려고 하면 Pond에 들어있는 Duck 인스턴스 변수가 저장될 수 없어 결국 직렬화되지 않는다. Head First JAVA

  9. 직렬화된 객체 (5/5) 어떤 인스턴스 변수를 저장할 수 없다면 (또는 저장해선 안 된다면) 그 변수는 transient로 지정하면 된다. transient는직렬화할 때 이 변수는 저장하지 않고 그냥 넘어가라고 지정하기 위한 키워드 import java.io.*; class Chat implementsSerializable { transient String currentID; String userName; // 나머지 코드 } userName변수는 직렬화하는 과정에서 객체 상태의 일부로 저장됨 자바 클래스 라이브러리에 있는 것은 대부분 직렬화할 수 있지만 네트워크 연결, 스레드, 파일 객체 같은 것은 저장할 수 없다 Head First JAVA

  10. 역직렬화(1/5) “MyGame.ser”이라는 파일이 없으면 예외가 발생 FileInputStream을 만든다. FileInputStreamfileStream = new FileInputStream(“MyGame.ser”); ObjectInputStream을 만든다. ObjectInputStreamos = new ObjectInputStream(fileStream); 객체를 읽는다. Object one = os.readObject(); Object two = os.readObject(); Object three = os.readObject(); FileInputStream객체를 만든다. FileInputStream은 기존의 파일에 연결할 수 있다. ObjectInputStream은 객체를 읽게 해 주지만 파일에 직접 연결할 수 없기 때문에 반드시 연결 스트림에 연쇄되어야 한다. readObject()를호출하면 그 스트림의 다음 객체를 받아올 수 있어서 처음에 저장된 순서로 그대로 가져올 수 있다. 저장 횟수보다 많이 가져오려고 하면 예외 발생 Head First JAVA

  11. 역직렬화(2/5) 객체를 캐스트한다. GameCharacter elf = (GameCharacter) one; GameCharacter troll = (GameCharacter) two; GameCharacter magician = (GameCharacter) three; ObjectInputStream을 닫는다. os.close(); readObject()의리턴값은Object 유형이므로 우리가 알고 있는 원래 유형으로 다시 캐스트해야 한다. 맨 위에 있는 스트림을 닫으면 그 밑에 있는 것도 같이 닫히기 때문에 FileInputStream (그리고 그 파일)도 자동으로 닫힌다. Head First JAVA

  12. 역직렬화(3/5) 객체를 바이트 형태로 읽음 011010010110111001 011010010110111001 읽는다 FileInputStream(연결 스트림) 파 일 연쇄 JVM에서 클래스를 찾을 수 없거나 불러올 수 없으면 이 단계에서 예외가 발생 클래스를 찾아서 불러온 다음 인스턴스변수값을 다시 대입함 객 체 ObjectInputStream(연쇄 스트림) Head First JAVA

  13. 역직렬화(4/5) 스트림으로부터 객체를 읽어온다. JVM에서 객체의 클래스 유형을 결정한다. JVM에서 객체의 클래스를 찾아서 불러오려는 시도를 하는데 클래스를 찾거나 불러오는데 실패한다면 JVM에서 예외를 던지고 역직렬화는 실패한다. 새로운 객체는 힙에 공간을 할당 받지만 직렬화된 객체는 처음 생성될 때의 상태가 아닌 직렬화되었을 때의 상태로 되돌아가야 하기 때문에 생성자가 실행되지 않는다. Head First JAVA

  14. 역직렬화(5/5) 객체의 상속 트리에서 그 위 어딘가에 직렬화할 수 없는 클래스가 있다면 그 직렬화할 수 없는 클래스의 생성자가 실행된다. 일단 생성자 연쇄 호출이 시작되면 가장 가까운 직렬화할 수 없는 클래스부터 시작해서 그 위로 있는 모든 상위클래스의 생성자에서 상태를 새로 초기화하게 된다. 객체의 인스턴스 변수에 직렬화된 상태값이 대입된다. Transient로 지정된 변수는 레퍼런스인 경우에는 null이, 원시변수인 경우에는 0, false 등이 주어진다. Head First JAVA

  15. 직렬화 예제 (1/3) import java.io.*; public classGameSaverTest { public static void main(String[] args) { GameCharacterone = newGameCharacter(40, "Elf", new String[] {"bow", "sword", "dust"}); GameCharactertwo = newGameCharacter(200, "Troll", new String[] {"bare hands", "big ax"}); GameCharacterthree = newGameCharacter(120, "Magician", new String[] {"spells", "invisibility"}); try{ ObjectOutputStreamos = new ObjectOutputStream(new FileOutputStream("Game.ser")); os.writeObject(one); os.writeObject(two); os.writeObject(three); os.close(); } catch (IOException ex) { ex.printStackTrace(); } 몇 가지 캐릭터를 만든다. 이렇게 해도 된다. Head First JAVA

  16. 직렬화 예제 (2/3) one = null; two = null; three = null; try{ ObjectInputStreamis = newObjectInputStream(newFileInputStream("Game.ser")); GameCharacteroneRestore = (GameCharacter) is.readObject(); GameCharactertwoRestore = (GameCharacter) is.readObject(); GameCharacterthreeRestore = (GameCharacter) is.readObject(); System.out.println("One's type: " + oneRestore.getType()); System.out.println("Two's type: " + twoRestore.getType()); System.out.println("Three's type: " + threeRestore.getType()); } catch (Exception ex) { ex.printStackTrace(); } } } null로 설정하면 힙에 있는 객체에 접근할 수 없다. 파일로부터다시 읽어드린다. 제대로 읽혔는지 다시 확인한다. Head First JAVA

  17. 직렬화 예제 (3/3) import java.io.*; publicclass GameCharacterimplementsSerializable { intpower; String type; String[] weapons; publicGameCharacter(int p, String t, String[] w) { power= p; type= t; weapons= w; } public intgetPower() { returnpower; } publicString getType() { returntype; } publicString getWeapons() { String weaponList = ""; for(inti = 0; i < weapons.length; i++) { weaponList+= weapons[i] + ""; } returnweaponList; } } Head First JAVA

  18. 핵심정리 (1/3) 객체를 직렬화하면 객체의 상태를 저장할 수 있다. 객체를 직렬화하려면 ObjectOutputStream이 필요하다. 스트림에는 연결 스트림과 연쇄 스트림이 있다. 연결 스트림은 출발지나 목적지에 대한 연결을 나타낸다. 연쇄 스트림은 반드시 연결 스트림 또는 다른 스트림에 연쇄되어야 한다. 객체를 직렬화해서 파일로 저장하고 싶다면 FileOutputStream을 만들고 그 스트림에 ObjectOutputStream에 연쇄시키면 된다. Head First JAVA

  19. 핵심정리 (2/3) 객체를 직렬화할 때는 ObjectOutputStream의 writeObject(theObject) 메소드를 호출하면 된다. Serializable인터페이스를 구현한 객체만 직렬화할 수 있다. 상위 클래스 중 Serializable을 구현하는 클래스가 있다면 자동으로 직렬화할 수 있는 클래스가 된다. 객체가 직렬화되면 그 객체와 연관된 모든 객체가 직렬화된다. 연관된 객체 중에 직렬화할 수 없는 것이 하나라도 있으면 직렬화 과정에서 예외가 던져진다. 직렬화할 때 어떤 인스턴스 변수를 건너뛰고 싶다면 transient 키워드를 사용하면 된다. Head First JAVA

  20. 핵심정리 (3/3) 역직렬화를 할 때는 그 JVM에서 해당 객체와 연관된 모든 객체의 클래스를 사용할 수 있어야만 한다. 객체를 읽을 때는 처음에 객체를 저장한 것과 같은 순으로 읽어오게 된다. readObject()의 리턴 유형은 Object므로 역직렬화 과정에서 원래 유형으로 캐스트해야 한다. 정적 변수는 직렬화되지 않는다. 정적 변수 값은 한 유형에 속하는 모든 객체들에 들어있는 단 한 개 뿐인 값을 공유하기 때문에 특정 객체 상태의 일부로 저장할 이유가 없다. Head First JAVA

  21. 텍스트 파일로 저장 import java.io.*; classWriteAFile { public static void main(String[] args) { try { FileWriter writer = newFileWriter(“Foo.txt”); writer.write(“hello foo!”); writer.close(); } catch (IOException ex) { ex.printStackTrace(); } } } “Foo.txt”라는 파일이 없으면 FileWriter에서 새로 만든다. 입출력 관련 코드는 모두 try/catch 블록 안에 집어넣어야 한다. IOException을 던질 수 있다. Write() 메소드는String을 인자로 받아들인다. 텍스트 데이터를 저장하는 것은 객체를 저장하는 것과 비슷하지만 객체 대신 String을 저장하고 FileOutputStream대신 FileWriter를 쓴다. ObjectOutputStream에 연쇄시키지 않아도 된다. Head First JAVA

  22. Java.io.File클래스 (1/2) File 객체는 디스크에 있는 파일이나 디렉토리의 이름과 경로를 나타낸다. 하지만 그 파일에 들어있는 데이터를 나타낸다거나 그 데이터에 접근할 수 있게 해 주는 것은 아니다. 이미 존재하는 파일을 나타내는 File 객체를 만든다. File f = new File(“MyCode.txt”); 새로운 디렉토리를 만든다. File dir = new File(“Chapter7”); dir.mkdir(); Head First JAVA

  23. Java.io.File클래스 (2/2) 디렉토리에 들어있는 내용의 목록을 출력한다. if (dir.isDirectory()) { String[] dirContents = dir.list(); for (inti = 0; i < dirContents.length; i++) { System.out.println(dirContents[i]); } } 파일 또는 디렉토리의 절대 경로명을 구한다. System.out.println(dir.getAbsolutePath()); 파일 또는 디렉토리를 삭제한다(성공한 경우에는 true를 리턴). booleanisDeleted = f.delete(); Head First JAVA

  24. 텍스트 파일을 읽는 방법 File객체와 FileReader객체, BufferedReader를 이용한다. import java.io.*; classReadAFile { public static void main(String[] args) { try { File myFile = new File(“MyText.txt”); FileReaderfileReader = newFileReader(myFile); BufferedReader reader = newBufferedReader(fileReader); String line = null; while ((line = reader.readLine()) != null) { System.out.println(line); } reader.close(); } catch (Exception ex) { ex.printStackTrace(); } } } FileReader는 텍스트 파일로 연결되는 문자를 위한 연결 스트림이다. 행을 읽어올 때마다 각 행을 저장하기 위한 String 변수를 만든다. 읽기작업의 효율을 향상시키기 위해 FileReader를 BufferedReader에 연쇄시킨다. 텍스트 한 행을 읽은 다음 그 행을 line이라는 String 변수에 저장하는 부분이다. 읽을것이 있으면 null이 아니기 때문에 방금 읽어온 것을 출력한다. Head First JAVA

More Related