Java NIO는 New Input Output의 줄임말로 기능 중 간단한 파일 제어만 설명


Java IO와는 다르게 Stream이 아니고 Channel 방식을 사용




1. Files, 파일 다루기


Files의 다양한 메소드들은 다음 예제를 통해 확인하자.



package chap11.exam13.files;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class FilesExam {
	// 파일의 속성을 알아 볼 수 있다.
	public static void main(String[] args) throws Exception {
		
		Path path = Paths.get("C:/img/asd.txt");
		System.out.println("디렉토리 여부 : " + Files.isDirectory(path));
		System.out.println("파일 여부 : " + Files.isRegularFile(path));
		System.out.println("마지막 수정 시간 : " + Files.getLastModifiedTime(path));
		System.out.println("파일 크기 : " + Files.size(path));
		System.out.println("소유자 : " + Files.getOwner(path));
		System.out.println("숨김 파일 여부 : " + Files.isHidden(path));
		System.out.println("읽기 가능 여부 : " + Files.isReadable(path));
		System.out.println("쓰기 가능 여부 : " + Files.isWritable(path));
		System.out.println("실행 여부 : " + Files.isExecutable(path));
	}

}



2. FileSystem, 파일 정보


FileSystem은 현재 시스템의 다양한 정보를 불러올 수 있다.


Iterable에 FileStroe을 붙여서 사용



package chap11.exam13.files;

import java.io.IOException;
import java.nio.file.FileStore;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Path;

public class FileSystemExam {
	// 파일 시스템(파일/폴더/저장공간) 정보
	public static void main(String[] args) throws IOException {
		// 기본 파일 시스템 정보 추출하는 객체
		FileSystem fs = FileSystems.getDefault();
		Iterable<FileStore> infolist = fs.getFileStores();
		for(FileStore info : infolist) {
			System.out.println("드라이브 이름 : " + info.name());
			System.out.println("저장 타입 : " + info.type());
			System.out.println("용량 : " + info.getTotalSpace()/(1024*1024*1024) + "GB");
			System.out.println("사용 가능한 용량 : " + info.getUsableSpace()/(1024*1024*1024) + "GB");
		}
		
		System.out.println("====현재 사용중인 드라이버 루트 ====");
		for(Path path : fs.getRootDirectories()) {
			System.out.println(path.toString());
		}
	}

}



3. Path, 경로


Path는 경로에 관련된 다양한 메소드들이 있다.


폴더 생성 또는 파일 이름만 뽑는다던가 상위 폴더를 알아 낸다던가 등 여러가지 있다.



package chap11.exam13.files;

import java.nio.file.Path;
import java.nio.file.Paths;

public class PathExam {
	// 1. 파일 경로 확인 전문화
	public static void main(String[] args) {
		// 특정 경로의 파일 정보를 가져옴(Uri | String)
		Path path = Paths.get("C:/img/temp/10multi_copy");
		
		// 파일명
		System.out.println(path.getFileName());
		// 부모 확인
		System.out.println(path.getParent().getFileName());
		// 루트 확인
		System.out.println(path.getRoot());
		// 위에 쓴 경로들의 단계 수
		System.out.println(path.getNameCount());
		// 개별 단계 확인
		for(int i = 0; i < path.getNameCount(); i++) {
			System.out.println(i + " 단계 : " + path.getName(i));
		}
	}

}



package chap11.exam13.files;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class MKdirExam {
	// 디렉토리 및 파일 생성
	public static void main(String[] args) throws Exception {
		Path path = Paths.get("c:/img/test");
		// !File.exists()
		if(Files.notExists(path)) {
			System.out.println("폴더 생성");
			Files.createDirectories(path);
		}
		path = Paths.get("c:/img/test/textFile.txt");
		if(Files.notExists(path)) {
			System.out.println("파일 생성");
			Files.createFile(path);
		}
	}

}




4. WatchService, 파일 감시


WatchService는 지정한 폴더 내부의 파일이 생성되거나 수정되거나 삭제되는 경우를 감지하는 기능을 가지고 있다.


생성 시 감시할 이벤트들을 설정하고 사용한다.



package chap11.exam13.files;

import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchEvent.Kind;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.List;

