1) I/O
데이터의 입력과 출력
자바의 I/O : Stream을 통해서 데이터를 주고 받는 구조
1-1. Stream과 Node
-
Stream :
데이터의 소스 -> 목적지까지 데이터를 이동시키는 통로
- Stream의 종류 : 파일 데이터, HTTP 응답 데이터, 키보드 입력(System.in)
-
Node :
데이터의 소스 or 목적지
- Node의 종류 : 키보드, 모니터, 파일, 메모리, 데이터베이스 등등..
1-2. Stream의 종류
java.io 패키지에서 관리
- 고려해야할 것 : 데이터타입, 노드타입, 방향
-
데이터타입
- byte : binary 데이터도 전송 가능
- char : 한글의 경우는 한 글자가 2바이트 이상이므로 char기반이 좋음.
-
방향
- 읽느냐 쓰느냐?
- Reader or Writer
- Input or Output
- 읽느냐 쓰느냐?
-
노드의 타입
-
단방향
ex) 키보드 (InputStream, Reader), 모니터 (OutputStream, Writer)
-
양방향
ex) 파일 (File), 다른 스레드 (Piped), 메모리 이용(Array - ByteArray, CharArray)
-
1-3. 노드 스트림
- Node와 직접 연결된 Stream입니다. (직접적으로 데이터를 받거나, 출력함)
-
대표적으로 키보드, 모니터, 파일을 다룰 수 있습니다.
- 키보드
- InputStream
- Reader
- Scanner
- 모니터
- OutputStream
- Writer
- 파일
- File 클래스
- FileInputStream, FileOutputStream
- FileReader, FileWriter
1-4. 키보드 입력받기
public static void main(String[] args) throws IOException {
InputStream is = System.in; // 키보드도 하나의 스트림입니다!
byte[] bytes = new byte[6];
is.read(bytes);
for (byte bt : bytes) {
System.out.println(bt);
}
}
abcd (입력)
---(출력들)---
97
98
99
100
10
0
InputStream 객체의 메서드 read를 통해서 데이터를 읽을 수 있는데,
read 함수는 오버라이딩이 되어있기 때문에 offset같은거도 설정할 수 있고, bytes라는 배열에 저장하도록 할 수도 있고, 아무튼 그렇다..
출력된 값들을 보면, a -> 97, b -> 98, c -> 99, d -> 100 그리고 마지막으로 \n
-> 10으로 인식되기 때문에 bytes에는 [97, 98, 99, 100, 10, 0]
이 들어있습니다.
그런데, 뭔가 문자인데 숫자로 인식되는게 불편합니다.
이를 위해서 숫자를 문자로 번역할 수 있는 일종의 통역사가 필요합니다.
=> 그런 통역사 역할을 보조 스트림(Auxiliary Stream)이 할 수 있다고 합니다.
1-5. Scanner
그런데, Scanner가 추가되면서 더 쉽게 처리할 수가 있다고 합니다.
import java.util.Scanner;
public class ScannerTest {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
for (int i=0; i<5; i++){
System.out.println(sc.nextInt());
}
}
}
1 a b c (인풋)
1
Exception in thread "main" java.util.InputMismatchException
at java.util.Scanner.throwFor(Scanner.java:864)
at java.util.Scanner.next(Scanner.java:1485)
at java.util.Scanner.nextInt(Scanner.java:2117)
at java.util.Scanner.nextInt(Scanner.java:2076)
at Tutorial.ScannerTest.main(ScannerTest.java:8)
sc.nextInt() 이외에도 nextLine()같은 여러 메소드가 있기 때문에 타입만 잘 지정을 하면 출력을 해줍니다.
만약 타입이 틀리면 출력되지 않고 에러를 반환해줍니다.
그렇지만 이게 다음에 소개할 보조스트림을 이용한 방식보다는 처리 속도가 느린 경우가 많기 때문에 어찌됬건 보조스트림에 대해서 알고 있어야 합니다.
1-6. 파일 입출력
-
- File 클래스
-
파일에 대한 정보를 담고 있는 객체, but 파일을 읽고 쓰는 것은 불가능.
파이썬으로 치면 일종의 OS 라이브러리랑 비슷한 느낌인것 같네요.
사용예제1. 주어진 위치에 파일을 생성하기.
public static void main(String[] args) throws IOException, URISyntaxException{ String dirName = "c:" + File.separator + "Temp" + File.separator + "mydir"; File file1 = new File(dirName); File file2 = new File(dirName, "test2.txt"); File file3 = new File(new URI("file:///c:/Temp/test4.txt")); file1.mkdir(); file2.createNewFile(); file3.createNewFile(); file3.deleteOnExit(); // 어플이 종료되면서 삭제됨. }
- File.separator를 사용하기 : OS에 따라 구분자가 달라지는 것을 해결하기 위함
- deleteOnExit : 어플리케이션이 종료될 때 자동으로 파일, 디렉토리를 삭제함.
사용예제2
현재 디렉토리 -> 자식파일들을 획득 -> 파일의 정보를 출력하기.
public static void main(String[] args){ File currentDir = new File("."); if (currentDir.exists()){ File[] childs = currentDir.listFiles(); for (File child : childs){ String name = child.getName(); System.out.println(name); } }
.listFiles()
: 그 디렉토리에 있는 파일들의 리스트를 가져옴.
-
현재 파일트리구조
C:. ├─.idea ├─markdown ├─out │ └─production │ └─untitled104 │ ├─com │ │ └─company │ ├─META-INF │ └─Tutorial └─src ├─Algorithm ├─com │ └─company └─Tutorial
-
출력된 내용
.gitignore .idea markdown out src untitled104.iml
src의 Tutorial 안에 있는 클래스에서 실행하였으나, 출력은 src가 아니라 윗쪽을 기준으로 출력이 되고 있습니다.
-
FileInputStream, FileOutputStream, FileReader, FileWriter
결론적으로 파일을 읽고 쓰기 위해서는 얘네들이 필요합니다.
ex)
FileInputStream input = new FileInputStream(file)
: 주어진 file객체의 내용을 읽기 위한 Stream
-
예제 :
c:/Windows/explorer.exe
파일을c:/Temp
로 복사하기- 두개의 파일 객체를 열기
- Source의 파일 객체를 읽어들이고, Target의 파일 객체에 쓰기
public static void main(String[] args){ String src_path = "C:" + File.separator + "Windows" + File.separator + "explorer.exe"; String tg_path = "C:" + File.separator + "temp" + File.separator + "explorer.exe"; File source = new File(src_path); File target = new File(tg_path); try { FileInputStream input = new FileInputStream(source); FileOutputStream output = new FileOutputStream(target); byte[] buffer = new byte[100]; int read; while ((read = input.read(buffer)) > 0 ){ output.write(buffer, 0, read); } } catch (IOException e){ e.printStackTrace(); } }
input.read(buffer)
- 파일의 값을 읽어서 buffer에 추가한다.
- 이 함수의 리턴값은 데이터의 byte 개수입니다.
output.write(buffer, 0, read)
- 0부터 read인덱스까지 buffer배열의 값을 파일에 씁니다.
- 자바에서는 특이한 while문이 가능합니다. while문 조건을 체크할 때도 그 값을 변수로 넣어버릴 수 있네요.