즐거운자바(5) - JavaIO

지환·2023년 8월 10일
0

JAVA

목록 보기
6/39
post-thumbnail

출처 https://www.inflearn.com/course/%EC%A6%90%EA%B1%B0%EC%9A%B4-%EC%9E%90%EB%B0%94

JAVA IO(입출력)

IO란?

  • Input & Output
  • 입출력
  • 입력은 키보드, 네트워크, 파일 등으로 부터 받을 수 있다.
  • 출력은 화면, 네트워크, 파일 등에 할 수 있다

Java IO 도 객체다.

  • Java IO에서 사용되는 객체는 자바 세상에서 사용되는 객체이다.
  • Java IO가 제공하는 객체는 어떤 대상으로 부터 읽어들이며, 어떤 대상에게 쓰는 일을 한다.

  • 장식을 하고 또 장식을 하는 구조다.
  • 왼쪽이 주인공(ConcreteComponent) 오른쪽이 장식(Decorator) -> Decorator가 마름모를 통해서 Component를 가질 수 있다.
  • Decorator 생성자는 주인공을 받아들이게 되어있다.

주인공과 장식을 구분할 수 있어야 한다.

  • 장식은 InputStream, OutputStream, Reader, Write를 생성자에서 받아들인다.
  • 주인공은 어떤 대상에게서 읽어들일지, 쓸지를 결정한다.
  • 주인공은 1byte or byte[] 단위로 읽고 쓰는 메소드를 가진다.
  • 주인공은 1char or char[] 단위로 읽고 쓰는 메소드를 가진다.
  • 장식은 다양한 방식으로 읽고 쓰는 메소드를 가진다.

Java IO의 특수한 객체

system.in : 표준입력(InputStream) -> 키보드로부터 입력

System.out : 표준 출력(PrintStream)

System.err : 표준 에러 출력 (PrintStream)

  • 여기서 주인공 역할과 장식 역할을 하는게 있다.
  • 여기서 중요한 부분 InputStream, OutputStream, Reader , Writer

Java IO 클래스는 생성자가 중요하다

  • 장식은 InputStream, OutputStream, Reader, Writer를 생성자에서 받아들인다. (또한 추상 클래스) / 장식 역할이다. --> 생성자에서 네 가지 중에 하나를 받아들이는 애들이 있다면 장식이다.

  • 이런 얘들은 InputStream, OutputStream, Reader, Writer 이 없기 때문에 -> 주인공 역할이다.

  • 얘도 주인공 역할이다.

Java IO를 잘 다루려면, API는 한번쯤은 읽어봐야 한다.

문제) 키보드로 부터 한줄 씩 입력 받아 화면에 한줄씩 출력하시오.

package javaIO;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;

public class KeyBoardIOExam{
    public static void main(String[] args) throws IOException {
        // 키보드로부터 한줄씩 입력받고, 한줄씩 화면에 출력하시오.
        // system.in (InputStream 주인공)
        // 화면에 출력 : System.out (PrintStream 주인공)
        // 키보드로 입력받는다는건 문자를 입력받는 것 : char 단위 입출력
        // char 단위 입출력 클래스는 Reader, Writer
        // 한줄 읽기 BufferedReader 라는 클래스는 readLine이라는 메소드를 가지고 있다.
        //                         더 이상 읽어들일것이(EOF) 없으면 null을 반환
        //                          장식!
        // 한줄 쓰기 : PrintStream, PrintWriter

        // BurredReader x
        // CharReader x - 문자로 부터 입력받음
        // FilterReader x - 장식. Reader 를 넣어줘야 한다.
        // InputStreamReader(InputStream in) - 장식
        // BufferedReader(Reader in) 에서 Reader는 추상클래스임
        // InputStreamreader(InputStream in) 장식
        // Reader의 서브 클래스인 자식들(BufferdReader, InputStreamReader 등)를 받아들이겠다는 말
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        // System.in 에서 입력받고, InputStreamrader로 전달하고 BuffereReader로 전달하고 문자로 리턴
        String line = null;
        while ((line = br.readLine()) != null) { // 한줄 입력받는다. 
            // Mac의 경우 command + D 를 하면 null값을 넣어줌
            // Windows의 경우 CTRL + D
            System.out.println("읽어들인값 : "+line);
        }
    }
}

