Input(입력 : 외부에서 내부로 값이 들어오는 것)과 Output(출력 : 내부에서 외부로 값이 나가는 것)의 약자, 컴퓨터 내부 또는 외부 장치와 프로그램 간의 데이터를 주고 받는 것
장치와 입출력을 위해서는 하드웨어 장치에 직접 접근이 필요한데 다양한 매체에 존재하는 데이터들을 사용하기 위해 입출력 데이터를 처리할 공통적인 방법으로 스트림(시냇물) 이용 (일방통행)
Scanner 로 input
print 구문 이용 console 출력 output

파일 시스템의 파일을 표현하는 클래스
파일 크기, 파일 속성, 파일 이름 등의 정보와 파일 생성 및 삭제 기능 제공
java.io 패키지
파일/디렉토리(폴더)를 관리하는 클래스
(파일/디렉토리 존재 유무 관계 없음)
파일 생성, 제거, 이름, 크기, 마지막 수정일, 존재여부 등의 기능 제공
File file = new File("파일 경로");
File file = new File("C:/dev/test.txt");
* + 폴더가 존재하지 않으면 폴더 생성
*/
public void method1() {
// 제일 앞 "/" : 최상위 폴더 (== root, 절대 경로의 기준점 C드라이브)
// C:/io_test/20240222 폴더를 지정
File directory = new File("/io_test/20240222");
// -> 처음 : 존재하지 않는 폴더를 관리하는 File 객체 생성
System.out.println("존재 여부 확인 : " + directory.exists());
// 존재 여부 확인 : false
if(!directory.exists()) { // 폴더가 존재하지 않으면
// 폴더 모두 생성 (폴더 2개 생성해야해서 s 붙은 거 씀)
directory.mkdirs();
// 폴더 이름
System.out.println(directory.getName());
// 20240222
// 전체 경로 반환
System.out.println(directory.getPath());
// \io_test\20240222
}
}
File 객체를 이용해서 지정된 위치에 파일 생성하기
public void method2() {
// 백슬래쉬 한개는 이스케이프 문자
// \\ 문자열에서 "\" 표기하는 방법 : "\\"
// 확장자까지 써줘야함
File file = new File("\\io_test\\20240222\\파일생성.txt");
try {
if(!file.exists()) { // 파일이 존재하지 않으면
if(file.createNewFile()) { // 파일 생성이 성공한 경우
// createNewFile 이 boolean 값 반환
System.out.println(file.getName() + " 파일이 생성 되었습니다.");
// 파일생성.txt 파일이 생성 되었습니다.
}
}
} catch (IOException e) {
e.printStackTrace(); // 예외 정보 + 예외가 발생한 위치까지의 메서드 추적
}
}
File 클래스 제공 메서드 활용하기
public void method3() {
// File 객체 생성
File directory = new File("\\workspace\\02_Java\\12_io");
// 지정된 디렉토리에 있는 모든 파일/디렉토리를 File[] 형태로 얻어오기
File[] files = directory.listFiles();
// 향상된 for 문 -> for( 요소 저장 변수 : 배열|컬렉션) {}
for(File f : files) {
// String File.toString() : 지정된 파일/디렉토리의 절대경로
// System.out.println( f.toString() );
// \workspace\02_Java\12_io\.classpath
// \workspace\02_Java\12_io\.gitignore
// \workspace\02_Java\12_io\.project
// \workspace\02_Java\12_io\.settings
// \workspace\02_Java\12_io\bin
// \workspace\02_Java\12_io\src
// 파일명
String fileName = f.getName();
// 마지막으로 수정한 날짜
long lastModified = f.lastModified();
// System.out.println(lastModified);
// 1708571652475
// 1708571652611
// 1708571652461
// 1708571652469
// 1708571684955
// 1708571684828
// java.text.SimpleDateFormat : 간단히 날짜 형식을 지정할 수 있는 객체
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd a h:mm");
// 2024-02-22 오후 2:14
// String SimpleDateFormat.format(long) :
// 매개변수 long 값을 지정된 패턴 형식으로 변화하여
// 문자열 형태로 반환
String date = sdf.format(lastModified);
// System.out.println(date);
// 2024-02-22 오후 12:14
// 2024-02-22 오후 12:14
// 2024-02-22 오후 12:14
// 2024-02-22 오후 12:14
// 2024-02-22 오후 12:14
// 2024-02-22 오후 12:14
// 파일 유형 (파일이냐 폴더냐)
String type= null;
if(f.isFile()) type = "파일";
else type = "폴더"; // isDirectory
// 파일 크기(byte)
String size = f.length() + "B";
if(f.isDirectory()) { // 폴더라면 파일 크기 안 나옴
size = "";
}
String result
= String.format("%-20s %-20s %-5s %10s",
fileName, date, type, size);
System.out.println(result);
// .classpath 2024-02-22 오후 12:14 파일 396B
// .gitignore 2024-02-22 오후 12:14 파일 6B
// .project 2024-02-22 오후 12:14 파일 381B
// .settings 2024-02-22 오후 12:14 폴더
// bin 2024-02-22 오후 12:14 폴더
// src 2024-02-22 오후 12:14 폴더
}
}

