입력/출력 스트림
이전에 우리가 배웠던 스트림과는 완전 다른 스트림이다. 지금까진 메모리 내에서 동작되는 내용에 대해서 배웠지만 입출력이라는건 메모리 외부와 통신하는 것이다. 대표적인건 파일시스템, 네트워크로 통하는 소켓 이런것들을 다루는 과정이 입출력이다. 메모리 외부의 것들을 메모리로 옮기는 것, 메모리 안의 것을 메모리 밖으로 옮기는 것을 스트림이란 개념으로 전부 추상화를 시켜놨다.
데이터를 읽고 쓸 때는 스트림을 이용한다.
- 입력 스트림 : 바이트(데이터)의 출발지(source)
- 출력 스트림 : 바이트(데이터)의 도착지
데이터는 바이너리와 텍스트로 구분 (자바에선 UTF-16을 바이너리 데이터로 쓰고, 텍스트를 다루는 입력 데이터는 reader 클래스, 출력 데이터는 writer 클래스)
주로 파일이나 네트워크를 데이터의 출발지와 도착지로 사용
파일에 데이터 쓰기 : 데이터 메모리 => 하드
파일에 텍스트 데이터 쓰기
- 자바에서 텍스트는 UTF-16 문자로 다루어짐
- 2바이트 문자를 다루기 위해서 Writer 사용
// 데코레이터 패턴, FileWriter로 파일을 읽어 BufferedWriter로 버퍼링
BufferedWriter out = new BufferedWriter(new FileWriter(“out.txt”);
// out.txt로 무언가를 쓰겠다. bufferedwriter로 생성자의 파라미터를 filewriter로 받는다.
// out 스트림에 스트링을 출력
out.write(“Hello world..”);
// 자동적으로 out stream이 만들어지면서 out.txt 파일에 hello world를 쓰게 됨.
// 리소스 해제는 반드시 수행되어야 함
out.close();
// out이라는 객체는 외부 파일 resource를 다루기 때문에 반드시 클로즈 해야 한다.
파일에서 데이터 읽기 : 하드 => 데이터 메모리
텍스트 파일 읽기
- 2바이트 텍스트 파일을 읽기 위해 Reader 사용
- FileReader와 BufferedReader를 데코레이터 패턴으로 사용
// 데코레이터 패턴, FileReader로 파일을 읽어 BufferedWriter로 버퍼링 (한 줄씩 읽기 위해)
BufferedReader in = new BufferedReader(FileReader(“out.txt”));
// 파일을 라인 단위로 읽어들임
String line;
while (line = in.readLine() != null) {
System.out.prinln(line);
}
//리소스 해제
in.close();
경로, 파일, 디렉터리
Path 클래스는 파일과 디렉터리(경로)를 나타낸다. (구형은 File 클래스. 이제는 Path 많이 사용)
- 디렉터리 이름을 나타내며, 경우에 따라 파일 이름이 붙음
- 절대경로와 상대경로를 나타낼 수 있음
Path absolute = Paths.get(“/“, “where”, “to”); // 절대 경로에 해당되는 디렉토리가 만들어진다.
Path relative = Paths.get(“myapp”, “conf”, “user.properties”);
// 실무에서는 상대경로보다는 절대경로가 더 선호된다.
Path : Paths는 컴패니언 클래스다. path는 인터페이스, paths는 static 메소드를 포함한 클래스다.
이런 컴패니언 클래스는 jdk 1.8 이전에 나온거고, 그 이후엔 이런 컴패니언 클래스를 잘 안쓴다.
Path 인터페이스에는 경로를 분리하고 다른 경로와 결합하는 메소드가 있다.
Path p = Paths.get(“/home”, “kim”, “myapp.properties”); // 경로가 포함된 파일 p(myapp.properties)를 하나 만든다. 세 개의 요소는 리스트 형태로 저장된다.
Path parent = p.getParent(); // 경로 /home/kim
Path file = p.getFileName(); // 마지막 요소인 myapp.properties
Path root = p.getRoot(); // 처음 세그먼트인 / (상대 경로일때는 null)
Path first = p.getName(0); // 첫 번째 요소, 즉 0번째 인덱스인 /home 반환.
Path dir = p.subpath(1, p.getNameCount());
// 두 번째 요소 이후의 경로 kim/myapp.properties
for 루프를 이용해 Path 이름 구성요소를 순회할 수 있다.
for (Path component : path) {…}
파일과 디렉터리 생성하기
// 새 디렉토리 생성
Files.createDirectory(path);
// 빈 파일 생성 (이미 파일이 있으면 예외가 발생됨)
Files.createFile(path);
파일 복사, 이동, 삭제
// 파일을 다른 위치로 복사
Files.copy(fromPath, toPath);
// 파일 이동 (원본을 복사 후 삭제)
Files.move(fromPath, toPath);
// 파일 삭제 (빈 디렉터리도 삭제 가능)
Files.delete(path);
Files.deleteIfExists(path); // 파일이 있을 때만 삭제
ThinkPoint
윈도우와 리눅스(맥)에서의 파일처리 시 다른 점을 조사해보세요.
- 디렉토리 구조 (윈도우 원 사용, 리눅스 / 사용)
- 대소문자 구분 (윈도우는 대소문자 구분 하지 않지만 리눅스는 구분함)
- 드라이브 이름 사용 여부
- 리눅스는 모든것을 파일로 취급
- 파일을 사용중일 때 락을 거는 것 (윈도우 : 엄격, 리눅스 : 덜 엄격)
실습 코드
package com.acompany.io;
import java.io.*;
public class TextFileIOTest {
public static void main(String[] args) {
// 1. 텍스트 파일에서 파일 읽기 - 텍스트 파일에서부터 메모리 연결된 스트림 먼저 만들기. (앞서 스트림과는 다른 개념)
try (BufferedReader in = new BufferedReader(
new FileReader("cities.txt"))) {
// BufferedReader : 스트림 소스가 어떤것이든 간에 그걸 버퍼링해서 읽어들이는 것
String line; // 한줄씩
while ((line = in.readLine()) != null) {// 읽어서
System.out.println(line); // 처리(출력)
}
} catch (FileNotFoundException fe){
// ...
} catch (IOException ie) {
// ...
} // try in을 해줬으니 close를 해주지 않아도 됨.
//in.close(); // resource는 반드시 클로즈 해줘야 함.
// 2. 텍스트 파일로 쓰기 - 메모리부터 파일까지 아웃스트림 생성
try (BufferedWriter out = new BufferedWriter(
new FileWriter("output.txt"))) {
out.write("hello world\nJava is very interesting language!");
} catch (FileNotFoundException fe) {
// ...
} catch (IOException ie) {
}
//out.close(); // 스트림을 정확히 안닫으면 파일에 써지질 않음.
}
}
해당 강의 코드는 아래에서 확인 가능합니다.
https://github.com/LeenaKim/java9Politec/blob/master/src/com/acompany/io/TextFileIOTest.java
'Programming > Java' 카테고리의 다른 글
[ JAVA 수업 DAY 02 - 03 ] Java 반복문과 조건문 (0) | 2020.04.12 |
---|---|
[ JAVA 수업 DAY 01 ] Java 기초 (0) | 2020.04.12 |
[Java9 프로그래밍] 16. 스트림 활용과 Optional (0) | 2020.03.30 |
[Java9 프로그래밍] 15. 스트림 (0) | 2020.03.30 |
[Java9 프로그래밍] 14. 제네릭과 컬렉션 (0) | 2020.03.29 |