18.데이터 입출력

프로그램 기준으로 입출력하는 방법을 배우고 잇엇다.

18.6 BufferdOutputStream

18.6.2 BufferdWriter

BufferdWriter의 생상자는 Writer를 파라미터로 받는다.
주요메소드는 write이다. 기본 Writer보다 빠르다.

writer에는 없는 newLine이라는 메소드도 있다.
새로운 줄을 만들어준다.

public class C05BufferedWriter {
    public static void main(String[] args) {
        String name = "output/bufferd5.txt";
        try (FileWriter fw = new FileWriter(name);
                BufferedWriter bw = new BufferedWriter(fw)) {

            for (int i = 0; i < 10; i++) {
                bw.write("hello world");
                bw.newLine();
            }

            bw.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

18.6.3 BufferdReader

BufferedReader의 주요 메소드느 read가 있고
한줄씩 읽어오는 readLine()이라는 특화된 메소드가 있다.
한줄씩읽어오고 읽어올 문자가 없다면 null을 리턴한다.

public class C06BufferedReader {
    public static void main(String[] args) {
        String name = "output/bufferd5.txt";
        try (FileReader fr = new FileReader(name);
                BufferedReader br = new BufferedReader(fr)) {

            while (true){
                String s = br.readLine();
                if(s == null) {
                    break;
                }
                System.out.println(s);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

18.6.4 확이문제 7번

소스파일에 라인번호를 추가시켜 출력하기

public class Example {
    public static void main(String[] args) throws Exception {
        String filePath = "src/ch18/exercise/exam07/Example.java";

        FileReader fr = new FileReader(filePath);
        BufferedReader br = new BufferedReader(fr);

        int rowNumber = 1;
        String rowData;
        while (true) {
            rowData = br.readLine();
            if (rowData == null) {
                break;
            }
            System.out.println(rowNumber + ": " +rowData);
            rowNumber++;
        }
        br.close();
        fr.close();
    }
}

18.7 PrintWriter()

PrintWriter() 문자단위로 출력하는 스트림이다.
프린터기 처럼 출력을 한다.
pirntln() prinf()등의 메소드를 가지고 있다.
생성자는 파일, 아웃풋스트림등을 받는다.

public class C01PrintWriter {
    public static void main(String[] args) {
        String name = "output/print1.txt";

        try (PrintWriter pw = new PrintWriter(name)) {

            pw.println(33333);
            pw.println(3.14);
            pw.println(true);
            pw.println("hello world");
            pw.println("슬램덩크");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

18.7.1 PrintStream()

바이트 단위출력이지만 문자출력을 위해 잘 사용된다.
문자단위출력이 아님에도 불구하고 문자를 출력할 수 있다.

public class C02PrintStream {
    public static void main(String[] args) {
        String name = "output/print2.txt";

        try (PrintStream ps = new PrintStream(name)) {

            ps.println(99999);
            ps.println(9.99999999);
            ps.println(false);
            ps.println("hello world");
            ps.println("더 글로리");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

PrintWriter()는 1.1버전부터 사용이 되었고
PrintStream은 1.0부터 시작이 되었다.

자바는 영어권에서 만들었다. 영어권에서는 문자출력을 1바이트로 다 가능햇다.
처음나올때는 print할때 문자단위 출력은 염두에 두지 않았었다.
그래서 초창기에 출력할때 PrintStream을 사용했다. 바이트 단위 출력스트림인 OutputStream의 하위클래스이다.
그런데 지나고보니 Writer를 상속받아 만드는게 좋다고 생각이 들어서 PrintWriter가 생겨났다.
둘다 비슷한 메소드를 가지고 있다.

System.out.println()코드를 잘 사용했다.
out은 PrintStream타입이다.

18.8 문자 변환 스트림
바이트단위를 문자단위로 바꿔야하는 경우가 있다.
다른사람이 바이트스트림으로 받는 메소드를 만들어서
내가 수정할 수 없는 경우에 사용할 수 있다.

영어권은 바이트단위여도 문자를 하나씩 보낼 수 있어서 상관이없다.
그런데 한글을 쓰려고 하면 write()는 2바이트만쓰고 2바이트느 버려서 문제가 생긴다.

이걸 해결하기 위해서 바이트단위 스트림을 문자단위 스트림으로 바꿔주는 클래스를 사용하면된다.

18.8.1 OutputStreamWriter()
OutputStreamWriter()는 OutputStream을 파라미터로 받는다.
우리가 OutputStream을 변경을 못한다하더라도 받아온 OutputStream을
OutputStreamWriter의 파라미터로 넣을 수 있다.

프로그램은 OutputStreamWriter한테 write하고 OutputStreamWriterd은 바이트스트림에 write하는 구조이다.
불편함을 해소 할 수 있다.

public class C01OutputStreamWriter {
    public static void main(String[] args) throws Exception {
        String fileName = "output/byte1.txt";
        OutputStream os = getOutput(fileName);
        OutputStreamWriter osw = new OutputStreamWriter(os);

        osw.write('a');
        osw.write('b');
        osw.write('한');

        osw.flush();
        osw.close();
    }

    public static OutputStream getOutput(String fileName) throws Exception {
        OutputStream os = new FileOutputStream(fileName);
        return os;
    }
}

18.8.2 OutputStreamReader()

반대로 읽어올때도 바이트스트림을 얻고 리더로 읽어올 수 있다.

public class C02InputStreamReader {
    public static void main(String[] args) throws Exception {
        String fileName = "output/byte1.txt";
        InputStream is = new FileInputStream(fileName);
        InputStreamReader isr = new InputStreamReader(is);

        int f1 = isr.read();
        System.out.println((char) f1);

        int f2 = isr.read();
        System.out.println((char) f2);

        int f3 = isr.read();
        System.out.println((char) f3);
    }
}

어찌어찌 얻어온게 바이트단위 스트림인데 문자로 입출력하고싶다면
InputStreamReader / InputStreamWriter로 문자열 변환을 해고 사용하자.
문자열 변환스트림은 문자열 저장방식도 정할 수 있다.

문자열 저장방식은 다양하다. 한바이트 이상으로 문자를 표현하기 위한 규칙이 굉장히많다.
그중 하나가 UTF-8이다.

특정 문자코드로 출력했으면 입력할때도 같은 문자열로 받아야한다.

public class CharacterConvertStreamExample {
    public static void main(String[] args) throws Exception {
        write("문자변환 스트림을 사용합니다.");
        String data = read();
        System.out.println(data);
    }

    public static void write(String str) throws Exception {
        OutputStream os = new FileOutputStream("output/test.txt");
        Writer writer = new OutputStreamWriter(os, "UTF-8");
        writer.write(str);
        writer.flush();
        writer.close();
    }

    public static String read() throws Exception {
        InputStream is = new FileInputStream("output/test.txt");
        Reader reader = new InputStreamReader(is, "UTF-8");

        char[] data = new char[100];
        int num = reader.read(data);
        String str = new String(data, 0, num);
        reader.close();

        return str;
    }
}

18.9 보조스트림

위에서 연결해서 작성하는 것이 다른 스트림을 받아서 만드는 거였다.
이것들을 보조 스트림이라고 한다.
어떤 스트림을 감싸서 만드는 것이다.
결론은 스트림끼리 연결할 수있다. 1개뿐만이아니라 여러개를 연결 할 수 있다.

같은 방향의 스트림끼리 연결이 가능하다.

public class C01Filter {
    public static void main(String[] args) {
        String fileName = "output/byte1.txt";

        try (InputStream fis = new FileInputStream(fileName);
                InputStreamReader isr = new InputStreamReader(fis);
                BufferedReader br = new BufferedReader(isr);) {

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

public class C02Filter {
    public static void main(String[] args) {
        String fileName = "output/byte1.txt";

        try (OutputStream fos = new FileOutputStream(fileName);
                BufferedOutputStream bos = new BufferedOutputStream(fos);
                OutputStreamWriter osw = new OutputStreamWriter(bos)) {

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

18.11 File / Files클래스

File정보를 저장하고 있는 객체를 만들어내는 클래스이다.
File 클래스는 (file 또는 directory)에 관한 객체이다.
java.io패키지에 있다.

생성자에는 파일경로를 파라미터로 넣으면된다.
경로를 넣으면 그 파일의 정보에 대해 알게 되기때문에
파일과 관련된 메소드를 사용할 수 있다.

getName() : file의 이름
length() : 파일의 길이
exist() : 파일이 존재하는지
isFile() : 파일인지?
isDirectory() : 디렉토리인지?
listFiles() : 디렉토리내 파일 목록 배열로 얻어오기

createNewFile() : 새로운 파일을 생성한다.
mkdir() : 메소드를 사용하면 새로운 디렉토리를 만들 수 있다.
mkdirs() : 경로상에 없는 모든 디렉토리를 생성한다.
mkdir()은 하나의 폴더만 만들고 mkdirs()상위폴더를 다 만들어준다.

이외에도 파일과 관련된 메소드들을 사용할 수 있다.

public class FileExample {
    public static void main(String[] args) throws Exception {
        // File객체 생성
        File dir = new File("C:/Temp/images");
        File file1 = new File("C:/Temp/file1.txt");
        File file2 = new File("C:/Temp/file2.txt");
        File file3 = new File("C:/Temp/file3.txt");

        // 존재하지 않으면 디렉토리 또는 파일 생성
        if (dir.exists() == false) {
            dir.mkdir();
        }
        if (file1.exists() == false) {
            file1.createNewFile();
        }
        if (file2.exists() == false) {
            file2.createNewFile();
        }
        if (file3.exists() == false) {
            file3.createNewFile();
        }

        // Temp 폴더의 내용을 출력
        File temp = new File("C:Temp");
        File[] contnets = temp.listFiles();

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd a HH:mm");
        for (File file : contnets) {
            System.out.printf("%-25s", sdf.format(new Date(file.lastModified())));
            if (file.isDirectory()) {
                System.out.printf("%-10s%-20s", "<DIR>", file.getName());
            } else {
                System.out.printf("%-10s%-20s", file.length(), file.getName());
            }
            System.out.println();
        }
    }
}

18.11.1 확인문제 10번

원본 파일 경로와 복사파일 경로를 입력받고
원본파일을 복사하는 프로그램 만들기

public class Exmaple {
    public static void main(String[] args) {

        // 파일명 입력받는 코드(option)
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        String origin = "";
        String target = "";
        try {
            System.out.print("원본 파일 경로: ");
            origin = br.readLine();
            System.out.print("복사 파일 경로: ");
            target = br.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }

        File originFile = new File(origin);

        if (originFile.exists() == false) {
            System.out.println("원본 파일이 존재하지 않습니다.");
            System.exit(0);
        }

        // 복사 파일 경로상에 없는 모든 디렉토리 생성
        File targetFile = new File(target);
        // 부모파일 얻어서 File객체 리턴
        File parentFile = targetFile.getParentFile();
        if (parentFile.exists() == false) {
            parentFile.mkdirs();
        }

        try (InputStream is = new FileInputStream(originFile);
                BufferedInputStream bis = new BufferedInputStream(is);
                OutputStream os = new FileOutputStream(targetFile);
                BufferedOutputStream bos = new BufferedOutputStream(os);) {

            byte[] data = new byte[1024];
            while (true) {
                int len = bis.read(data);
                if (len == -1) {
                    break;
                }
                bos.write(data, 0, len);
            }
            bos.flush();
            System.out.println("복사가 성공되었습니다.");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

14. 멀티스레드

Thread
프로그램이 실행되면 하나의 프로그램이 동시에 실행된다.
가사를 보면서 노래듣기 등등 하나의 프로그램에서 동시에 여러개 발생한다.

이동시에 진행되는 코드를 어떻게 작성하는가가 14장이다.
핵심적인 내용은 두개의 스레드가 공통으로 접근하면 주의해야한다.

기존의 코드는 동시에 일어나지 않고 흐름이 이어진다.
동시에 일어나게 하고 싶다면 스레드를 사용해야한다.

스레드를 만드려면 스레드 객체를 만들면된다.
Thread 시작 start() 메소드를 사용하면된다.
start()메소드를 실행하는 순간 실행된다.

Thread를 만드는 이유는 일을 시키기 위함이다.
Thread를 만드려면 Runnable인터페이스를 구현한 객체면된다.

Thread가 가지고 있는 Runnable의 run메소드를 적절한 상황에 실행시켜준다.
동시에 실행한다.

public class C03Thread {
    public static void main(String[] args) {
        Process03 p1 = new Process03();
        Thread t1 = new Thread(p1);

        t1.start();

        while (true) {
            System.out.println("@@@ main Thread @@@");
        }
    }
}

class Process03 implements Runnable {
    @Override
    public void run() {
        while (true) {
            System.out.println("### 스레드 실행중 ###");
        }
    }
}

14.1.1 Runnable객체 구현

Runnable이 추상메소드가하나인 인터페이스 이기때문에 람다식으로 구현할 수 있다.

public class C04Thread {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            while (true) {
                System.out.println("## 스레드 실행중 ##");
            }
        });

        t1.start();

        while (true) {
            System.out.println("@@@ main Thread @@@");
        }
    }
}

14.1.2 Thread 클래스 상속

Thread 만드는 두번째 방법은 Thread 클래스 상속받아서
run 메소드를 재정의하면된다.

public class C05Thread {
    public static void main(String[] args) {
        Thread t1 = new MyThread5();
        t1.start();

        while (true) {
            System.out.println("@@@ main Thread @@@");
        }

    }
}

class MyThread5 extends Thread {
    @Override
    public void run() {
        while (true) {
            System.out.println("### 스레드 작업중 ###");
        }
    }
}

Thread클래스가 Runnable인터페이스를 구현하고 있다.
그래서 바로 Thread의 생성자로 사용할 수 있다.
또한 익명자식객체를 직접 구현해서 스레드를 사용할 수도 있다.

14.1.3 확인문제 2번

각각 익명 자식객체와 람다식을 이용한 익명구현객체로 작성해보았다.

public class ThreadExample2 {
    public static void main(String[] args) {
        Thread thread1 = new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < 3; i++) {
                    System.out.println("음악을 재생합니다.");
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        thread1.start();

        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 3; i++) {
                System.out.println("동영상을 재생합니다.");
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        thread2.start();
    }
}

2023.03.23

다음주부터 JSP를 시작할예정이다.
JAVA 국비 수업에서의 끝이 보인다.
그런데 솔직히 사람들이 얼마나 따라왔을지도 궁금하고 아무도 탈주를 하지 않았다는 점이 놀랍다.
JSP에서 화면에 찍어내려면 DB가 필요한데 진도 중간에 DB로 바꿔서 나갈거같다는 예상이 든다.
혼자서 먼저 시작을 했지만 곧바로 시작이 되니 또 두렵다.
수업을 따라가는것은 아직까지는 어렵지 않지만 앞으로 어떻게 해야할지 정말 두렵다.
매일매일 두렵기만하고 새로 시작하는 것이 두렵다. 너무무섭다.
이런 수준이기에 어려운 길이라는 것을 알고 시작했지만 더 어렵다. 혼자서 잘해내고 싶지만 길을 잃는 것 같다.
너무 두렵다. 힘내고 싶다. 방황하는 지금 이순간을 이겨내면 더 밝은 미래가 있기를 바란다.

'국비 > Java' 카테고리의 다른 글

2023.03.24 41일차 Java  (0) 2023.03.24
2023.03.22 39일차 Java  (0) 2023.03.22
2023.03.21 38일차 Java  (0) 2023.03.21
2023.03.20 37일차 Java  (0) 2023.03.20
2023.03.17 36일차 Java  (0) 2023.03.19

+ Recent posts