File 클래스 메서드
boolean mkdir() : 디렉토리 생성
boolean mkdirs() : 경로상의 모든 디렉토리 생성
boolean createNewFile() : 파일 생성
boolean delete() : 파일/디렉토리 삭제
String getName() : 파일 이름 반환
String parent() : 파일이 저장된 디렉토리 반환
String getPath() : 전체 경로 반환
boolean isFile() : 현재 File 객체가 관리하는게 파일이면 true
boolean isDirectory() : 현재 File 객체가 관리하는게 디렉토리 true
boolean exists() : 파일/디렉토리가 존재하면 true, 아님 false
long length() : 파일 크기 반환
long lastModified() : 파일 마지막 수정일 (1970.01.01 09:00 부터 현재까지 지난 시간을 ms 단위로 반환)
String[] list() : 디렉토리 내 파일 목록을 String[] 배열로 반환
File[] listFiles() : 디렉토리 내 파일 목록을 File[] 배열로 반환
OS : 운영 체제
(Windows) / (Linux, Mac)
폴더 / 디렉토리
- 경로 표기 방법(하위 폴더, 파일 표시)
백슬래시(\, Windows) -> C:\workspace\02_Java
슬래시 (/, Linux, Mac) -> Users:/workspace/02_Java
- Java 언어의 특징 : 플랫폼(OS)에 독립적
-> OS 관계 없이 똑같은 코드 작성이 가능
-> 이 특징을 유지하기 위해 /, \ 둘 다 호환 가능
(런타임 시 실행되는 OS에 맞게 자동으로 변경)
---------------------------------------------------
- 경로 표기 방법
1) 절대 경로 : 하나의 (절대적인) 기준으로 부터
목표까지의 경로를 모두 표기하는 방법
C:\workspace\02_Java
- 기준
[Windows] : C:/ , D:/
[Linux, Mac] : /Users , /
2) 상대 경로 : 현재 위치를 기준으로 목표까지의 경로를 표기하는 방법
<script src = "../js/01_js">


입출력 장치에서 데이터를 읽고 쓰기 위해서 자바에서 제공하는 클래스
모든 스트림은 단방향이며 각각의 장치마다 연결할 수 있는 스트림 존재
하나의 스트림으로 입출력을 동시에 수행할 수 없으므로 동시에 수행하려면 2개의 스트림 필요
스트림(Stream) : 데이터가 이동하는 통로
기본적으로 한 방향으로 흐름
Byte 기반 스트림
1byte 단위로 데이터를 입/출력하는 스트림
최상위 인터페이스 : InputStream, OutputStream
문자열, 이미지, 영상, 오디오, pdf 등
모든 것을 입/출력 할 수 있음
(단, 통로가 좁다보니 속도가 조금 느림)
-> 거의 모든 메서드가 throws IOException
-> IOException 예외 처리 구문을 작성하는 것이 필수