-------------
asdas
읽어들인값 : asdas

동작 과정

File 클래스

  • java.io.File 클래스는 파일의 크기, 파일의 접근 권한, 파일의 삭제, 이름 변경 등의 작업을 할 수 있는 기능을 제공하여 준다.
  • 여기서 주의해야 할 것은 디렉토리(폴더) 역시 파일로써 취급된다는 것이다.


FileInfo

import java.io.File;
import java.io.IOException;

// java FileInfo
public class FileInfo {

    public static void main(String[] args) {
        if(args.length != 1) {
            System.out.println("사용법 : java FileInfo 파일이름");
            System.exit(0); // return; 같은말
        } // if end

        // 문자를 하나 받아들임
        File f = new File(args[0]); // 파일의 경로를 읽어들여서
        if(f.exists()) { // 파일이 존재할 경우
            System.out.println("length : "+f.length());
            System.out.println("canRead : "+f.canRead());
            System.out.println("canWrite : "+f.canWrite());
            System.out.println("getAbsolutePath : "+f.getAbsolutePath());
            try {
                System.out.println("getCanonicalPath :"+f.getCanonicalPath());
            } catch (IOException e) {
                System.out.println(e);
            }
            System.out.println("getName : "+f.getName());
            System.out.println("getParent : "+f.getParent());
            System.out.println("getPath : "+f.getPath());
        } else { // 파일이 존재하지 않을 경우
            System.out.println("파일이 존재하지 않습니다.");
        }
    } // main end
}


-------------------
결과 
에디터에 .< 입력 했을 때

length : 4096
canRead : true
canWrite : true
getAbsolutePath : C:\Users\HB\IdeaProjects\JavaIo\.
getCanonicalPath :C:\Users\HB\IdeaProjects\JavaIo
getName : .
getParent : null
getPath : .

Process finished with exit code 0

FileList

import java.io.File;

// 파일 목록 출력하기
public class FileList {
    public static void main(String[] args) {
        File file = new File("/tmp");

        printFiles(file);
    }
    private static void printFiles(File file) {
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            file.listFiles();
            // 파일 이름 출력
            for (int i = 0; i < files.length; i++) {
                System.out.println("[dir] - "+files[i]);
                printFiles(files[i]);
            }
        } else if(file.isFile()){
            System.out.println(file.getName());
        } else {
            System.out.println("else --"+file.getName());
        }
    }
}

------------------

"C:\Program Files\Java\jdk-17.0.4\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2023.1.3\lib\idea_rt.jar=55783:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2023.1.3\bin" -Dfile.encoding=UTF-8 -classpath C:\Users\HB\IdeaProjects\JavaIo\out\production\JavaIo FileList
else --tmp

Process finished with exit code 0

TempFile

import java.io.File;
import java.io.IOException;

public class TempFile {
    public static void main(String[] args) {
        try {
            File f = File.createTempFile("tmp_", ".dat");
            System.out.println(f.getAbsolutePath());
            System.out.println("10초 동안 멈춰있습니다.");
            try {
                Thread.sleep(10000); // 10초 동안 정지
            } catch(InterruptedException e1) {
                System.out.println(e1);
            }
            f.deleteOnExit(); // JVM이 종료될 때 자동으로 파일을 삭제한다.
        } catch (IOException e) {
            System.out.println(e);
        }
    }
}

Byte Stream

주인공과 장식을 구분 할 수 있어야 한다.

InputStream, OutpuSteam

  • 추상 클래스
  • byte 단위 입출력 클래스는 InputStream, OutputStream의 후손이다.

import java.io.IOException;
import java.io.InputStream;

