본문 바로가기

(09.04) java 기초 - 바이트 스트림, 표준 입출력 스트림, IO 와 컬렉션 사용, 데이터 스트림

@starweb2025. 9. 4. 20:22

[ 4주차 - 0904 ] 

    금일 커리큘럼
        ├ 09:00 ~ 12:00 자바 프로그래밍 기초 (바이트 스트림(복습), 표준 입출력 스트림, File)
        └ 13:00 ~ 18:00 자바 프로그래밍 기초 (파일 I/O와 컬렉션(List) 연동 실습, 데이터 스트림)

1. 바이트 스트림 (복습)

(*복습) 모든 데이터(이미지, 영상 등) 가능

바이트 스트림

  • FileInputStream : 파일에서 바이트 단위로 읽기
  • FileOutputStream : 파일에 바이트 단위로 쓰기

읽기/쓰기

  • read() : 한 바이트 읽기 (없으면 -1 반환)
  • read(byte[]) : 여러 바이트를 한 번에 읽기, 실제 읽은 바이트 수 반환
  • write() : 읽은 바이트 데이터를 파일에 기록

 

read 예시 (하나씩 진행)

package week_04._0904;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class ReadFile {
    public static void main(String[] args) throws Exception {
        String fileSrc = "src/etc/io_test/";
        // HelloWorld!!!!

        FileInputStream fisTest = new FileInputStream((fileSrc + "0904.txt"));
        System.out.println(fisTest.read()); //  72 → H
        System.out.println((char)fisTest.read()); // e
        // read() : 읽을때마다 다음 것 진행

        fisTest.close();
    }
}
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class ReadFile {
    public static void main(String[] args) throws Exception {
        String fileSrc = "src/etc/io_test/";
        // HelloWorld!!!!

        FileInputStream fisTest = new FileInputStream((fileSrc + "0904.txt"));
        System.out.println(fisTest.read()); //  72 → H
        System.out.println((char)fisTest.read()); // e
        // read() : 읽을때마다 다음 것 진행

        fisTest.close();
    }
}

 

1바이트 방식

