본문 바로가기
교육/Java&Spring

kosta 클라우드 네이티브 애플리케이션 개발 과정 day 18

by Renechoi 2023. 1. 13.

kosta 클라우드 네이티브 애플리케이션 개발 과정 day 18

 

 

자바 입출력 

 

스트림이란? 일차원적인 데이터의 흐름 

 

자바 IO => 클래스가 많다 ! 

 

왜이렇게 많을까? 내용물들이 다르기 때문이다 ! 

 

파일 입출력의 과정 

1) 파일을 열고 

2) 읽고 

3) 처리한다 

 

바이트스트림 (데이터 값에 바이트가 왔다갔다함) 

InputStream/OutputStream 

 

문자스트림 

Reader/Writer

-> FileReader/FileWriter, BufferedReader/BufferedWriter 

 

 

1) 단계 : 파일을 엽니다 

FileReader reader = new FileReader("poem.txt"); // 생성자 안에서 현재 디렉토리의 poem.txt 파일을 연다

 

2) 파일을 읽습니다 .

data = reader.read();  // 이 메서드는 파일에 있는 문자 하나를 읽어서 리턴합니다.
while (true) {
	int data = reader.read();
    if (data < 0) {
    	break;
    }
    Char ch = (char) data;

 

3. 파일을 닫습니다

reader.close();

 

 

기본 flow 

 

package kosta.basic.day018.io;

import java.io.FileReader;

public class FileReaderExam {
    public static void main(String[] args) {
        // 파일에 있는 문자 데이터를 읽어보자

        FileReader fileReader = null;

        try {
            fileReader = new FileReader("poem.txt");

            while (true) {
                int alphabetAscii = fileReader.read();
                if (alphabetAscii == -1) {
                    break;
                }
                System.out.println((char) alphabetAscii);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                fileReader.close();
            } catch (Exception e2) {

            }
        }

    }
}

 

 

 

파일을 복사하는 코드를 작성해보자 ! 

package kosta.basic.day018.io;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

public class CopyExam {

    public static void main(String[] args) throws IOException {
        // Todo : poem2.txt -> 카피 -> poem3.txt로 복사해보자

        String fileOriginal = "poem2.txt";
        String fileNew = "poem3.txt";

        copyFile(fileOriginal, fileNew);
    }

    private static void copyFile(String fileOriginal, String fileNew) throws IOException {
        FileReader fileReader = new FileReader(fileOriginal);
        FileWriter fileWriter = new FileWriter(fileNew);

        String textTotal = fetchContent(fileReader, getTextLength(fileOriginal));
        writeContent(fileWriter, textTotal);
        checkResult(fileNew);
    }

    private static String fetchContent(FileReader fileReader, int textLength) throws IOException {
        char[] copyBlock = new char[textLength + 2];
        fileReader.read(copyBlock);
        fileReader.close();
        return String.valueOf(copyBlock);
    }

    private static void writeContent(FileWriter fileWriter, String textTotal) throws IOException {
        fileWriter.write(textTotal);
        fileWriter.close();
    }

    private static void checkResult(String fileNew) throws IOException {
        char[] resultBlock = new char[getTextLength(fileNew) + 2];
        FileReader copyChecker = new FileReader(fileNew);
        copyChecker.read(resultBlock);
        System.out.printf("이런 텍스트가 카피되었네요! ⇣⇣⇣\n\n");
        System.out.println(resultBlock);
        copyChecker.close();
    }

    private static int getTextLength(String fileOriginal) throws IOException {
        return Files.lines(Paths.get(fileOriginal)).mapToInt(String::length).sum();
    }
}

 

 


 

 

기존 스트림 : 노드 스트림 

연결하는 스트림 : 필터 스트림 (보조 스트림) 

 

scanner를 사용하지 않고 스트림으로 입력을 받아보자 ! 

 

System.in => inputStream이다. 

 

호출될시 스트림이 연결된다. 

 

inputStream은 바이트스트림 

=> 문자를 쓰고 싶기 때문에 

=> 문자를 일고 쓸 수 있도록하는 스트림이 필요하다 => 추가 연결 

=> InputStreamReader => 필터 스트림이므로 노드 스트림 즉 inputStream이 와야 한다. 

=> BufferedReader 

=> BufferedReader는 reader를 받는다. 

 

따라서 정석적인 플로우 

InputStream in = System.in;
InputStreamReader inputStreamReader = new InputStreamReader(in);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

 


BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("outputExample.txt"));

 

다음 4개의 코드 중 어떤 코드가 좋은 코드일까 ?

 

// 1번째
String text = "";
while ((text = bufferedReader.readLine()) != null) {
    text += "\n";
    bufferedWriter.write(text);
    bufferedWriter.flush();
}

// 2번째
String text2 = bufferedReader.readLine();
while (text2 != null) {
    text2 += "\n";
    bufferedWriter.write(text2);
    text2 = bufferedReader.readLine();
    bufferedWriter.flush();
}

// 3번째
StringBuilder text3 = new StringBuilder(bufferedReader.readLine());
while (text3 != null) {
    text3.append("\n");
    bufferedWriter.write(text3.toString());
    text3 = new StringBuilder(bufferedReader.readLine());
    bufferedWriter.flush();
}

// 4번째
StringBuilder text4 = Optional.ofNullable(bufferedReader.readLine()).map(StringBuilder::new).orElse(null);
while (text4 != null) {
    text4.append("\n");
    bufferedWriter.write(text4.toString());
    text4 = Optional.ofNullable(bufferedReader.readLine()).map(StringBuilder::new).orElse(null);
    bufferedWriter.flush();
}

 

 

자바에서 EOF를 처리하는 가장 보편적인 방식은 1번일 것이다. 

// 1번째 
String text = "";
while ((text = bufferedReader.readLine()) != null) {
    text += "\n";
    bufferedWriter.write(text);
    bufferedWriter.flush();
}

 

그런데 이 코드를 딱 보았을 때 잘 읽히지 않았다. 

 

while문의 괄호안은 boolean 값을 판단하는 기능을 수행한다. 그런데 선언과 동시에 boolean 값을 판단하고 있어 좁은 공간에서 두 가지 기능을 동시에 하고 있다. 

 

while 문안의 코드는 가장 짧지만 이와 같은 문제점 때문에 지양하고 싶은 코드가 아닐까 한다. 


객체를 저장하기 

 

 

객체의 직렬화 (serialization) = 객체를 바깥으로 쓰게 하는 것 

반대로 바깥에서 읽어오는 것을 역직렬화 Deserialization 

 

직렬화란 JVM에 존재하는 힙, 스택의 값, 객체 데이터를 바이트 형태로 변환하는 기술이다. 

 

자바는 Serializable을 구현한 클래스만 직렬화할 수 있도록 제한한다. 

 

즉, 상위 클래스가 Serializable을 구현했다고 하더라도 하위 멤버 필드 다른 객체도 Serializable을 구현해야 직렬화가 가능하다. 

 

 

직렬화 구현 

 

package kosta.basic.day018.io;

import java.io.*;

public class MemberSerialRunner {

    private static Member member;

    // 객체 직렬화
    public static void write() throws IOException {
        member = new Member("홍길동", 39);
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("objectTest1.ser"));
        objectOutputStream.writeObject(member);
    }

    // 객체 역직렬화
    public static void read() throws IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("objectTest1.ser"));
        Member member1 = (Member) objectInputStream.readObject();
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        write();
        member = null;
        read();
    }
}

 

serializable을 구현하지 않은 것을 write 하려고 하면 exception이 발생한다. 

 

 

반응형