1. Java 입출력
- 자바 ⇒ 모든 I/O가 스트림(Stream)을 통해 이루어짐
- 스트림 : “데이터의 흐름” (데이터 입출력 시 데이터가 이동하는 통로)
📌 java.io 패키지 ⇒ 다양한 입출력 스트림 클래스 제공
크게 바이트 기반 스트림과 문자 기반 스트림으로 나눌 수 있음
바이트 기반 입출력 스트림 : 그림, 멀티미디어, 문자 등 모든 종류의 데이터들을 주고받을 수 있음
문자 기반 입출력 스트림 : 오로지 문자만 주고받을 수 있게 특화
1-1. 바이트 기반 스트림
- 최상위 클래스
- InputStream, OutputStream 존재
- 둘 다 추상 클래스 ⇒ 상속받는 하위 클래스 통해서 구현
- 하위 클래스 : XXXInputStream, XXXOutputStream
- 입력 ⇒ ex) FileInputStream, BufferedInputStream, DataInputStream
- 출력 ⇒ ex) FileOutputStream, BufferedOutputStream, DataOutputStream, PrintStream
1-1-1. 바이트 입력 스트림 : InputStream
- read()
- 입력 스트림으로부터 바이트 단위로 값을 읽음
- ASCII 코드 반환 (int형)
- 바이트가 없으면 -1 반환
public static void main(String[] args) throws FileNotFoundException {
String filePath = System.getProperty("user.dir") + "/src/week4/ch4_1/input.txt";
// try-with-resources : inputStream.close() 생략가능!
try (InputStream inputStream = new FileInputStream(filePath)) {
while(true) {
int readData = inputStream.read();
if(readData == -1) {
System.out.println("끝");
break;
}
System.out.println("readData = " + readData);
System.out.println("(char)readData = " + (char) readData);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
// input.txt 에는 "hello~" 가 저장되어 있음
/* 실행결과
readData = 104
(char)readData = h
readData = 101
(char)readData = e
readData = 108
(char)readData = l
readData = 108
(char)readData = l
readData = 111
(char)readData = o
readData = 126
(char)readData = ~
끝
*/
- read(byte[] b)
- 입력 스트림으로부터 읽어온 데이터를 (파라미터로 넘긴) 바이트 배열에 저장함
- 읽은 바이트 수를 반환함
public static void main(String[] args) throws FileNotFoundException {
String filePath = System.getProperty("user.dir") + "/src/week4/ch4_1/input.txt";
try(InputStream inputStream = new FileInputStream(filePath)) {
byte[] byteArr = new byte[20];
int read = inputStream.read(byteArr); // 반환값 : 읽은 바이트 수
System.out.println("read = " + read);
// 인덱스 0~read 까지 byteArr 배열의 값을 String 객체로 생성
System.out.println("String(byteArr) = " + new String(byteArr,0,read));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
// input.txt 에는 "hello~" 가 저장되어 있음
/* 실행결과
read = 6
String(byteArr) = hello~
*/
- read(byte[] b, int off, int len)
- 입력 스트림으로부터 읽어 온 데이터를 바이트 배열에 저장
- 이때, 배열의 offset 인덱스부터 저장
- len 만큼만 읽어옴
- read(byte[] b) 와 동일하게 읽어온 바이트 수 반환
- 입력 스트림으로부터 읽어 온 데이터를 바이트 배열에 저장
public static void main(String[] args) throws FileNotFoundException {
String filePath = System.getProperty("user.dir") + "/src/week4/ch4_1/input.txt";
try(InputStream inputStream = new FileInputStream(filePath)) {
byte[] byteArr = new byte[10];
int read = inputStream.read(byteArr, 2, 4);
System.out.println("read = " + read);
System.out.println("String(byteArr) = " + new String(byteArr));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
// input.txt 에는 "hello~" 가 저장되어 있음
/* 실행결과
read = 4
String(byteArr) = xxhellxxxx ( <= 여기서 x는 없음을 의미)
*/
1-1-2. 바이트 출력 스트림 : OutputStream
- write(int b)
- 출력 스트림으로 단일 바이트 출력
- 파라미터가 int ⇒ int 형 데이터를 넘기면 마지막 1바이트만 전송됨
public static void main(String[] args) {
String filePath = System.getProperty("user.dir") + "/src/week4/ch4_1/output.txt";
try (FileOutputStream outputStream = new FileOutputStream(filePath)) {
String outputMessage = "OutputStream Example~";
byte[] bytes = outputMessage.getBytes();
for (byte b : bytes) {
outputStream.write(b);
}
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/* 실행결과
(output.txt 가 없다면 해당 경로에 output.txt가 생성되고)
OutputStream Example~ 이 출력됨
*/
- write(byte[] b)
- 바이트 배열 b를 출력 스트림 통해서 출력함
public static void main(String[] args) {
String filePath = System.getProperty("user.dir") + "/src/week4/ch4_1/output.txt";
try(FileOutputStream outputStream = new FileOutputStream(filePath)) {
byte[] bytes = "OutputStream Example 2 !!".getBytes();
outputStream.write(bytes);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/* 실행결과
(output.txt 가 없다면 해당 경로에 output.txt가 생성되고)
OutputStream Example 2 !! 이 출력됨
*/
- write(byte[] b, int off, int len)
- 바이트 배열 b에서 off 인덱스부터 len 개수만큼의 바이트를 출력 스트림 통해서 출력함
public static void main(String[] args) {
String filePath = System.getProperty("user.dir") + "/src/week4/ch4_1/output.txt";
try(FileOutputStream outputStream = new FileOutputStream(filePath)) {
byte[] bytes = "OutputStream Example 3 !!".getBytes();
outputStream.write(bytes, 13, 9); // "Example 3"
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/* 실행결과
(output.txt 가 없다면 해당 경로에 output.txt가 생성되고)
Example 3 이 출력됨
*/
1-2. 문자 기반 스트림
- 최상위 클래스
- Reader, Writer 존재
- 둘 다 추상 클래스 ⇒ 상속받는 하위 클래스 통해서 구현
- 하위 클래스 : XXXReader, XXXWriter
- 입력 ⇒ ex) FileReader, BufferedReader, InputStreamReader
- 출력 ⇒ ex) FileWriter, BufferedWriter, OutputStreamWriter, PrintWriter
1-2-1. 문자 입력 스트림 : Reader
- read()
- 입력 스트림으로부터 단일 문자 단위로 값을 읽음
- 단일 문자 ⇒ 2바이트 의미
- 값이 존재하지 않으면 -1 반환
📌 InputStream의 read() vs Reader의 read()
- InputStream의 read() : 바이트 단위로 값을 읽어옴
- Reader의 read() : 단일 문자(2바이트)로 값을 읽어옴
⇒ InputStream의 read()는 한글이 깨지는 현상 발생
Reader의 read()는 2바이트로 읽어오므로 한글이 깨지지 않음!
public static void main(String[] args) {
String filePath = System.getProperty("user.dir") + "/src/week4/ch4_1/input.txt";
try (FileReader reader = new FileReader(filePath)){
while(true) {
int read = reader.read();
if(read == -1) break;
System.out.println("read = " + read);
System.out.println("(char)read = " + (char) read);
}
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
// input.txt => "hello~" 인 경우
/* 실행결과 (InputStream의 read() 와 동일함)
read = 104
(char)read = h
read = 101
(char)read = e
read = 108
(char)read = l
read = 108
(char)read = l
read = 111
(char)read = o
read = 126
(char)read = ~
*/
// input.txt => "안녕하세요!" 인 경우
/* 실행결과 (InputStream의 read()와는 다르게 한글이 깨지지 않음!)
read = 50504
(char)read = 안
read = 45397
(char)read = 녕
read = 54616
(char)read = 하
read = 49464
(char)read = 세
read = 50836
(char)read = 요
read = 33
(char)read = !
*/
- read(char[] cbuf)
- 읽어온 데이터를 파라미터로 넘긴 cbuf (char 배열)에 저장함
- 읽어온 단일문자의 수 반환
public static void main(String[] args) {
String filePath = System.getProperty("user.dir") + "/src/week4/ch4_1/input.txt";
try (FileReader reader = new FileReader(filePath)){
char[] cbuf = new char[20];
System.out.println("reader.read(cbuf) = " + reader.read(cbuf));
System.out.println("Arrays.toString(cbuf) = " + Arrays.toString(cbuf));
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
// input.txt => "안녕하세요!" 인 경우
/* 실행결과
reader.read(cbuf) = 6
Arrays.toString(cbuf) = [안, 녕, 하, 세, 요, !, , , , ]
*/
1-2-2. 문자 출력 스트림 : Writer
- write(int c), write(char[] cbuf), write(char[] c, int off, int len) 등
위의 메서드 들과 동일 - write(String str)
- 편의상 char 배열이 아닌 String 타입도 가능!
public static void main(String[] args) {
String filePath = System.getProperty("user.dir") + "/src/week4/ch4_1/output.txt";
try (FileWriter writer = new FileWriter(filePath)){
String content = "hello!\n안녕하세요!";
writer.write(content);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/* 실행결과
(output.txt 가 없다면 해당 경로에 output.txt가 생성되고)
hello!
안녕하세요!
*/
- write(String str, int off, int len)
- String 타입 (문자열) 에서 offset 인덱스부터 length 만큼의 문자열을 출력 스트림 통해서 출력함
public static void main(String[] args) {
String filePath = System.getProperty("user.dir") + "/src/week4/ch4_1/output.txt";
try (FileWriter writer = new FileWriter(filePath)){
String content = "hello!\n안녕하세요!";
writer.write(content,0,6);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/* 실행결과
(output.txt 가 없다면 해당 경로에 output.txt가 생성되고)
hello!
*/
2. 버퍼 (Buffer)
- 버퍼 : 데이터를 임시로 저장하는 메모리 공간
📌 버퍼는 입력받은 값을 임시로 저장하고
버퍼에 값이 가득차거나 개행문자가 나타나면 버퍼의 내용을 한 번에 전송함!!
⇒ 바로바로 입력값을 전달하는 것이 아니라 모아두었다가 한 번에 전송하기 때문에 속도가 빠름!
2-1. 버퍼 주의사항
- Scanner ⇒ 띄어쓰기, 개행문자를 기준으로 입력 값 구분
버퍼 ⇒ 오직 개행문자만을 기준으로 입력 값 구분
따라서 버퍼 사용시에는 띄어쓰기는 데이터 가공으로 직접 구분해야함! - 버퍼로 입력받은 값 ⇒ 기본타입: String
따라서 원하는 타입 (ex. int, double) 등으로 형변환 해야함! - IOException 에 대한 처리 필수
2-2. 버퍼 스트림 사용법
public static void main(String[] args) {
String fileInputPath = System.getProperty("user.dir") + "/src/week4/ch4_1/input.txt";
String fileOutputPath = System.getProperty("user.dir") + "/src/week4/ch4_1/output.txt";
try (BufferedReader bufferedReader = new BufferedReader(new FileReader(fileInputPath));
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(fileOutputPath))) {
String inputString = bufferedReader.readLine();
// 띄어쓰기로 구분
String[] stringArr = inputString.split(" ");
for (String s : stringArr) {
bufferedWriter.write(s + "\n");
}
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
// input.txt : "버퍼스트림 예제 input" 저장되어 있을 때
/* 실행결과 (output.txt 에 아래와 같이 출력됨)
버퍼스트림
예제
input
*/
'Java' 카테고리의 다른 글
[Java] 예외 처리 (Exception Handling) (0) | 2024.07.28 |
---|---|
[Java] 자바 제네릭스 (Generics) (0) | 2024.07.28 |
[Java] 자바 메모리 구조 (0) | 2024.07.09 |
[Java] final (0) | 2024.07.09 |
[Java] static (0) | 2024.07.09 |