try-catch-finally 방식일 경우 (finally 내 close처리 필수)

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class ReadFile {
    public static void main(String[] args) throws Exception {
        String fileSrc = "src/etc/io_test/";
        // HelloWorld!!!!

        // 1바이트 -------------------------------------------------------
        // try-catch-finally 기본 방식
        FileInputStream fis = null;
        FileOutputStream fos = null;

        try {
            fis = new FileInputStream((fileSrc + "0904.txt"));
            fos = new FileOutputStream(fileSrc + "0904_output.md");
            int ch;
            int cnt = 0;
            // 1바이트씩 / -1 인 경우 파일의 끝
            while ((ch = fis.read()) != -1) {
                fos.write(ch); // 실제 쓰는 일은 OS가 함
                cnt++;
            }
            System.out.println("1byte 진행: " + cnt);
            // 1byte 진행: 14
        } catch (IOException e) {
            System.out.println("오류: " + e.getMessage());
        } finally {
            try {
                if (fis != null) fis.close();
                if (fos != null) fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

 

바이트 배열 방식

try-with-resources 방식일 경우 (자원 자동 close)

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class ReadFile {
    public static void main(String[] args) throws Exception {
        String fileSrc = "src/etc/io_test/";
        // HelloWorld!!!!

        // 바이트 묶음 -------------------------------------------------------
        // try-with-resources 방식
        try (
            FileInputStream fis1 = new FileInputStream((fileSrc + "0904.txt"));
            FileOutputStream fos1 = new FileOutputStream(fileSrc + "0904_output.md");
        ) {
            int ch1;
            int cnt1 = 0;
            byte[] bytes = new byte[1024]; // 1KB

            // read(bytes[]) : 최대 bytes.length 만큼 읽고, 실제 읽힌 바이트 수를 반환
            while ((ch1 = fis1.read(bytes)) != -1) {
                // String str = new String(bytes, 0, ch1);
                // System.out.println(str);
                fos1.write(ch1);
                cnt1++;
            }
            System.out.println("byte[1024] 진행: " + cnt1);
            // byte[1024] 진행: 1

            // resources 방식으로 트라이블럭 끝나면 자동적으로 close()됨
        } catch (IOException e) {
            System.out.println("오류: " + e.getMessage());
        }
    }
}

 

2. 표준 입출력 스트림

자바는 콘솔 기반 입출력을 위해 세 가지 표준 스트림을 제공

  • System.in : 키보드로부터 입력 받기 (바이트 스트림 → 문자 변환 필요)
    • read() 하면 한글자씩만 읽히므로 BufferedReader 과 InputStreamReader 사용 권장
    • 예 : BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
  • System.out : 콘솔에 일반 메시지 출력
  • System.err : 콘솔에 오류 메시지 출력 (System.out 과 별개 스트림)
import java.io.BufferedReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;

public class SystemIOExam {
    public static void main(String[] args) {
        String fileSrc = "src/etc/io_test/";
        try (
                // System.in을 BufferedReader로 감싸기
                BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        ) {
            // System.out으로 프롬프트 출력
            System.out.print("이름을 입력하세요: ");
            String name = br.readLine();

            System.out.print("나이를 입력하세요: ");
            int age = Integer.parseInt(br.readLine());

            // 오류 출력
            if (age < 0) {
                System.err.println("오류: 나이는 음수일 수 없습니다. 입력값: " + age);
            } else {
                // 정상 출력
                String printStr1 = "안녕하세요, " + name + "님!";
                String printStr2 = "당신은 " + age + "살입니다.";

                // 해당값 쓰기
                try(
                    FileWriter fw = new FileWriter((fileSrc + "info_test.txt"));
                    // PrintWriter pw = new PrintWriter(fw);
                ) {
                    System.out.println(printStr1 + "\n" + printStr2);
                    fw.write(printStr1 + "\n" + printStr2);
                    // or
                    // pw.println(printStr1);
                    // pw.println(printStr2);
                }
            }
        } catch (IOException e) {
            System.err.println("입력 오류: " + e.getMessage());
        } catch (NumberFormatException e) {
            System.err.println("숫자 형식 오류: " + e.getMessage());
        }
    }
}
  • readLine() : 한줄단위 입력 가능

 

3. 파일 입출력 File

파일 입출력은 데이터의 영속성을 보장하는 핵심 기능

File 주요 기능

  • 파일/디렉토리 생성, 삭제, 존재 여부 확인
    • 자바에서는 디렉토리도 파일(File 객체)로 취급됨
  • 파일 이름, 경로, 속성 정보(읽기/쓰기 가능 여부, 길이 등) 제공
  • 실제 데이터 읽기/쓰기 역할은 하지 않음 → FileInputStream, FileOutputStream 같은 스트림 클래스와 함께 사용

파일 정보 관련 메서드

메서드 설명 예시 출력
exists() 존재 여부 true / false
length() 크기(byte). 디렉토리면 0 반환 1024
canRead() 읽기 권한 여부 true / false
canWrite() 쓰기 권한 여부 true / false
getAbsolutePath() 절대 경로 D:\dev\pj\test.md
getCanonicalPath() 정규화된 절대 경로
./.. 제거
D:\dev\pj\test.md
getName() 파일 이름(확장자 포함) test.md
getParent() 부모 디렉토리 경로 dev\pj
getPath() File 객체 생성 시 사용한 경로 그대로 반환 dev\pj\test.md
import java.io.File;
import java.io.IOException;

public class Fileinfo {
    public static void main(String[] args) {
        String fileSrc = "src/etc/io_test/";

        File file = new File(fileSrc,"test.md");
        // 파일 존재여부
        if(file.exists()) {
            System.out.println("length : " + file.length());
            System.out.println("canRead : " + file.canRead());
            System.out.println("canWrite : " + file.canWrite());
            System.out.println("getAbsolutePath : " + file.getAbsolutePath());
            try {
                System.out.println("getCanonicalPath : " + file.getCanonicalPath());
            } catch(IOException e) {
                System.out.println(e);
            }
            System.out.println("getName : " + file.getName());
            System.out.println("getParent : " + file.getParent());
            System.out.println("getPath : " + file.getPath());
        }
    }
}
# 실행 결과
length : 5501
canRead : true
canWrite : true
getAbsolutePath : D:\dev\backend\backend\src\etc\io_test\test.md
getCanonicalPath : D:\dev\backend\backend\src\etc\io_test\test.md
getName : test.md
getParent : src\etc\io_test
getPath : src\etc\io_test\test.md

 

폴더 및 파일 추가 & 삭제

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

public class FileDel {
    public static void main(String[] args) {
        String fileSrc = "src/etc/del/";

        File dir = new File(fileSrc);
        File file = new File(fileSrc,"deltest.md");

        // 폴더 및 파일 생성
        try {
            if(dir.mkdirs() && file.createNewFile()) {
                System.out.println("폴더 및 파일 생성 시도 완료");
                System.out.println("파일 경로: " + file.getPath());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        long start = System.currentTimeMillis();
        try {
            Thread.sleep(3000); // 3초 동안 프로그램 멈춤
        } catch (InterruptedException e) {
            System.out.println(e);
        }
        long end = System.currentTimeMillis();

        System.out.println("슬립 걸린 시간(ms): " + (end - start));

        if(file.exists()) {
            if(file.delete()) System.out.println("파일 삭제 성공: " + file.getPath());
            else System.out.println("파일 삭제 실패");
        }
        if(dir.exists()) {
            if (dir.delete()) System.out.println("폴더 삭제 성공: " + dir.getPath());
            else System.out.println("폴더 삭제 실패");
        }
    }
}
# 실행 결과
폴더 및 파일 생성 시도 완료
파일 경로: src\etc\del\deltest.md
슬립 걸린 시간(ms): 3010
파일 삭제 성공: src\etc\del\deltest.md
폴더 삭제 성공: src\etc\del

 

파일 I/O와 컬렉션(List) 연동 실습

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;


public class FileExam2 {

    /** 입력 후 파일 및 List<UserInfo> 저장 */
    public static void infoInput(String path, List<UserInfo> lists, int cnt) {
        String name, tel, addr;
        try (
                BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
                PrintWriter writer = new PrintWriter(new FileWriter(path, true));
        ) {

            for (int i = 0; i < cnt; i++) {
                System.out.printf("[ 입력 | %d번쨰 중 %d번째 ]%n", cnt, (i + 1));

                System.out.print("이름: ");
                name = reader.readLine();

                System.out.print("전화번호: ");
                tel = reader.readLine();

                System.out.print("주소: ");
                addr = reader.readLine();

                writer.println(name + "," + tel + "," + addr);

                lists.add(new UserInfo(name, tel, addr));
            }

        } catch (IOException e) {
            System.err.println(e.getMessage());
        }
    }

    /** 읽기 */
    public static void infoOutput(String path) {
        try (
            BufferedReader reader = new BufferedReader(new FileReader(path))
        ) {
            System.out.println("─".repeat(8) + "[ 파일 내용 ]" + "─".repeat(8));

            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }

        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
    }

    /** 파일정보 List<UserInfo> 에 삽입 */
    public static void joinList(String path, List<UserInfo> lists) {
        File file = new File(path);
        if (!file.exists()) return;
        try (
                BufferedReader read = new BufferedReader(new FileReader(file))
        ) {
            String line;
            while ((line = read.readLine()) != null) {
                // 이름 | 전화 | 주소
                String[] join = line.split(",", 3);
                System.out.println(Arrays.toString(join));
                if (join.length == 3) lists.add(new UserInfo(join[0], join[1], join[2]));
            }
        } catch (IOException e) {
            System.err.println(e.getMessage());
        }
    }


    public static void main(String[] args) {
        String path = "src/etc/file_exam/info.txt";
        Scanner sc = new Scanner(System.in);
        List<UserInfo> lists = new ArrayList<>();

        joinList(path, lists);
        System.out.println("수정전 배열정보:\n" + lists);
        System.out.println("─".repeat(20));

        int cnt;
        System.out.print("횟수입력: ");
        cnt = Integer.parseInt(sc.nextLine());

        System.out.println("─".repeat(20));
        infoInput(path, lists, cnt);
        infoOutput(path);

        System.out.println("─".repeat(20));
        System.out.println("수정 후 배열정보:\n" + lists);
    }
}
# 실행 결과
[라이언0, 010-0000-0000, 서울]
수정전 배열정보:
[UserInfo{name='라이언0', tel='010-0000-0000', addr='서울'}]
────────────────────
횟수입력: 2
────────────────────
[ 입력 | 2번쨰 중 1번째 ]
이름: 라이언1
전화번호: 010-0000-0000
주소: 경기
[ 입력 | 2번쨰 중 2번째 ]
이름: 라이언2
전화번호: 010-0000-0000
주소: 부산
────────[ 파일 내용 ]────────
라이언0,010-0000-0000,서울
라이언1,010-0000-0000,경기
라이언2,010-0000-0000,부산
────────────────────
수정 후 배열정보:
[UserInfo{name='라이언0', tel='010-0000-0000', addr='서울'}, 
UserInfo{name='라이언1', tel='010-0000-0000', addr='경기'}, 
UserInfo{name='라이언2', tel='010-0000-0000', addr='부산'}]

4. 데이터 스트림

자바의 기본 데이터 타입 입출력

  • 텍스트가 아닌 바이너리 포맷으로 저장 → 공간 절약 + 정확한 복원
  • 텍스트 에디터로 열면 “깨져 보이는 것”이 정상
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class DataExam {
    public static void main(String[] args) {
        String path = "src/etc/io_test/data.txt";
        try(
                DataOutputStream dos = new DataOutputStream(new FileOutputStream(path));
        ) {
            dos.writeBoolean(true);
            dos.writeChar('a');
            dos.writeInt(10);
            dos.writeDouble(3.14);
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }

        try (
                DataInputStream dis = new DataInputStream(new FileInputStream(path));
        ) {
            System.out.println(dis.readBoolean());
            System.out.println(dis.readChar());
            System.out.println(dis.readInt());
            System.out.println(dis.readDouble());
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
    }
}
# 실행 결과
true
a
10
3.14
starweb
@starweb :: starweb 님의 블로그

starweb 님의 블로그 입니다.

공감하셨다면 구독도 환영합니다!

목차