public class WatchServiceExam {
	// 특정 경로의 파일 변경을 감시
	public static void main(String[] args) throws Exception {
		
		// 기본 영역 지정
		WatchService watch = FileSystems.getDefault().newWatchService();
		
		// 감시 할 상세 주소 지정
		Path path = Paths.get("c:/img");
		
		// 어떤 와치 서비스가 어떤것을 감시하나?
		path.register(watch,  StandardWatchEventKinds.ENTRY_CREATE, 
				StandardWatchEventKinds.ENTRY_DELETE, 
				StandardWatchEventKinds.ENTRY_MODIFY);
		// 감시 실행
		while(true) {
			// 등록한 이벤트 발생 시 WatchKey로 반환
			WatchKey key = watch.take();
			// 이벤트 추출, ?는 와일드 카드 타입
			List<WatchEvent<?>> list = key.pollEvents();
			// 상세 내용을 추출
			for(WatchEvent e: list) {
				// 이벤트 상세 내용
				Kind evtKind = e.kind();
				Path evtPath = (Path) e.context();
				System.out.println(evtKind);
				System.out.println(evtPath);
			}
			// 다 쓰고난 이벤트 키는 리셋 해 주어야 한다.
			// reset을 하지 않으면 감시가 일회성으로 끝난다.
			// false : 초기화 실패, 해당 디렉토리가 사라진 경우
			boolean success = key.reset();
			System.out.println(success);
		}
	}

}



5. Path를 이용한 Write Read Copy


위에 사용한 Path를 이용하여 파일을 만들거나 읽거나 복사하는 기능


쓰기


package chap11.exam14.fileRW;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Scanner;

public class fileWriteEx {

	public static void main(String[] args) throws Exception{
		// 파일 위치 지정
		Path path = Paths.get("c:/img/write.txt");
		// 쓰기 할 값 입력 받기
		Scanner scan = new Scanner(System.in);
		System.out.println("아무거나 입력하세요!");
		String txt = scan.nextLine() + "\r\n";
		// 스트림 준비 + 쓰기
		Files.write(path, txt.getBytes(), StandardOpenOption.APPEND);
		System.out.println("저장 되었습니다.");
		// 자원반납(flush, close) - 생략
	}

}


읽기


package chap11.exam14.fileRW;

import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;

public class FileReadEx {

	public static void main(String[] args) throws Exception {
		// 1. 경로
		Path path = Paths.get("C:/img/asd.txt");
		// 2. 스트림 생성		// 3. 읽기
		List<String> contents = Files.readAllLines(path, Charset.forName("UTF-8"));

		// 4. 출력
		for(String line : contents) {
			System.out.println(line);
		}
	}

}


복사


package chap11.exam14.fileRW;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

public class FileCopyEx {
	// 파일 복사
	public static void main(String[] args) throws Exception {
		// 읽어와서 -> 쓰기
		// 파일 지정
		Path from = Paths.get("c:/img/10multi.pdf");
		Path to = Paths.get("c:/img/temp/10multicopyFile");
		// 스트림 + 읽기 + 읽어온 값 쓰기
		Files.copy(from,  to, StandardCopyOption.REPLACE_EXISTING);
		System.out.println("파일 복사 완료");
		// REPLACE_EXISTING : 기존 파일이 있으면 덮어쓰기
		// COPY_ATTRIBUTES : 파일의 모든 속성 복사(권한, 읽기 전용)
		// 자원 반납
	}

}


Data Stream은 .dat 파일을 만들 때 사용하는 스트림으로 


특징은 dat 파일을 읽기 위해서는 어떤 타입이 어떤 순서로 들어있는지 알아야 읽을 수 있기 때문에


쉽게 읽어올 수 없다는 특징을 가진다.



package chap11.exam10.data;

import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class DataOutput {

	public static void main(String[] args) throws Exception {
		// 자료형을 유지해서 파일에 쓰기
		// 1. 파일 위치 설정
		String path = "C:/img/data.dat";
		// 2. 스트림 준비(보조)
		FileOutputStream fos = new FileOutputStream(path);
		BufferedOutputStream bos = new BufferedOutputStream(fos);
		DataOutputStream dos = new DataOutputStream(bos);
		
		// 3. 쓰기
		dos.writeUTF("aaa");
		dos.writeInt(1000);
		dos.writeBoolean(true);
		
		// 4. 비우기
		dos.flush();
		
		// 5. 닫기
		dos.close();
		bos.close();
		fos.close();
	}

}


package chap11.exam10.data;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.FileInputStream;

public class DataInput {