/*
1byte가 표현할 수 있는 값 : 00000000 ~ 11111111
read() 메소드가 읽어들일 수 있는 정보.
1byte씩 파일을 읽어들인다. 파일의 크기를 모른다. 그럼 언제까지 읽어들이냐
더 이상 읽어들일게 없다 EOF (EOF를 표현할 수 없어서, int 타입을 리턴)

int 에 1 byte 값을 담자 00000000 00000000 00000000 00000000
                     00000000 00000000 00000000 11111111
EOF : -1
1 --> 00000000 00000000 00000000 00000001
1의 보수 11111111 11111111 11111111 11111110
2의 보수 11111111 11111111 11111111 11111111 : -1
 */


/* 숙제?

1. txt 파일로 입력 받아 한줄씩 입력 받아 파일에 출력한다.
2. 키보드로 부터 한줄씩 입력받아 파일에 출력한다. (파일명은 아규먼트로 받아들인다)
3. txt 파일로 부터 한줄씩 입력받아 다른 파일에 한줄씩 출력한다.
 */
public class InputStreamExam01 {
    public static void main(String[] args) {


        InputStream in = null;
        try {
            int data = in.read();
            // byte를 리턴하지 못하고 int로 리턴하는 이유
            // : EOF를 표현할 방법이 없어서
        } catch (IOException ex) {
            System.out.println("IO 오류" + ex);
        } finally {
            try {
                in.close();
            } catch (Exception ex2) {
                System.out.println("io 오류 : " + ex2);
            }
        }
    }
}

IO Stream

Reader, Writer

  • 추상 클래스
  • char단위 입출력 클래스는 Rader, Writer의 후손이다.

HelloIO01

import java.io.FileOutputStream;
import java.io.OutputStream;

public class HelloIO01 {
    public static void main(String[] args) throws Exception{
        OutputStream out = new FileOutputStream("/tmp/helloio01.dat");
        out.write(1); // 0000 0000      0000 0000       0000 0000       0000 0001
        out.write(255);
        out.write(0);
        out.close();
    }
}

HelloIO02

import java.io.FileInputStream;
import java.io.InputStream;

public class HelloIO02 {
    public static void main(String[] args) throws Exception{
        InputStream in = new FileInputStream("/tmp/helloio01.dat");
//        int i1 = in.read();
//        System.out.println(i1); // 1 첫번째 바이트를 읽게됨
//        int i2 = in.read();
//        System.out.println(i2); // 255 두번째 바이트를 읽게됨
//        int i3 = in.read(); 
//        System.out.println(i3); // 0 세번째 바이트를 읽게됨
//        int i4 = in.read();
//        System.out.println(i4); // -1 (파일의 끝)
        int buf = -1;
        while((buf = in.read()) != -1) { // 더 이상 읽을게 없을 때
            System.out.println(buf);
        }
        in.close();
    }
}

추상 클래스라서 new Reader 이런게 안됨

HelloIO03

import java.io.FileWriter;
import java.io.Writer;

public class HelloIO03 {
    public static void main(String[] args) throws Exception {
        Writer out = new FileWriter("/tmp/hello.txt");
        // 정수로 형변화해서 저장
        out.write((int)'가');
        out.write((int)'나');
        out.write((int)'다');
        out.close();
    }
}

HelloIO04

import java.io.File;
import java.io.FileReader;
import java.io.Reader;

public class HelloIO04 {
    public static void main(String[] args) throws Exception{
        Reader in = new FileReader("/tmp/hello.txt");
//        int ch1 = in.read();
//        System.out.println((char)ch1);
//        int ch2 = in.read();
//        System.out.println((char) ch2);
//        int ch3 = in.read();
//        System.out.println((char) ch3);
//        int ch4 = in.read();
//        System.out.println(ch4);
        int ch = -1;
        while((ch = in.read()) != -1) {
            System.out.println((char)ch);
        }
        in.close();
    }
}

HelloIO05

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