바이트 기반 파일 출력
public void fileByteOutput() {
// FileOutputStream 참조 변수 선언
FileOutputStream fos = null;
try {
// new FileOutputStream("경로") :
// -> 경로에 작성된 파일과 연결된 파일 출력 스트림 객체 생성
// -> 출력 스트림에 연결된 파일이 존재하지 않으면 자동 생성
// (단, 폴더는 생성되지 않음)
// -> 기존 파일이 존재하면 내용을 덮어쓰기함
// new FileOutputStream("경로", true)
// -> 기존 파일이 존재하면 내용을 이어쓰기함
fos = new FileOutputStream("/io_test/20240222/바이트기반_테스트.txt");
// String 불변성 문제를 해결한 객체(가변성)
StringBuilder sb = new StringBuilder();
sb.append("Hello World!!\n");
sb.append("1234567890\n");
sb.append("~!@#$%^&*()_+\n");
sb.append("가나다라마바사아\n");
sb.append("와 자바 너무 재밌다\n");
sb.append("선생님 저 공부 열심히 할게요");
sb.append("진짜로");
sb.append("정말로");
sb.append("화이팅");
// StringBuilder -> String 변환
String content = sb.toString();
// 출력 방법 1 : 한 글자(2byte) 씩 파일로 출력
// -> 2byte 범주의 문자(영어, 숫자, 기본 특수문자 제외)는
// 1byte 기반 스트림 통과 시
// 데이터 손실이 발생해서 글자가 깨지는 문제가 발생
// for(int i = 0 ; i < content.length() ; i++) {
// char ch = content.charAt(i); // i 번째 글자 반환
// fos.write(ch); // 1byte 출력 스트림이 연결된 파일에 ch 쓰기
// }
// System.nanoTime() : 1970.01.01 09:00:00 부터
// 현재 시간까지의 차이를 ns(nano second 단위)로 반환
// 1ms(밀리) == 1/1000초
// 1us(마이크로) == 1/1000ms
// 1ns(나노) == 1/1000us (1/10억 초)
long startTime = System.nanoTime();
// 출력 방법 2 : String 을 byte[] 변환 후 출력
fos.write(content.getBytes());
long endTime = System.nanoTime();
System.out.println("[수행 시간] : " + (endTime - startTime) + "ns");
// [수행 시간] : 59600ns
fos.flush(); // 스트림 안에 남아있는 모든 데이터를 모두 밀어냄
System.out.println("출력 완료");
} catch(IOException e) {
e.printStackTrace(); // 예외가 발생한 메서드까지 추적해 출력
} finally { // try 예외 발생 여부 관계 없이 무조건 수행
// 사용 완료한 스트림을 제거(닫기, 메모리 반환)하는 코드 작성
try {
// 스트림이 정상 생성된 경우
if(fos != null) fos.close();
} catch(IOException e) {
e.printStackTrace();
}
}
}
버퍼를 이용한 파일 출력
BufferedOutputStream 보조 스트림 이용
버퍼(Buffer)란?
데이터를 모아두는 박스, 장바구니 같은 메모리 공간
버퍼링
인터넷 속도 낮음 + 스트리밍 코드가 효율이 안 좋음
-> 동영상 재생 중에 미리
앞에 재생될 부분을 다운 받아놔서
영상을 끊김없이 볼 수 있게 함
-> 다운 받아서 저장해놓는 공간 == 버퍼
BufferedOutputStream / BufferedInputStream
FileOutputStream 은 1바이트씩 데이터를 입출력
-> 버퍼에 입출력할 내용을 모아서 한 번에 입출력
--> 스트림을 이용하는 횟수가 적어짐
-> 성능, 시간 효율 up
public void bufferedFileByteOutput() {
FileOutputStream fos = null;
BufferedOutputStream bos = null; // 보조 스트림 선언
try {
fos = new FileOutputStream("/io_test/20240222/바이트기반_테스트_Buffered.txt");
// 기반 스트림 fos 를 이용해
// 보조 스트림 bos 를 생성
bos = new BufferedOutputStream(fos);
StringBuilder sb = new StringBuilder();
sb.append("Hello World!!\n");
sb.append("1234567890\n");
sb.append("~!@#$%^&*()_+\n");
sb.append("가나다라마바사아\n");
sb.append("와 자바 너무 재밌다\n");
sb.append("선생님 저 공부 열심히 할게요");
sb.append("진짜로");
sb.append("정말로");
sb.append("화이팅");
String content = sb.toString();
long startTime = System.nanoTime();
bos.write(content.getBytes());
long endTime = System.nanoTime();
System.out.println("[수행 시간] : " + (endTime - startTime) + "ns");
// [수행 시간] : 25300ns
bos.flush(); // 스트림에 남아있는 데이터 밀어내기(쏟아내기)
System.out.println("출력 완료");
} catch(IOException e) {
e.printStackTrace();
} finally {
try {
if(bos != null) bos.close();
// 보조스트림 close()시
// 보조스트림 생성에 사용된 기반 스트림 같이 close() 됨
} catch(IOException e) {
e.printStackTrace();
}
}
}