	public static void main(String[] args) throws Exception {
		
		// 1. 파일 위치 설정
		String path = "C:/img/data.dat";
		// 2. 스트림 준비(보조)
		FileInputStream fis = new FileInputStream(path);
		BufferedInputStream bis = new BufferedInputStream(fis);
		DataInputStream dis = new DataInputStream(bis);
		
		// 3. 읽기 (파일에 있는 타입들을 알아야 하고
		// 입력한 순서대로 불러야 한다.)
		// 4. 출력
		System.out.println("이름 : " + dis.readUTF());
		System.out.println("급여 : " + dis.readInt());
		System.out.println("승진대상 : " + dis.readBoolean());
		
		
		
		// 5. 닫기
		dis.close();
		bis.close();
		fis.close();
	}

}



다양한 스트림들은 다양한 타입을 다루기에는 적절하지 않고 보통 하나에 특화 되어 있다.


그러나 Object Stream은 데이터 타입의 최상위 객체인 Object를 의미하는 보조 스트림으로


다양한 데이터 타입 뿐만 아니라 객체, 배열, 컬렉션 등 다양한 형태가 들어 갈 수 있다.


하지만 클래스의 경우는 직렬화를 하지 않으면 전달되지 않는다.


직렬화는 전달 할 데이터를 바이트로 바꿔서 나열하는 것이다.


다음 예제는 dat 파일을 만들어 읽는데 Sample이라는 클래스도 함께 전달하는 예제이다.



package chap11.exam11.obj;

import java.io.Serializable;
// 직렬화 인터페이스를 통해 모양을 잡아 준다.
public class Sample implements Serializable {
	/**
	 * 통신 시 사용하는 일련번호 serialVersionUID
	 * 객체 통신을 위한 일련번호
	 */
	private static final long serialVersionUID = 1L;
	int num = 11;
	String team = "edu";
	String job = "manager";
	
	public String method() {
		return "메소드 호출";
	}
}



package chap11.exam11.obj;

import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;
import java.util.Map;

public class ObjOutput {

	public static void main(String[] args) throws Exception {
		// 1. 파일 위치 설정
		String path = "C:/img/temp/obj.dat";
		// 2. 스트림 준비(보조)
		FileOutputStream fos = new FileOutputStream(path);
		DataOutputStream dos = new DataOutputStream(fos);
		ObjectOutputStream oos = new ObjectOutputStream(dos);
		// 3. 쓰기
		// - Map으로
		Map<String, String> map = new HashMap<>();
		map.put("name",  "kim");
		map.put("phone", "010-1234-5678");
		oos.writeObject(map);
		// - Array로
		oos.writeObject(new int[] {90, 95, 90, 100});
		// - String으로
		oos.writeUTF("기본형도 가능");
		// - Instance Object, 객체화하여 넣기
		oos.writeObject(new Sample());
		// 4. 비우기
		oos.flush();
		// 5. 자원 반납
		oos.close();
		dos.close();
		fos.close();
	}

}



package chap11.exam11.obj;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.util.Map;
import java.util.Set;

public class ObjInput {

	public static void main(String[] args) throws Exception {
		// 1. 경로 설정
		String path = "C:/img/temp/obj.dat";
		
		// 2. 스트림 생성
		FileInputStream fis = new FileInputStream(path);
		BufferedInputStream bis = new BufferedInputStream(fis);
		ObjectInputStream ois = new ObjectInputStream(bis);
		
		// 3. 읽기 
		Map<String, String> map = (Map<String, String>)ois.readObject();
		int [] scores = (int[])ois.readObject();
		String msg = (String)ois.readUTF();
		Sample sample = (Sample)ois.readObject();
		
		// 4. 출력하기
		Set<String> set = map.keySet();
		for(String key : set) {
			System.out.println(key + " : " + map.get(key));
		}
		
		for(int i = 0; i < scores.length; i++) { System.out.println(scores[i]); }
		
		System.out.println(msg);
		
		System.out.println("sample : " + sample.num);
		System.out.println("sample : " + sample.job);
		System.out.println("sample : " + sample.team);
		System.out.println("sample : " + sample.method());
		
		// 4. 해제
		ois.close();
		bis.close();
		fis.close();
	}

}





Prop은 Properties의 줄임말로 보통 Java Project 내부에서 읽고 쓰기를 한다.