public class HelloIO05 {
    public static void main(String[] args) throws Exception {
        // FileOutputStream은 "/tmp/my.txt"에 저장한다
        // FileOutputStream은 write(int); int의 마지마 byte만 저장
        // OutPutStreamWriter 생성자에 들어온 OutputStream의 write()을 이용하여 쓴다.
        // OutPutStreamWriter는 write(int); int의 끝부분 char를 저장
        // PrintWriter는 생성자에 들어온 OutputStreamWrite의 write()을 이용하여 쓴다.
        // PrintWriter는 println(문자열); 문자열을 출력한다.
        PrintWriter out = new PrintWriter(new OutputStreamWriter(new FileOutputStream("/tmp/my.txt")));
        out.println("hello");
        out.println("world");
        out.println("!!!!!");
        out.close();
    }
}

HelloIO06

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;

public class HelloIO06 {
    public static void main(String[] args) throws Exception{
        BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream("/tmp/my.txt")));

//        String line1 = in.readLine(); // hello
//        String line2 = in.readLine(); // world
//        String line3 = in.readLine(); // !!!!!
//        String line4 = in.readLine(); // null
//        System.out.println(line1);
//        System.out.println(line2);
//        System.out.println(line3);
//        System.out.println(line4);
        String line = null;
        while ((line = in.readLine()) != null) {
            System.out.println(line);
        }
        in.close();
    }
}

파일과 폴더를 다이어그램으로 표현해보자

  • 폴더가 파일을 가진다. 폴더가 폴더를 가진다.
  • Node : 공통점
  • 폴더가 노드를 가진다

  • 컴포지트 패턴[공통적인 부분이 FileComponent에 묶음]
  • Folder는 FileComponet를 가진다 라는 얘기 [화살표]
  • Folder는 FileComponent를 가짐으로써 일체화 시킨다. 상속 받는 것을 모두 가지게 만든다.

CompositePatternDemo

public class CompositePatternDemo {
    public static void main(String[] args) {
        File f1 = new File("file1", 10L);
        File f2 = new File("file2", 20L);
        File f3 = new File("file3", 30L);

        Folder folder1 = new Folder("folder1");
        Folder folder2 = new Folder("folder2");

        folder1.add(f1);
        folder1.add(folder2);

        folder2.add(f2);
        folder2.add(f3);

        System.out.println(folder1.getSize());
    }
}

Node


public abstract class Node {
    private String name;

    public Node(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public abstract long getSize();
    public abstract boolean isFolder();
}

File


public class File extends Node{ // Node를 상속받고 있다.
    private long size;

    public  File(String name, long size) {
        super(name);
        this.size = size;
    }

    @Override
    public long getSize() {return this.size;}

    @Override
    public boolean isFolder() {return false;}
}

Folder


import java.util.ArrayList;
import java.util.List;

public class Folder extends Node{
    private List<Node> nodes; // Folder가 Node를 여러개 가질 수 있다.라는 의미다.

    public Folder(String name) {
        super(name);
        nodes = new ArrayList<>(); //nodes를 초기화해줌
    }

    // 오버로딩
    public void add(File file) {nodes.add(file);}

    public void add(Folder folder) {nodes.add(folder);}

    @Override
    public long getSize() {
        long total = 0L;
        for(int i=0; i< nodes.size(); i++) {
            total = total + nodes.get(i).getSize(); //getSize()에서 폴더의 사이즈면 폴더크기를 리턴
        }
        return total;
    }

    @Override
    public boolean isFolder() {
        return true;
    }
}

  • Circle , Rectangle --> 주인공 역할을 수행하며 , 장식할 대상이다.

