[ 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