프로그램의 내부에서 사용하기 때문에 환경 설정, 저장한 데이터 등의 데이터를 저장한다.


Properties는 map 인터페이스를 상속받은 자료 구조이다.


다음 예제를 확인해보자. 예제를 실행 하면 클래스 파일 옆에 Properties 파일이 생성된다.



package chap11.exam12.prop;

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.util.Properties;

public class PropWriter {

	public static void main(String[] args) throws Exception {
		// 1. 파일 위치 지정
		String path = "src/chap11/exam12/prop/profile.properties";
		
		// 2. Properties 객체 준비
		Properties pro = new Properties();
		
		// 3. 객체에 값 추가 (무엇을 넣어도 문자열로 넣어버림
		pro.put("1", "1111");
		pro.put("2", "2222");
		pro.put("3", "3333");
		pro.put("4", "4444");
		pro.put("5", "5555");
		
		// 4. 스트림 준비
		FileOutputStream fos = new FileOutputStream(path);
		BufferedOutputStream bos = new BufferedOutputStream(fos);
		
		// 5. 저장(스트림, 주석)
		pro.store(bos, "simple Comment");
		System.out.println("저장 완료");
		
		// 6. 자원 반납
		bos.close();
		fos.close();
	
	}

}



package chap11.exam12.prop;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Properties;

public class PropReader {

	public static void main(String[] args) throws Exception {
		// 1. 불러올 파일 위치 지정
		String path = "";
		// jar로 배포하고나면 사용자마다 경로가 상이하므로
		// 특정 클래스를 기준으로 리소스를 호출해야 한다.
		// 1-1. 경로를 가져오는 방법
//		path = PropReader.class.getResource("profile.properties").getPath();
//		System.out.println(path);
		// 1-2. 스트림으로 직접 불러오는 방
		InputStream is = PropReader.class.getResourceAsStream("profile.properties");
		
		// 2. 프로퍼티 객체 준비
		Properties pro = new Properties();
		
		// 3. 스트림 준비
		BufferedInputStream bis = new BufferedInputStream(is);
		
		// 4. 읽어오기
		pro.load(bis);
		
		// 5. 객체에서 값을 하나씩 추출
		System.out.println(pro.get("1"));
		System.out.println(pro.get("2"));
		System.out.println(pro.get("3"));
		System.out.println(pro.get("4"));
		System.out.println(pro.get("5"));
		
		// 6. 자원 반납
		bis.close();
		is.close();
		
		// 간단한 설정에 좋음, 보안성이 안좋음(전부 String)
		
	}

}



보조 스트림은 다른 스트림에게 스트림을 전달하는 기능이다.


일반적으로 스트림 자체가 기능이 하나만 특화되어 매우 한정적인데


다른 스트림에 전달 함으로써 다른 기능을 사용 할 수 있다.


하지만 Stream 선언이 늘어 난 만큼 close로 해제도 제때 해주어야 한다.


다음 예제는 File Stream을 Input, Output Stream에 전달한 예제이다.



package chap11.exam08.string;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;

public class TextFileCopy {

	public static void main(String[] args) throws Exception {
		// 1. 경로 설정
		String ori = "C:/img/asd.txt";
		String target = "C:/img/temp/asd.txt";
				
		// 2. 스트림 준비
		// 보조스트림 - 바이너리 기반의 스트림에 문자열 특화 기능 추가
		FileInputStream fis = new FileInputStream(ori);
		InputStreamReader reader = new InputStreamReader(fis, "UTF-8");
		
		FileOutputStream fos = new FileOutputStream(target);
		OutputStreamWriter writer = new OutputStreamWriter(fos, "UTF-8");
		
		// 3. 읽어오기
		char[] arr = new char[100];
		while(reader.read(arr) != -1) {
			writer.write(arr);	// 4. 내보내기
		}

		// 5. 자원반납(flush, close)
		writer.flush();
		reader.close();
		writer.close();
		fis.close();
		fos.close();
		
	}

}






기존의 스트림이 하나씩 하나씩 데이터를 들고 왔다면


Buffer Stream은 데이터를 한꺼번에 여러개씩 들고, 한꺼번에 전송 할 수 있도록 해 주는 임시 저장소이다.


그만큼 속도도 확연하게 차이나게 된다.


다음 예제는 데이터를 하나씩 받았을 때와 


Buffer Stream을 이용해 Byte 배열 덩어리로 한꺼번에 받았을 때의 속도를 비교하는 코드이다.