  • Shape를 상속 받고 있는 ShapeDecorator, RedShapeDecorator [장식 역할을 하며] 추상 클래스이다.

DecoratorPatternDemo

package Decorator;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.InputStream;

public class DecoratorPatternDemo {
    public static void main(String[] args) throws Exception{
        Circle circle = new Circle();

//        RedShapeDecorator redShapeDecorator = new RedShapeDecorator(circle);
//        redShapeDecorator.draw();;
//
//        GreenShapeDecorator greenShapeDecorator = new GreenShapeDecorator(redShapeDecorator);
//        greenShapeDecorator.draw();

        Shape shape = new GreenShapeDecorator(new RedShapeDecorator(new Rectangle()));
        shape.draw();

        // Shape ==> InputStream (추상 클래스)
        // Rectangle ==> FileInputStream
        // RedShapeStreamDecorator ==> DataInputStream
        InputStream in = new DataInputStream(new FileInputStream("a.txt"));
    }
}

Circle

package Decorator;

public class Circle extends Shape{
    @Override
    public void draw() {
        System.out.println("Shape : Circle");
    }
}

Rectangle

package Decorator;

public class Rectangle extends Shape{

    @Override
    public void draw() {
        System.out.println("Shape : Rectangle");
    }
}

Shape

package Decorator;

public class Shape {
    public void draw() {

    }
}

ShapeDecorator

package Decorator;

public abstract class ShapeDecorator extends Shape{
    protected Shape decoratedShape;

    public ShapeDecorator(Shape decoratedShape) {this.decoratedShape = decoratedShape;}

    public void draw() {decoratedShape.draw();}
}

RedShapeDecorator

package Decorator;

public class RedShapeDecorator extends ShapeDecorator{

    public RedShapeDecorator(Shape decoratedShape) {
        super(decoratedShape);
    }

    @Override
    public void draw() {
//        decoratedShape.draw();
        setRedBorder(decoratedShape);
    }

    private void setRedBorder(Shape decoratedShape) {
        System.out.println("RED =================== Start");
        decoratedShape.draw();
        System.out.println("RED =================== End");
    }
}

GreenShapeDecorator

package Decorator;

public class GreenShapeDecorator extends ShapeDecorator{

    public GreenShapeDecorator(Shape decoratedShape) {
        super(decoratedShape);
    }

    @Override
    public void draw() {
//        decoratedShape.draw();
        setRedBorder(decoratedShape);
    }

    private void setRedBorder(Shape decoratedShape) {
        System.out.println("Green ****************** Start");
        decoratedShape.draw();
        System.out.println("Green ****************** End");
    }
}

주인공과 장식을 구분할 수 있어야 한다.

  • 장식은 InputStream, OutputStream, Reader, Writer를 생성자에서 받아들인다.
  • 주인공은 어떤 대상에게서 읽어들일지, 쓸지를 결정한다.
  • 주인공은 1byte or byte[] 단위로 읽고 쓰는 메소드를 가진다.
  • 주인공은 1char or char[] 단위로 읽고 쓰는 메소드를 가진다.
  • 장식은 다양한 방식으로 읽고 쓰는 메소드를 가진다.

한줄 입력받아 출력하기

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class IOExam01 {
    public static void main(String[] args) throws Exception{
        // 키보드로부터 한줄씩 입력받는다.
        // BufferedReader의 readLine()을 이용해야 한줄씩 입력받을 수 있다.
        // BufferdReader는 장식역활을 수행한다.

        // 키보드를 나타내는 것은 System.in - 주인공 - inputStream

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String line = br.readLine();
        System.out.println(line);
        br.close();
    }
}

DataInputStream,DataOutputStream

