일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
Tags
- 분류
- ChatGPT
- supervised learning
- LG
- LG Aimers 4th
- LLM
- 오블완
- GPT-4
- Classification
- PCA
- LG Aimers
- 티스토리챌린지
- Machine Learning
- 지도학습
- deep learning
- 딥러닝
- OpenAI
- regression
- 머신러닝
- 회귀
- gpt
- 해커톤
- AI
Archives
- Today
- Total
SYDev
[이것이 자바다] Chapter 18. 데이터 입출력 본문
1. 입출력 스트림
- 데이터 입출력: 데이터는 키보드를 통해 입력될 수도 있고, 파일 또는 프로그램으로부터 입력되거나, 모니터로 출력될 수 있고, 파일에 저장되거나 다른 프로그램으로 전송될 수 있음
- Java는 입력 스트림과 출력 스트림을 통해 데이터를 입출력함
- Stream: 단방향으로 데이터가 흐르는 것을 의미
- 어떤 데이터를 입출력하느냐에 따라 두 종류로 구분
- 바이트 스트림: 그림, 멀티미디어, 문자 등 모든 종류의 데이터를 입출력할 때 사용
- InputStream & OutputStream
- 문자 스트림: 문자만 입출력할 때 사용
- Reader & Writer
- 바이트 스트림: 그림, 멀티미디어, 문자 등 모든 종류의 데이터를 입출력할 때 사용
2. 바이트 출력 스트림
- OutputStream: 바이트 출력 스트림의 최상위 클래스이자 추상 클래스
2.1. 1 바이트 출력
- write(int b) method는 매개값 int(4 byte)에서, 끝 1byte만 출력
- OutputStream은 내부에 작은 buffer를 가짐
- write() method 호출 -> 버퍼에 바이트를 우선 저장, 버퍼가 차면 순서대로 바이트를 출력
- flush(): 내부 버퍼에 잔류하는 모든 바이트를 출력하고, 버퍼를 비우는 역할
- OutputStream을 더이상 사용하지 않을 때, close() method를 호출하여 outputStream이 사용한 메모리를 해제
package ch18.sec2.exam1;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class WriteExample {
public static void main(String[] args) {
try {
OutputStream os = new FileOutputStream("경로/test1.db");
byte a = 10;
byte b = 20;
byte c = 30;
os.write(a);
os.write(b);
os.write(c);
os.flush();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
-> test1.db 파일 생성
2.2. 바이트 배열 출력
- write(byte[] b): 매개값으로 주어진 배열의 모든 바이트를 출력
- write(byte[] b , int off, int len): b[off]부터 len개의 바이트를 출력
3. 바이트 입력 스트림
- InputStream: 바이트 입력 스트림의 최상위 클래스이자, 추상 클래스
3.1. 1 바이트 읽기
- read(): inputStream으로부터 1byte를 읽고, int (4byte) 타입으로 리턴 -> 리턴된 4byte 중 끝 1byte에만 데이터가 들어 있음
- 더 이상 입력 스트림으로부터 바이트를 읽을 수 없으면, -1을 리턴
InputStream is = ...;
while(true) {
int data = is.read(); // 1 바이트를 읽고 리턴
if(data == -1) break; // -1을 리턴한 경우 while문 종료
}
- 예제
package ch18.sec2.exam1;
import java.io.InputStream;
import java.io.*;
public class ReadExample {
public static void main(String[] agrs) {
try {
InputStream is = new FileInputStream("경로/test1.db");
while(true) {
int data = is.read();
if(data == -1) {
break;
}
System.out.println(data);
}
is.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.2. 바이트 배열로 읽기
- read(byte[] b): inputStream으로부터 주어진 배열의 길이만큼 바이트를 읽고, 배열에 저장한 다음 바이트 수를 리턴
InputStream is = ...;
byte[] data = new byte[100];
while (true) {
int num = is.read(data); // 최대 100byte를 읽고, 읽은 바이트는 배열 data 저장, 읽은 수는 return
if(num == -1) break; // -1을 리턴하면 while문 종료
}
- 파일 복사 예제
package ch18.sec3.exam3;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class CopyExample {
public static void main(String[] args) throws Exception {
String originalFileName = "경로/test.jpg";
String targetFileName = "경로/test2.jpg";
InputStream is = new FileInputStream(originalFileName);
OutputStream os = new FileOutputStream(targetFileName);
is.transferTo(os); // 아래 주석 대체 가능
/*
byte[] data = new byte[1024];
while(true) {
int num = is.read(data);
if(num == -1) break;
os.write(data, 0 , num);
}
*/
os.flush();
os.close();
is.close();
System.out.println("복사 완료");
}
}
4. 문자 입출력 스트림
4.1. 문자 출력
- InputStream & OutputStream vs. Reader & Writer -> 입출력 단위가 문자인 것을 제외하고, 사용 방법 동일
package ch18.sec4.exam1;
import java.io.IOException;
import java.io.Writer;
import java.io.FileWriter;
public class WriteExample {
public static void main(String[] args) {
try {
// 문자 기반 출력 스트림 생성
Writer writer = new FileWriter("경로/test.txt");
// 1 문자씩 출력
char a = 'A';
writer.write(a);
char b = 'B';
writer.write(b);
// char 배열 출력
char[] arr = { 'C', 'D', 'E' };
writer.write(arr);
// 문자열 출력
writer.write("FGH");
// 버퍼에 잔류하고 있는 문자열들 출력, 버퍼를 비움
writer.flush();
// 출력 스트림을 닫고 메모리 해제
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
4.2. 문자 읽기
package ch18.sec4.exam1;
import java.io.Reader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class ReadExample {
public static void main(String[] args) {
try {
Reader reader = null;
// 1 문자씩 읽기
reader = new FileReader("path/test.txt");
while(true) {
int data = reader.read();
if(data == -1) break;
System.out.print((char)data);
}
reader.close();
System.out.println();
// 문자 배열로 읽기
reader = new FileReader("path/test.txt");
char[] data = new char[100];
while(true) {
int num = reader.read(data);
if(num == -1) break;
for(int i = 0; i < num; i++) {
System.out.print(data[i]);
}
}
reader.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
5. 보조 스트림
- 보조 스트림: 다른 스트림과 연결되어 여러 가지 편리한 기능을 제공해주는 스트림
- 자체적으로 입출력 수행 불가능 -> 입출력 소스로부터 직접 생성된 입출력 스트림에 연결해서 사용
보조스트림1 변수 = new 보조스트림1(입출력스트림);
보조스트림2 변수 = new 보조스트림2(보조스트림1); // stream chain
- 예제
InputStream is = new FileInputStrema("...");
InputStreamReader reader = new InputStreamReader( is ); // 바이트 스트림을 문자 스트림으로 변환
BufferReader br = new BufferedReader( reder );
6. 문자 변환 스트림
- 바이트 스트림(InputStream, OutputStream)에서 입출력할 데이터가 문자인 경우, 문자 스트림(Reader, Writer)로 변환해서 사용하는 것이 좋음
- 문자로 바로 입출력하는 편리함
- 문자셋의 종류를 지정 가능
6.2. InputStream을 Reader로 변환
- InputStream을 Reader로 변환하려면 InputStreamReader 보조 스트림 연결
InputStream is = new FileInputStream("path/test.txt");
Reader reader = new InputStreamReader(is); // (is, "UTF-8")로 문자셋 전달 가능
6.3. OutputStream을 Writer로 변환
- OutputStream을 Writer로 변환하려면 OutputStreamWriter 보조 스트림 연결
OutputStream os = new FileOutputStream("path");
Writer writer = new OutputStreamWriter(os); // (os, "UTF-8")로 문자셋 전달 가능
7. 성능 향상 스트림
- cpu와 메모리가 아무리 뛰어나도, 하드 디스크의 입출력이 늦어지면 프로그램의 실행 성능은 하드 디스크의 처리 속도에 맞춰짐
- 네트워크로 데이터를 전송할 때도, 느린 네트워크 환경이라면 컴퓨터 사양과 별개로 성능이 낮아짐
- 프로그램이 입출력 소스와 직접 작업하지 않고, 중간에 메모리 버퍼와 작업함으로써, 실행 성능 향상 가능
- 버퍼에 데이터를 쌓다가, 한꺼번에 하드 디스크로 보냄으로써 디스크 접근 횟수 감소
- 메모리 버퍼를 제공하여 프로그램의 실행 성능을 향상시키는 보조 스트림
- 바이트 스트림의 경우, BufferedInputStream, BufferedOutputStream
- 문자 스트림의 경우, BufferedReaeder, BufferedWriter
BufferedInputStream bis = new BufferedInputStream(바이트 입력 스트림);
BufferedOutputStream bos = new BufferedOutputStream(바이트 입력 스트림);
BufferedReader br = new BufferedReader(문자 입력 스트림);
BufferedWriter bw = new BufferedWriter(문자 출력 스트림);
- 예제
package ch18.sec7.exam1;
import java.io.*;
public class BufferExample {
public static void main(String[] args) throws Exception {
// 입출력 스트림 생성
String originalFilePath1 =
BufferExample.class.getResource("originalFile1.jpg").getPath();
String targetFilePath1 = "path/targetFile1.jpg";
FileInputStream fis = new FileInputStream(originalFilePath1);
FileOutputStream fos = new FileOutputStream(targetFilePath1);
// 입출력 스트림 + 버퍼 스트림 생성
String originalFilePath2 =
BufferExample.class.getResource("originalFile2.jpg").getPath();
String targetFilePath2 = "path/targetFile2.jpg";
FileInputStream fis2 = new FileInputStream(originalFilePath2);
FileOutputStream fos2 = new FileOutputStream(targetFilePath2);
BufferedInputStream bis = new BufferedInputStream(fis2);
BufferedOutputStream bos = new BufferedOutputStream(fos2);
// 버퍼를 사용하지 않고 복사
long nonBufferTime = copy(fis, fos);
System.out.println("버퍼 미사용: \t" + nonBufferTime + " ns");
// 버퍼를 사용하고 복사
long bufferTime = copy(bis, bos);
System.out.println("버퍼 사용: \t" + bufferTime + " ns");
fis.close();
fos.close();
bis.close();
bos.close();
}
public static long copy(InputStream is, OutputStream os) throws Exception {
// 시작 시간 저장
long start = System.nanoTime();
// 1 바이트를 읽고 1 바이트 출력
while(true) {
int data = is.read();
if(data == -1) break;
os.write(data);
}
os.flush();
// 끝 시간 저장
long end = System.nanoTime();
// 복사 시간 리턴
return (end - start);
}
}
- 문자 입력 스트림 Reader에 BufferedReader를 연결하면, 행 단위로 문자열을 읽는 readLine() method 제공
BufferedReader br = new BufferReader(new FileReader("..."));
while(true) {
String str = br.readLine(); // 파일에서 한 행씩 읽음
if(str == null) break; // 파일 끝 -> while 문 종료
}
8. 기본 타입 스트림
- 바이트 스트림에 DataInputStream과 DataOutputStream 보조 스트림 연결 -> 기본 타입인 boolean, char, short, int, long, float, double 값을 입출력 가능
- 예제
FileOutputStreame fos = new FileOutputStream("path");
PrintStream ps = new PrintStream(fos);
ps.print("마치 ");
ps.println("프린터가 출력하는 것처럼 ");
ps.println("데이터를 출력합니다.");
ps.printf("| %6d | %-10s | %10s | \n", 1, "홍길동", "도적");
ps.printf("| %6d | %-10s | %10s | \n", 2, "김자바", "학생");
10. 객체 스트림
- Java는 메모리에 생성된 객체를 파일 또는 네트워크로 출력할 수 있음
- 객체를 출력하려면, 필드값을 일렬로 늘어선 바이트로 변경해야 함 -> 이를 직렬화(serialization)라 함
- 반대로 직렬화된 바이트 객체를 필드값으로 복원하는 것을 역직렬화(deserialization)
- 객체 입출력 보조 스트림
- ObjectInputStream: 바이트 입력 스트림과 연결되어 객체로 복원하는 역직렬화
- ObjectOutputStream: 바이트 출력 스트림과 연결되어 객체를 직렬화
ObjectInputStream ois = new ObjectInputStream(바이트 입력 스트림);
ObjectOutputStream oos = new ObjectOutputStream(바이트 출력 스트림);
oos.writeObject(객체);
객체타입 변수 = (객체타입) ois.readObject();
- 예제
package ch18.sec10;
import java.io.Serializable;
public class Member implements Serializable {
private static final long serialVersionUID = -622284561026719240L;
private String id;
private String name;
public Member(String id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() { return id + ": " + name; }
}
package ch18.sec10;
import java.io.Serializable;
public class Product implements Serializable {
private static final long serialVersionUID = -621812868570078544L;
private String name;
private int price;
public Product(String name, int price) {
this.name = name;
this.price = price;
}
@Override
public String toString() { return name + ": " + price; }
}
package ch18.sec10;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Arrays;
public class ObjectInputOutputStreamExample {
public static void main(String[] args) throws Exception {
// FileOutputStream에 ObjectOutputStream 보조 스트림 연결
FileOutputStream fos = new FileOutputStream("object.dat");
ObjectOutputStream oos = new ObjectOutputStream(fos);
// 객체 생성
Member m1 = new Member("fall", "단풍이");
Product p1 = new Product("노트북", 1500000);
int[] arr1 = { 1, 2, 3 };
// 객체를 역직렬화해서 파일에 저장
oos.writeObject(m1);
oos.writeObject(p1);
oos.writeObject(arr1);
oos.flush(); oos.close(); fos.close();
// FileInputStream에 ObjectInputStream 보조 스트림 연결
FileInputStream fis = new FileInputStream("object.dat");
ObjectInputStream ois = new ObjectInputStream(fis);
// 파일을 읽고 역직렬화해서 객체로 복원
Member m2 = (Member) ois.readObject();
Product p2 = (Product) ois.readObject();
int[] arr2 = (int[]) ois.readObject();
ois.close(); fis.close();
// 복원된 객체 내용 확인
System.out.println(m2);
System.out.println(p2);
System.out.println(Arrays.toString(arr2));
}
}
10.1. Serializable 인터페이스
- java에서는 Serializable interface를 구현한 클래스만 직렬화할 수 있도록 제한
- Serializable interface는 멤버가 없는 빈 인터페이스이지만, 객체를 직려로하할 수 있다고 표시하는 역할
- 객체가 직렬화될 때, 인스턴스 필드값은 직렬화 대상이지만, static 필드값과 transient로 선언된 필드값은 직렬화에서 제외
10.2. serialVersionUID 필드
- 직렬화할 때 사용된 클래스와 역직렬화할 때 사용된 클래스는 기본적으로 동일한 클래스여야 함
- 클래스 내용이 다르더라도 직렬화된 필드를 공통으로 포함하고, 두 클래스가 동일한 serialVersionUI 상수값을 가지고 있는 경우, 역직렬화 가능
11. File과 Files 클래스
11. File 클래스
- 경로 구분자는 os마다 조금씩 다른데, 윈도우는 \\ 또는 /, 맥os 및 리눅스에서는 / 사용
- 경로에 실제 파일이나 디렉토리가 없어도 예외 발생 X -> exists() method 호출로 검증
File file = new File("경로");
boolean isExist = file.exit(); // 파일이나 폴더가 존재하면 true 리턴
exists() method 리턴값이 false일 경우 사용 가능한 methods
exists() method 리턴값이 true일 경우 사용 가능한 methods
- 예제
package ch18.sec11;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
public class FileExample {
public static void main(String[] args) throws Exception {
// File 객체 생성
File dir = new File("src/ch18/sec11/Temp/images");
File file1 = new File("src/ch18/sec11/Temp/file1.txt");
File file2 = new File("src/ch18/sec11/Temp/file2.txt");
File file3 = new File("src/ch18/sec11/Temp/file3.txt");
// 존재하지 않으면 디렉토리 또는 파일 생성
if(dir.exists() == false) { dir.mkdirs(); }
if(file1.exists() == false) { file1.createNewFile(); }
if(file2.exists() == false) { file2.createNewFile(); }
if(file3.exists() == false) { file3.createNewFile(); }
// temp 폴더의 내용 출력
File temp = new File("src/ch18/sec11/Temp");
File[] contents = temp.listFiles();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd a HH:mm");
for(File file : contents) {
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();
}
}
}
11.2. Files 클래스
- Files 클래스는 static methods로 구성되어 있어, File 클래스처럼 객체로 만들 필요 X
- Files의 static methods는 os의 파일 시스템에게 파일 작업을 수행하도록 위임
- 위 methods는 parameter로 Path 객체를 받음
- Path 객체: 파일이나 디렉토리를 찾기 위한 경로 정보를 가짐, 정적 메소드인 get() method로 얻을 수 있음
Path path = Paths.get(String first, String ... more);
Path path = Paths.get("/Temp/dir/file.txt");
Path path = Paths.get("/Temp/dir", "file.txt");
Path path = Paths.get("Temp", "dir", "file.txt");
- 예제
package ch18.sec11;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class FilesExample {
public static void main(String[] args) {
try {
String data = ""
+ "id: winter\n"
+ "email: winter@mycompany.com\n"
+ "tel: 010-123-1234";
// Path 객체 생성
Path path = Paths.get("src/ch18/sec11/Temp/user.txt");
// 파일 생성 및 데이터 저장
Files.writeString(Paths.get("src/ch18/sec11/Temp/user.txt"), data, Charset.forName("UTF-8"));
// 파일 정보 얻기
System.out.println("파일 유형: " + Files.probeContentType(path));
System.out.println("파일 크기: " + Files.size(path) + " bytes");
// 파일 읽기
String content = Files.readString(path, Charset.forName("UTF-8"));
System.out.println(content);
} catch (IOException e) {
e.printStackTrace();
}
}
}
참고자료
'Programming Lang > Java' 카테고리의 다른 글
[이것이 자바다] Chapter 19. 네트워크 입출력 (0) | 2025.02.07 |
---|---|
[이것이 자바다] Chapter 17. 스트림 요소 처리 (0) | 2025.02.03 |
[이것이 자바다] Chapter 16. 람다식 (2) | 2025.02.02 |
[이것이 자바다] Chapter 15. 컬렉션 자료구조 (0) | 2025.02.02 |
[이것이 자바다] Chapter 14. 멀티 스레드 (1) | 2025.02.01 |