TimeChecker chk = new TimeChecker는 클래스 파일을 새로 만들어 선언한 클래스이고, 시간을 체크하는 기능을 간단하게 만들었다.


버퍼를 사용하지 않을 때


package chap11.exam09.buffer;

import java.io.FileInputStream;
import java.io.FileOutputStream;

public class BufferNotUse {

	public static void main(String[] args) throws Exception {

		TimeChecker chk = new TimeChecker();
		// 1. 파일 위치 지정
		String ori = "C:/img/10multi.pdf";
		String target = "C:/img/temp/NotuseCopy.pdf";
		
		// 2. 스트림 준비
		FileInputStream fis = new FileInputStream(ori);
		FileOutputStream fos = new FileOutputStream(target);
		int data;
		chk.timeStart();
		
		// 3. 읽기
		while((data = fis.read()) != -1) {
			System.out.println("복사중...");
			fos.write(data); // 4. 쓰기(시간 체크)
		}
		
		// 5. 비우고 반납
		fos.flush();
		// 15667ms 걸림, 15.6초
		System.out.println("완료 : " + chk.timeStop() + " ms");
		fis.close();
		fos.close();
	}

}


버퍼를 사용 할 때


package chap11.exam09.buffer;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.Buffer;

public class BufferUse {
	
	// try-with-resource == 트라이문이 끝나면 아래에 소켓 버퍼 등 close를 할 필요가 없음.
	public static void main(String[] args) throws Exception {
		TimeChecker chk = new TimeChecker();
		// 1. 파일 위치 지정
		String ori = "C:/img/10multi.pdf";
		String target = "C:/img/temp/useCopy.pdf";
		
		// 2. 스트림 준비(보조 스트림)
		try(  // 트라이가 끝나면 자동으로 close가 된다.
				FileInputStream fis = new FileInputStream(ori);
				BufferedInputStream bis = new BufferedInputStream(fis);
				
				FileOutputStream fos = new FileOutputStream(target);
				BufferedOutputStream bos = new BufferedOutputStream(fos);
			){
			byte[] arr = new byte[1024];
			chk.timeStart();
			while(bis.read(arr) != -1 ) {
				bos.write(arr);
			}
			// 5. 비우고 반납
			bos.flush();
			// 15667ms 걸림, 15.6초
			// 6044ms 걸림, 6초 (data를 배열로 받지 않았을 때)
			// 4ms 걸림, 0.004초 (byte[]배열로 받았을 때)
			System.out.println("완료 : " + chk.timeStop() + " ms");
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}
	
	
//	public static void main(String[] args) throws Exception {
//
//		TimeChecker chk = new TimeChecker();
//		// 1. 파일 위치 지정
//		String ori = "C:/img/10multi.pdf";
//		String target = "C:/img/temp/useCopy.pdf";
//		
//		// 2. 스트림 준비(보조 스트림)
//		FileInputStream fis = new FileInputStream(ori);
//		BufferedInputStream bis = new BufferedInputStream(fis);
//		
//		FileOutputStream fos = new FileOutputStream(target);
//		BufferedOutputStream bos = new BufferedOutputStream(fos);
//		
//		byte[] arr = new byte[1024];
//		chk.timeStart();
//		while(bis.read(arr) != -1 ) {
//			bos.write(arr);
//		}
//		
//		
//		
//		
//		
//		
//		
//		
////		int data;
////		chk.timeStart();
////		
////		// 3. 읽기
////		while((data = bis.read()) != -1) {
////			System.out.println("복사중...");
////			bos.write(data); // 4. 쓰기(시간 체크)
////		}
//		
//		// 5. 비우고 반납
//		bos.flush();
//		// 15667ms 걸림, 15.6초
//		// 6044ms 걸림, 6초 (data를 배열로 받지 않았을 때)
//		// 4ms 걸림, 0.004초 (byte[]배열로 받았을 때)
//		System.out.println("완료 : " + chk.timeStop() + " ms");
//		bos.close();
//		bis.close();
//		fis.close();
//		fos.close();
//	}

}


시간을 체크 할 타이머


package chap11.exam09.buffer;

public class TimeChecker {
	long start = 0;
	long end = 0;
	
	public void timeStart() {
		start = System.currentTimeMillis();
	}
	