  • 기본형 타입과 문자열을 읽고 쓸 수 있다.

DataInputStream

import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class IOExam12 {
    public static void main(String[] args) throws Exception {
        // 문제. 이름, 국어, 영어, 수하, 총점, 평균 점수를 /tmp/score.dat 파일에서 읽어들이시오.
        DataInputStream in = new DataInputStream(new FileInputStream("/tmp/score.dat"));

        // 2 사람의 정보를 읽어옴
        printStudent(in);
        printStudent(in);

        in.close();
    }

    private static void printStudent(DataInputStream in) throws IOException {
        String name = in.readUTF();
        int kor = in.readInt();
        int eng = in.readInt();
        int math = in.readInt();
        double total = in.readDouble();
        double avg = in.readDouble();

        System.out.println(name);
        System.out.println(kor);
        System.out.println(eng);
        System.out.println(math);
        System.out.println(total);
        System.out.println(avg);
    }
}

DataOutputStream

import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.FileOutputStream;

public class IOExam11 {
    public static void main(String[] args) throws Exception {
        // 문제. 이름, 국어, 영어, 수학 점수를 /tmp/score.dat 파일에 저장하시오.
        String name = "kim";
        int kor = 90;
        int eng = 50;
        int math = 70;
        double total = kor+eng+math;
        System.out.println(total);
        double avg = total / 3.0;
        System.out.println(avg);

        DataOutputStream out = new DataOutputStream(new FileOutputStream("/tmp/score.dat"));
        out.writeUTF(name);
        out.writeInt(kor);
        out.writeInt(math);
        out.writeInt(eng);
        out.writeDouble(total);
        out.writeDouble(avg);

        out.writeUTF(name);
        out.writeInt(kor);
        out.writeInt(math);
        out.writeInt(eng);
        out.writeDouble(total);
        out.writeDouble(avg);
        out.close();
    }
}

ByteArrayInputStream, ByteArrayOutPutStream

  • byte[]에 데이터를 읽고 쓰기

ByteArrayOutputStream

package IoExam;

import java.io.ByteArrayOutputStream;

public class IoExam13 {
    public static void main(String[] args) throws Exception{
        int data1 = 1;
        int data2 = 2;
        ByteArrayOutputStream out = new ByteArrayOutputStream(); // 메모리 상에 저장이 된다.
        out.write(data1); // data1의 마지막 한 바이트만 저장한다.
        out.write(data2);
        out.close();
        byte[] array = out.toByteArray(); // 바이트의 값을 꺼내올 수 있다.
        System.out.println(array.length);
        System.out.println(array[0]);
        System.out.println(array[1]);


    }
}

----------------------------
2
1
2

ByteArrayInputStream

package IoExam;

import java.io.ByteArrayInputStream;

public class IoExam14 {
    public static void main(String[] args) throws Exception{
        byte[] array = new byte[2];
        array[0] = (byte)1;
        array[1] = (byte)2;
        ByteArrayInputStream in = new ByteArrayInputStream(array);
        int read1 = in.read();
        int read2 = in.read();
        int read3 = in.read(); // 읽어들일 값이 없으면 -1 이 나옴
        in.close();

        System.out.println(read1);
        System.out.println(read2);
        System.out.println(read3);


    }
}

--------------------------------
1
2
-1

CharArrayReader, CharArrayWriter

  • char[]에 데이터를 읽고 쓰기

StringReader, StringWriter

  • 문자열 읽고 쓰기

StringWriter

package IoExam;

import java.io.StringWriter;

public class IoExam15 {
    public static void main(String[] args) throws Exception{
        StringWriter out = new StringWriter();
        out.write("hello");
        out.write("world");
        out.write("!!!!!!!");
        out.close();

        String str = out.toString();
        System.out.println(str);


    }
}

StringReader

package IoExam;

import java.io.StringReader;

public class IoStringReader {
    public static void main(String[] args) throws Exception{
        StringReader in = new StringReader("helloworld!!!");
        int ch = -1;

        while ((ch=in.read()) != -1) {
            System.out.print((char)ch);
        }
        in.close();
    }
}

ObjectinputStream, ObjectOutputStream

  • 직렬화 가능한 대상을 읽고 쓸 수 있다.
  • 직렬화 가능한 대상은 기본형 타입 or java.io.Serializable 인터페이스를 구현하고 있는 객체이다.

객체를 저장한다.

package IoExam.Io;

import java.io.Serializable;

public class User implements Serializable {
    private String email;
    private String name;
    private int birthYear;

    public User(String email, String name, int birthYear) {
        this.email = email;
        this.name = name;
        this.birthYear = birthYear;
    }

