개발공부/JAVA
[JAVA] I/O Stream
jnnjnn
2024. 3. 27. 19:48
입출력 스트림
I/O Stream
은 데이터 Input과 output을 실행할 수 있는 입출력 스트림으로 java.io 패키지에서 제공된다.
다음 두 종류로 구분할 수 있다
- 바이트 스트림 : 그림, 멀티미디어, 문자 등 모든 종류의 데이터 입출력할 때 사용
InputStream
,OutputStream
- 문자 스트림 : 문자만 입출력할 때 사용
Reader
,Writer
바이트 출력 스트림
- OutputStream은 바이트 출력 스트림의 최상위 클래스로 추상 클래스이다.
- 모든 바이트 출력 스트림 클래스는 OutputStream 클래스를 상속받아 만들어진다
- OutputStream이 추상 클래스이므로 객체는 OutputStream의 자식 객체를 사용하여 생성한다
IOException
을 발생시키므로 예외 처리가 필요하다- 사용 후 close() 메소드를 호출해서 출력 스트림이 사용했던 메모리를 해제해야 한다
OutputStream 클래스의 주요 메소드
리턴 타입 | 메소드 | 설명 |
---|---|---|
void | write(int b) | 1byte를 출력 |
void | write(byte[] b) | 매개값으로 주어진 배열 b의 모든 바이트를 출력 |
void | write(byte[] b, int off, int len) | 매개값으로 주어진 배열 b[off]부터 len개의 바이트를 출력 |
void | flush() | 출력 버퍼에 잔류하는 모든 바이트를 출력 |
void | close() | 출력 스트림을 닫고 사용 메모리 해제 |
public class C02OutputStream {
public static void main(String[] args) throws IOException {
// temp/output2.data로 출력 데이터 내보냄
OutputStream os = new FileOutputStream("temp/output2.data");
os.write(29374); // 1 byte 출력
byte[] array = {10, 20, 30, 40, 50};
os.write(array); // 배열 array 출력
os.write(array, 1, 3); // 1번 인덱스부터 3개까지 출력
os.flush(); // 아직 스트림에 출력되지 않은 데이터들을 강제로 출력
os.close(); // 꼭 작성해야함
}
}
바이트 입력 스트림
- InputStream은 바이트 입력 스트림의 최상위 클래스로, 추상 클래스이다
- 모든 바이트 입력 스트림은 InputStream 클래스를 상속받아 만들어진다
InputStream의 주요 메소드
리턴 타입 | 메소드 | 설명 |
---|---|---|
int | read() | 1byte를 읽은 후 읽은 바이트값을 int로 리턴 |
int | read(byte[] b) | 읽은 바이트를 매개값으로 주어진 배열에 저장 후 읽은 바이트 수를 리턴 |
void | close() | 입력 스트림을 닫고 사용 메모리 해제 |
더 이상 입력 스트림으로부터 바이트를 읽을 수 없다면 read() 메소드는 -1을 리턴한다
public class C02InputStream {
public static void main(String[] args) {
String fileName = "temp/test3.db";
try (InputStream is = new FileInputStream(fileName)) {
int data = 0;
while ((data = is.read()) != -1) { // 더 이상 읽을 바이트가 없을 때까지 반복
System.out.println("data = " + data); // 읽은 바이트 출력
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
try-with-resources
- try블록에 close()를 사용할 수 없음
- close()를 사용하기 위해 코드가 복잡해짐
- 자바 7부터는 try-with-resources를 사용하여 간편하게 리소스를 해제할 수 있다
public class C04TryWithResources {
public static void main(String[] args) {
// close 메소드 호출을 위한 코드를 줄이기 위한 문법
String fileName = "temp/output4.data";
// try-with-resources
// try () 괄호 안에서 선언된 객체는 자동으로 close 메소드를 호출해줌
try (OutputStream os = new FileOutputStream(fileName)) {
os.write(293748);
} catch (IOException e) {
e.printStackTrace();
}
}
}
문자 입출력 스트림
문자 입출력 스트림으로는 Reader
와 Writer
가 있다. 입출력되는 단위가 문자인 것을 제외하고는 바이트 입출력 스트림과 사용 방법은 동일하다.
문자 출력
- Writer는 문자 출력 스트림의 최상위 클래스로, 추상 클래스이다.
- 모든 문자 출력 스트림 클래스는 Writer 클래스를 상속받아서 만들어진다
Writer의 주요 메소드
리턴 타입 | 메소드 | 설명 |
---|---|---|
void | write(int c) | 매개값으로 주어진 한 문자를 출력 |
void | write(char[] cbuf) | 매개값으로 주어진 배열의 모든 문자를 출력 |
void | write(char[] cbuf, int off, int len) | 매개값으로 주어진 배열에서 cbuf[off]부터 len개까지의 문자를 출력 |
void | write(String str) | 매개값으로 주어진 문자열을 출력 |
void | write(String str, int off, int len) | 매개값으로 주어진 문자열에서 off 순번부터 len개까지의 문자를 출력 |
void | flush() | 버퍼에 잔류하는 모든 문자를 출력 |
void | close() | 출력 스트림을 닫고 사용 메모리를 해제 |
public class WriteExample {
public static void main(String[] args) {
try {
Writer writer = new FileWriter("temp/test.txt");
char a = 'A';
writer.write(a);
char b = 'B';
writer.write(b);
char[] arr = {'C', 'B', 'E'};
writer.write(arr);
writer.write("FGH");
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
문자 읽기
- Reader는 문자 입력 스트림의 최상위 클래스로, 추상 클래스이다
- 모든 문자 입력 스트림 클래스는 Reader 클래스를 상속받아서 만들어진다
Reader의 주요 메소드
리턴 타입 | 메소드 | 설명 |
---|---|---|
int | read() | 1개의 문자를 읽고 리턴 |
int | read(char[] cbuf) | 읽은 문자들을 매개값으로 주어진 무자 배열에 저장하고 읽은 문자 수를 리턴 |
void | close() | 입력 스트림을 닫고, 사용 메모리 해제 |
public class ReadExample {
public static void main(String[] args) {
try (Reader reader =new FileReader("temp/output2.txt")){
while (true) {
int data = reader.read();
if (data == -1) break;
System.out.println((char) data);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
보조 스트림
- 보조 스트림이란 다른 스트림과 연결되어 여러 가지 편리한 기능을 제공해주는 스트림을 말한다
- 자체적으로 입출력을 수행할 수 없기 때문에 입출력 소스로부터 직접 생성된 입출력 스트림에 연결해서 사용해야 한다
- 보조 스트림은 또 다른 보조 스트림과 연결되어 스트림 체인으로 구성할 수 있다
문자 변환 스트림
InputStream
을 Reader
로, OutputStream
을 Writer
로 변환할 수 있다
public class C02OutputStreamWriter {
public static void main(String[] args) throws Exception {
String file = "temp/output2.txt";
OutputStream os = new FileOutputStream(file);
// OutputStreamWriter :
// 문자 단위 출력 스트림을 바이트 단위 출력 스트림 연결
OutputStreamWriter osw = new OutputStreamWriter(os);
char c1 = 'A';
osw.write(c1);
char c2 = '가';
osw.write(c2);
osw.close();
}
}
성능 향상 스트림
입출력 버퍼 스트림
을 사용하면버퍼
에 데이터가 쌓이기를 기다렸다가 꽉 차게 되면 데이터를 한꺼번에 하드 디스크로 보낸다- 결과적으로 출력 횟수를 줄여주어 성능이 향상된다
public class C04BufferedOutputStream {
public static void main(String[] args) throws IOException {
String fileName = "temp/bigfile/output2.data";
OutputStream os = new FileOutputStream(fileName);
BufferedOutputStream bos = new BufferedOutputStream(os);
byte[] data = new byte[1024];
long start = System.nanoTime();
for (int i = 0; i < (1024 * 1024); i++) {
bos.write(data);
}
bos.flush();
bos.close();
long end = System.nanoTime();
long time = end - start;
System.out.println("time = " + time);
}
}
프린트 스트림
- 바이트 출력 스트림인
PrintStream
과 문자 출력 스트림인PrintWriter
가 있다. System.out.println()
의out
은PrintStream
타입이다- 프린트 스트림의 메소드로는
print()
,println()
,printf()
가 있다
public class PrintStreamExample {
public static void main(String[] args) throws FileNotFoundException {
FileOutputStream fos = new FileOutputStream("temp/printstream.txt");
PrintStream ps = new PrintStream(fos);
ps.print("마치");
ps.println("프린트가 출력하는 것처럼");
ps.println("출력합니다");
ps.printf("|%6|%-10s|%10s|\n", 1, "홍길동,도적");
ps.printf("|%6|%-10s|%10s|\n", 1, "김자바,학생");
ps.flush();
ps.close();
}
}
File과 Files 클래스
File
은java.io
패키지에,Files
는java.nio.file
패키지에 속한다Files
는File
을 개선한 클래스로, 좀 더 많은 기능을 가지고 있다- path에 파일이나 디렉토리가 없더라도 File
객체
를 생성할 수 있다 - 생성한 File 객체는
exists()
메소드로 실제 파일이나 디렉토리의 존재 유무를 확인할 수 있다 Files
클래스는 정적 메소드로 구성되어 있어 객체를 생성할 필요가 없다
exists() 메소드의 리턴값이 false인 경우
리턴 타입 | 메소드 | 설명 |
---|---|---|
boolean | createNewFile() | 새로운 파일을 생성 |
boolean | mkdir() | 새로운 디렉토리를 생성 |
boolean | mkdirs() | 경로상에 없는 모든 디렉토리를 생성 |
exists() 메소드의 리턴값이 true인 경우
리턴 타입 | 메소드 | 설명 |
---|---|---|
boolean | delete() | 파일 또는 디렉토리 삭제 |
String | getNaem() | 파일의 이름을 리턴 |
String | getParent() | 부모 디렉토리를 리턴 |
File | getParentFile() | 부모 디렉토리를 파일 객체로 생성 후 리턴 |
String | getPath() | 전체 경로를 리턴 |
boolean | isDirectory() | 디렉토리인지 여부 |
boolean | isFile() | 파일인지 여부 |
long | length() | 파일의 크기 리턴 |
String[] | list() | 디렉토리에 포함된 파일 및 서브 디렉토리 목록 전부를 String 배열로 리턴 |
public class FileExample {
public static void main(String[] args) throws IOException {
File dir = new File("temp/images");
File file1 = new File("temp/file1.txt");
File file2 = new File("temp/file2.txt");
File file3 = new File("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();
}
File temp = new File("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();
}
}
}