	public long timeStop() {
		end = System.currentTimeMillis();
		return end-start;
	}
}



2번째 코드에서 try catch 문의 try 앞에 괄호가 추가 되었는데


괄호 안에 Stream을 선언하였을 경우 


try catch문이 끝났을 때 자동으로 close, 해제가 된다. (아래 복사)



		// 2. 스트림 준비(보조 스트림)
		try(  // 트라이가 끝나면 자동으로 close가 된다.
				FileInputStream fis = new FileInputStream(ori);
				BufferedInputStream bis = new BufferedInputStream(fis);
				
				FileOutputStream fos = new FileOutputStream(target);
				BufferedOutputStream bos = new BufferedOutputStream(fos);
			){
			byte[] arr = new byte[1024];
			chk.timeStart();
			while(bis.read(arr) != -1 ) {
				bos.write(arr);
			}
			// 5. 비우고 반납
			bos.flush();
			// 15667ms 걸림, 15.6초
			// 6044ms 걸림, 6초 (data를 배열로 받지 않았을 때)
			// 4ms 걸림, 0.004초 (byte[]배열로 받았을 때)
			System.out.println("완료 : " + chk.timeStop() + " ms");
			
		} catch (Exception e) {
			e.printStackTrace();
		}





File class는 I/O에 해당하는 클래스가 아니다.


하지만 File을 읽어오거나 쓸 때 사용하며 이 기능을 사용 할 때 Stream과 함께 사용된다.


일반적으로


1. 파일 객체를 만들어 읽어올 경로를 설정하고


2. 읽어올 파일을 Input Stream에 집어 넣고


3. 프로그램에서 Stream을 이용해 작업 한 후


4. 작업한 데이터를 Output Stream에 집어 넣고


5. 파일 객체 만들어 파일을 만들 경로를 설정하여 내보냄


내보낼 때에는 File Input Stream, File Output Stream을 사용한다.



다음 예제는 File 객체의 메소드를 활용한 예제이다.



package chap11.exam04.file;

import java.io.File;

public class FileMain {

	public static void main(String[] args) throws Exception {
		// 폴더 만들기 - File 객체 사용
		File dir = new File("c:/img/temp");
		if(!dir.exists()) { // 폴더가 존재 하지 않을 경우
			System.out.println("폴더 생성");
			dir.mkdirs();
		}		
		
		// 파일 만들기 - File 객체 사용
		 File file = new File("C:/img/temp/test.txt");
		 if(!file.exists()) {
			 System.out.println("파일 생성");;
			 file.createNewFile();
		 }

		 // 폴더 또는 파일에 대한 정보 - File 객체 사용
		 dir = new File("c:/img");
		 // 폴더에 해당하는 파일명
		 String[] fileNames = dir.list();
		 for(String name : fileNames) {
			 System.out.println(name);
		 }
		 
		 // 파일 객체를 뽑아내기
		 File[] files = dir.listFiles();
		 String gubun;
		 for(File f : files) {
			 if(f.isDirectory()) {
				 System.out.println("true");
				 gubun = "[디렉토리]";
			 } else {
				 gubun = "[파일]";
			 }
			 System.out.println(gubun + " " + f.getName() + " / " + f.length() + "byte");
		 }
	}

}


package chap11.exam05.fileinput;

import java.io.File;
import java.io.FileInputStream;

public class FileInputMain {

	public static void main(String[] args) throws Exception {
		// 1. 읽어올 파일 위치 지정
		String path = "C:/img/temp/test.txt";
		
		// 2. 파일 객체 생성
		File file = new File(path);
		
		// 3. 스트림 준비(빨대)
		// FileInputStream은 파일 특화이고 생성자 경로를 문자열로 넣어도 됨
		FileInputStream fis = new FileInputStream(file);
		// fis = new FileInputStream(path);
		
		// 4. 빨아 들인다.
		int data;
		while((data = fis.read())!=-1) { // -1 == EOF
			// 5. 출력(시스템안에서 이루어짐)
			System.out.print((char)data);
		}

		
		// 6. 닫아준다.(빨대 치우기)
		fis.close();
	}

}



package chap11.exam05.fileinput;

import java.io.FileInputStream;
import java.io.FileOutputStream;

public class FileOutputMain {