    public String getEmail() {
        return email;
    }

    public String getName() {
        return name;
    }

    public int getBirthYear() {
        return birthYear;
    }

    @Override
    public String toString() {
        return "User{" +
                "email='" + email + '\'' +
                ", name='" + name + '\'' +
                ", birthYear=" + birthYear +
                '}';
    }
}

ObjectOutputStream

package IoExam.Io;

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;

public class ObjectOutputExam {
    public static void main(String[] args) throws Exception{
        User user = new User("daksld@naver.com", "홍길동", 1442);
        // temp --> 밑에 저장
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("/temp.user.dat"));
        out.writeObject(user);
        out.close();

    }
}

객체를 출력한다.

package IoExam.Io;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.util.ArrayList;

public class ObjectInputStream {
    public static void main(String[] args) throws Exception {
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("/tmp/userlist.dat"));
        // user 객체를 형변환 하여 받아들임
        ArrayList<User> list = (ArrayList)in.readObject();
        in.close();
        // 직렬화
        for (int i =0; i < list.size(); i++)
            System.out.println(list.get(i));
    }
}

ObjectOutputExam

package IoExam.Io;

import java.io.*;
import java.util.ArrayList;

public class ObjectOutputExam {
    public static void main(String[] args) throws Exception {
        User user1 = new User("hong@exam.com", "홍길동", 1992);
        User user2 = new User("go@exam.com", "고길동", 1995);
        User user3 = new User("d@exam.com", "둘리", 1991);
        ArrayList<User> list = new ArrayList<>();
        list.add(user1);
        list.add(user2);
        list.add(user3);


//        // User 자체가 복사가 되지 않은 얕은 복사
//        ArrayList<User> list2 = list;
//
//        for (int i = 0; i < list.size(); i++) {
//            System.out.println(list2.get(i));
////            list2.add(list.get(i));
//        }
//
//        list.remove(2);
//        System.out.println(list.size()); // 2
//        System.out.println(list2.size()); // 2


        // 깊은 복사를 하기 위해서 객체 직렬화가 필요함
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(bout);
        out.writeObject(list);
        out.close();
        bout.close();

        byte[] array = bout.toByteArray();

        ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(array));
        ArrayList<User> list2 = (ArrayList)in.readObject();

        // list2에 있는 user 목록들은 그대로
        list.remove(2);

        for (int i=0; i<list2.size(); i++) {
            System.out.println(list2.get(i));
        }
    }
}

ArrayList<User> list2 = list;
  • 같은 ArrayList를 참조하라는 얘기 복사에 대한 얘기가 시작된다. 이 코드는 복사에 대한 개념이냐? 참조에 대한 개념인가?
//        // User 자체가 복사가 되지 않은 얕은 복사
        ArrayList<User> list2 = new ArrayList<>();

        for (int i = 0; i < list.size(); i++) {
            System.out.println(list2.get(i));
            list2.add(list.get(i));
        }

        list.remove(2);
        System.out.println(list.size()); // 2
        System.out.println(list2.size()); // 2

ArrayList<User> list2 = new ArrayList<>();

        for (int i = 0; i < list.size(); i++) {
            System.out.println(list2.get(i));
            list2.add(list.get(i));
        }

list 자체는 따로따로 생겼지만 -> 같은 User를 사용하고 있다. 이렇게 되면 User의 정보를 변경하게 되면 List, List2의 값이 변경된다.

        // 깊은 복사를 하기 위해서 객체 직렬화가 필요함
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(bout);
        out.writeObject(list);
        out.close();
        bout.close();

        byte[] array = bout.toByteArray();

        ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(array));
        ArrayList<User> list2 = (ArrayList)in.readObject();

        // list2에 있는 user 목록들은 그대로
        list.remove(2);

        for (int i=0; i<list2.size(); i++) {
            System.out.println(list2.get(i));
        }
    }
}


profile
아는만큼보인다.

0개의 댓글