	public static void main(String[] args) throws Exception {
		// 1. 파일 위치 선정(읽어올 곳, 내보낼 곳)
		String pathInput = "C:/img/001.jpg";
		String pathInput2 = "C:/img/10multi.pdf";
		String pathOutput = "C:/img/temp/food.jpg";
		String pathOutput2 = "C:/img/temp/10multi_copy.pdf";
		// 2. 스트림 준비(input, output)
		FileInputStream fis = new FileInputStream(pathInput);
		FileOutputStream fos = new FileOutputStream(pathOutput);
		FileInputStream fis2 = new FileInputStream(pathInput2);
		FileOutputStream fos2 = new FileOutputStream(pathOutput2);
		// 3. 읽어오기
		int data;
		int i = 0;
		
//		while((data = fis.read())!=-1) { // -1 == EOF
//			// 4. 내보내기
//			fos.write(data);
//			i++;
//			System.out.println("파일 복사중... " + i);
//		}
		
		// 속도 향상을 위해 배열 사용
		byte[] arr = new byte[1024];
		while(fis2.read(arr)!=-1) { // -1 == EOF
			// 4. 내보내기
			fos2.write(arr);
			i++;
			System.out.println("파일 복사중... " + i);
		}
		
		System.out.println("복사 완료");
		// 5. flush, close
		fis.close();
		fos.flush();
		fos.close();
		fis2.close();
		fos2.flush();
		fos2.close();
	}

}



다음 예제는 File Reader와 File Writer을 이용한 예제이다.


Writer와 Reader는 문자형 특화로 txt 파일을 만들 때 자주 쓰인다.





package chap11.exam06.charIO;

import java.io.FileReader;

public class TextInput {

	public static void main(String[] args) throws Exception {
		// 1. 파일 위치 지정
		String path = "C:/img/asd.txt";
		// 2. 스트림 준비
		FileReader fr = new FileReader(path);
		// 3. 읽어오기
		char[] arr = new char[100];
		
		while(fr.read(arr)!=-1) { // -1 == EOF
			String data = new String(arr);
			// 4. 출력하기
			System.out.println(data);
			// System.out.print(arr);
		}

		
		// 5. 자원닫기
		
	}

}


package chap11.exam06.charIO;

import java.io.FileWriter;

public class TextOutput {

	public static void main(String[] args) throws Exception {
		// 1. 파일 위치 설정
		String fileName = "C:/img/temp/write.txt";
		// 2. 스트림 준비
		// append 인자 - 이어쓰기 여부
		FileWriter fw = new FileWriter(fileName, true);
		// 3. 쓰기
		System.out.println("저장 시작");
		fw.write("for 문 시작 \r\n");
		for(int i = 1; i <= 10; i++) {
			fw.write("for 문 증가 : " + i + "\r\n");
		}
		fw.write("for 문 종료\r\n");
		// 4. flush, close
		System.out.println("저장 종료");
		fw.flush();
		fw.close();
		
		// 실행을 두 번 해보면 데이터가 새로 쓰이지 않고 축적된다.
		// append를 true값으로 해서
	}

}


package chap11.exam07.test;

import java.io.FileWriter;
import java.util.Scanner;

public class WriteTest {

	public static void main(String[] args) throws Exception {
		// 1. 파일 위치 설정
		String fileName = "C:/img/temp/testkey.txt";
		
		// 2. 스캐너 준비
		Scanner scan = new Scanner(System.in);
		
		// 3. Writer 준비
		// append 인자 - 이어쓰기 여부
		FileWriter fw = new FileWriter(fileName, true);
		
		// 4. 읽어오기
		String temp = "";
		System.out.println("저장 시작");
		while(true) {
			System.out.println("추가할 문장을 입력하세요.(end test 입력 할 경우 끝남)");
			temp = scan.nextLine();
			if (temp.equals("end test")) { break; }
			else {
				// 5. 내보내기
				fw.write(temp);
				fw.write("\r\n");
				fw.flush();
			}
		}
		
		// 6. 자원 종료
		System.out.println("저장 종료");
		fw.close();
	}

}


InputStream과 OutputStream을 이용하여 콘솔에 간단한 입력과 출력을 해보자


package chap11.exam01.sysio;

import java.io.IOException;
import java.io.InputStream;

public class SysInput {

	public static void main(String[] args) {
		System.out.println("아무거나 입력 하세요!");

		InputStream in = System.in;

		try {
			char a = (char)in.read();
			System.out.println(a);
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}



package chap11.exam01.sysio;

import java.io.OutputStream;

public class SysOutput {

	public static void main(String[] args) throws Exception {
		OutputStream os = System.out;
		
		for(byte b = 97; b <= 122; b++) {
			os.write(b); // 바이너리를 내부적으로 처리 (파일 처리용)
//			System.out.println((char)b); // 외부로 출력
		}
		os.flush(); // flush가 없으면 출력이 안 될 수도 있다.
//		os.close(); // 여기서 close를 하면 밑에서 다시 객체화하여도 사용할 수 없음
		
		System.out.println();
		
		
		// 문자열을 배열로 만들어서 출력
		String hangul = "가나다라마바사아자차카타파하";
		
		byte[] aa = hangul.getBytes();
//		for(int i = 0; i < aa.length; i++) {
//			System.out.println((char)aa[i]);
//		}
		os.write(aa);
		// 단일 스레드에서 여러 개의 스트림을 다룰 수 없다.
		os.flush(); // flush가 없으면 출력이 안될 수도 있다.
		os.close();
	}

}


flush는 (변기의)물을 내리다 라는 의미를 가지고 있는데 


Stream을 flush하다 라고 이해하면 쉽다.


현재 메모리에 Stream이 그대로 흘러와 담겨있는데


flush하여 데이터를 뿌려준다고 할 수 있다.


그리고 Stream을 close 한다면 메모리를 반환하게 된다.


close를 한번 한 스트림은 다시 객체화 하여도 사용 할 수 없게 된다.










Console 클래스는 여태껏 사용해온 콘솔창의 입력 받은 문자를 쉽게 읽을 수 있는 클래스이고 cmd(Windows 커맨드 창)에서 실행된다.


Console은 정수, 실수 값을 바로 읽어 들이지 못하기 때문에 Scanner 클래스와 함께 이용하면 쉽게 사용가능하다.


여태껏 사용해온 Scanner scan = new Scanner(System.in);과 같다.




package chap11.exam02.console;

import java.io.Console;

public class Main {

	public static void main(String[] args) {
		// cmd에서만 실행 가능
		// 프로젝트 내 bin 폴더 > java [패키지이름.실행클래스] (경로)
		// 입력 순서 ex
		// d:
		// D:\JAVA\Chapter11\bin
		// java chap11.exam02.console.Main
		
		Console console = System.console();
		
		System.out.print("아이디 : ");
		String id = console.readLine();
		System.out.print("비번 : ");
		char[] pw = console.readPassword();
		String pass = new String(pw);
		System.out.println("---------------------");
		System.out.println("ID : " + id);
		System.out.println("PW : " + pass);
		
	}

}



콘솔 창으로 실행하는 방법은 https://qdgbjsdnb.tistory.com/79?category=715136 에서 확인하자





Scanner은 딱히 설명 할 것이 없으므로 예제만 올려보겠습니다.



package chap11.exam03.scanner;

import java.util.Scanner;

public class ScanMain {

	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		
		System.out.print("문자열 입력>");
		String inputStr = scan.nextLine();
		System.out.println(inputStr);
		
		System.out.print("정수 입력>");
		int inputInt = scan.nextInt();
		System.out.println(inputInt);
		
		System.out.print("실수 입력>");
		double inputDouble = scan.nextDouble();
		System.out.println(inputDouble);
		
	}

}




Stream이란 사전적 의미로는 '줄줄 흐르다', 즉 흘러가는 흐름을 말하는데


Input Output도 마찬가지다.


데이터를 불러오는데 읽어들어오는 흐름과 내보내는 흐름이라고 이해하면 쉽다.




C:\temp\data.dat


위의 파일을 inputStream으로 불러온다고 하면


C:\temp\data.dat 이 경로에서 나의 작업 공간으로 데이터가 흘러온다.


현실에 비유한다면


산(C:\temp\data.dat)에서 강물이 도시(작업 공간)로 흘러 들어온다.


Output도 역으로 생각하면 된다.





이 흐름은 Byte, 바이트 형식으로 흘러오거나 Character, 문자 형식으로 흘러온다.


Byte형식은 InputStream, OutputStream이고


Character형식은 Reader와 Writer로 사용한다.





InputStream은 Byte 형식의 흐름의 최상위 객체로 FileInputStream, BufferedInputStream, DataInputStream 등


각각 용도에 특화된 InputStream의 자식 객체가 있다.


다음 게시글을 통해 다양한 스트림의 활용을 확인해보자




+ Recent posts