-
JAVA IO (데이터 입출력)JAVA 2022. 10. 7. 09:41
java에서는 외부 system의 data도 다룰 수 있다.
system 안으로 또는 밖으로 이동하는 data의 흐름을 stream이라고 한다.
java.io package는 크게 InputStream과 OutputStream이 있다.
byte 기반과 문자 기반이 있다.
java.io package InputStream
FileInputStream, BufferedInputStream, DataInputStream이 하위에 있다.
OutputStream
FileOutputStream, BufferedOutputStream, DataOutputStream이 하위에 있다.
File I.O
File 클래스는 java에서 파일과 폴더를 다룰 수 있는 객체이다.
폴더 만들기 : mkdir()
파일 만들기 : createNewFile()
폴더, 파일 삭제하기 : delete()
폴더 여부 : isDirectory()
package chap11.ex02.file; import java.io.File; import java.io.IOException; public class FileMain { public static void main(String[] args) throws IOException { // 폴더 만들기 File dir = new File("C:/img/temp"); //System.out.println(dir.exists()); // 해당 파일이나 폴더가 존재하는지 확인 if(!dir.exists()) { System.out.println("해당 폴더가 존재하지 않습니다."); dir.mkdirs(); // 폴더들을 생성 } //파일 만들기 File file = new File("C:/img/temp/test.txt"); if(!file.exists()) { System.out.println("해당 파일이 존재하지 않습니다."); file.createNewFile(); } // 폴더 정보 알아보기 File folder = new File("C:/"); // 파일명 뽑아내기 (폴더인지 파일인지 알려주지 않고 이름만 알려준다.) /* String[] files = folder.list(); for (String name : files) { System.out.println(name); } */ File[] files = folder.listFiles(); // File 객체에는 파일 및 디렉토리에 대한 모든 정보가 있다. String gubun = ""; for (File f : files) { //System.out.println("디렉토리 여부 : " + f.isDirectory()); if(f.isDirectory()) { gubun = "[디렉토리]"; }else { gubun = "[파일]"; } System.out.println(gubun +" "+ f.getName() + "\t" + (f.length()) + " Byte"); } } }
File I.O를 활용하려면 특화된 FileInputStream과 FileOutputStream을 사용하면 된다.
밖으로 내보낼 때(Output)는 flush()를 통해 데이터를 모두 내보내야 한다.
Stream을 사용한 후에는 close()를 통해 자원을 닫아줘야 한다.
File InputStream 순서
파일 위치 지정
스트림 준비
읽어오기
자원 닫기
File OutputStream 순서
파일 위치 선정
스트림 준비
쓰기
자원 닫기
보조 스트림
다른 스트림과 연결하여 추가 기능을 해주는 스트림이다.
보조 스트림은 계속하여 붙일 수 있다.
package chap11.ex03.fileInput; import java.io.FileInputStream; import java.io.InputStreamReader; public class FileInputMain { public static void main(String[] args) throws Exception { // 1. 읽어올 파일 위치 설정 + 2. 파일 객체화 + 3. 읽어올 스트림 준비 FileInputStream fis = new FileInputStream("C:/img/temp/test.txt"); // 4. 읽어오기 (한글은 다 깨진다 == 바이너리 전문이지 문자 전문이 아니다.) int data; // 왜 int? int == byte == binary /* while((data = fis.read()) != -1) { // -1은 End Of File System.out.print((char)data); } */ // 한글이 안 깨지려면 문자 전문 스트림 사용 InputStreamReader reader = new InputStreamReader(fis, "UTF-8"); while((data = reader.read()) != -1) { // -1은 End Of File System.out.print((char)data); } // 5. 다 읽었으면 스트림 반납 fis.close(); } }
package chap11.ex03.fileInput; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; public class FileOutputMain { public static void main(String[] args) throws Exception { // 1. 읽어올 위치와 내보낼 위치 지정 + 2. 스트림 준비 (input/output) FileInputStream fis = new FileInputStream("C:/img/img1.jpg"); FileOutputStream fos = new FileOutputStream("C:/img/temp/copy.jpg"); // 3. 읽어오기 int data; int i=0; while((data=fis.read()) != -1) { // fis에서 가져오는 값을 data에 저장하고 data가 -1이 될 때까지 반복 fos.write(data); // 4. 읽어온 파일 쓰기 i++; //성능 체크용 System.out.println("파일 복사중 : " + i); } /* //속도 향상을 위해서 티스푼으로 옮기던 것을 컵으로 바꿔보자 byte[] arr = new byte[1024]; while(fis.read(arr) != -1) { fos.write(arr); i++; //성능 체크용 System.out.println("파일 복사중 : " + i); } */ //5. 자원 정리 (flush, close) fos.flush(); fis.close(); fos.close(); System.out.println("파일 복사 끝"); } }
문자 전용으로 문자가 깨지는 것을 방지하려면 Reader와 Writer를 사용하면 된다.
package chap11.ex04.charIO; import java.io.FileNotFoundException; import java.io.FileReader; public class TextInput { public static void main(String[] args) throws Exception { // 1. 읽어올 파일 위치 설정 + 2. 읽어 올 스트림 준비 FileReader reader = new FileReader("C:/img/temp/test.txt"); // 3. 읽어오기 int data; while((data = reader.read()) != -1) { System.out.print((char)data); } // 4. 자원 정리 reader.close(); } }
package chap11.ex04.charIO; import java.io.File; import java.io.FileWriter; import java.nio.charset.Charset; public class TextOutput { public static void main(String[] args) throws Exception { // 1. 파일 위치 지정 File file = new File("C:/img/temp/output.txt"); if(!file.exists()) { System.out.println("파일이 존재하지 않아 생성합니다."); file.createNewFile(); } // 2. 스트림 준비 // file을 UTF-8 캐릭터 셋에, 다음에 쓸 때 이어쓰기가 가능하도록 한다. FileWriter fw = new FileWriter(file, Charset.forName("UTF-8"), true); // true이면 이어쓰기, false이면 덮어쓰기 // 3. 쓰기 fw.write("저장 시작====== \r\n"); fw.write("Hello Java I.O. \r\n"); fw.write("저장 끝====== \r\n"); // 4. 자원 정리(flush, close) fw.flush(); fw.close(); System.out.println("저장 완료"); } }
* fileWriter에 scanner를 이용해보자
package chap11.ex05.test; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.nio.charset.Charset; import java.util.Scanner; public class ConsoleFile { public static void main(String[] args) throws IOException { // 파일 생성 File file = new File("C:/img/temp/sample.txt"); if(!file.exists()) { System.out.println("파일을 생성합니다."); file.createNewFile(); } // 내용 입력 System.out.println("내용을 입력하세요."); Scanner scan = new Scanner(System.in); // 스트림 생성 FileWriter fw = new FileWriter(file, Charset.forName("UTF-8"), true); // 쓰기 fw.write(scan.nextLine()+"\r\n"); // 자원 정리 fw.flush(); fw.close(); scan.close(); System.out.println("저장 완료"); } }
성능 향상 보조 스트림 (Buffer)
buffer는 전송받은 데이터들을 모아서 한 번에 전송해주는 임시 저장소이다.
버퍼 사용과 미사용은 차이가 크다.
* buffer를 사용하지 않을 때
package chap11.ex06.buffer; import java.io.FileInputStream; import java.io.FileOutputStream; public class BufferNotUse { public static void main(String[] args) throws Exception { // 1. 파일 위치 지정 + 2. 스트림 준비(input, output) FileInputStream fis = new FileInputStream("C:/img/img2.png"); FileOutputStream fos = new FileOutputStream("C:/img/temp/copy.png"); TimeChecker chk = new TimeChecker(); // 3. 읽어 오기 chk.timeStart(); int data; while((data = fis.read()) != -1) { fos.write(data);// 4. 읽은 내용 쓰기 } System.out.println("버퍼 미사용 : " + chk.timeStop() + "ms"); //24693ms // 5. 자원 정리(flush, close) fos.flush(); fis.close(); fos.close(); } }
* buffer를 사용했을 때
package chap11.ex06.buffer; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; public class BufferUse { public static void main(String[] args) throws Exception { // 1. 파일 위치 지정 + 2. 스트림 준비 FileInputStream fis = new FileInputStream("C:/img/img2.png"); FileOutputStream fos = new FileOutputStream("C:/img/temp/copy2.png"); // 1-1. 보조 스트림 준비 BufferedInputStream bis = new BufferedInputStream(fis); BufferedOutputStream bos = new BufferedOutputStream(fos); // 3. 읽어오기 TimeChecker chk = new TimeChecker(); chk.timeStart(); /* int data; while((data = bis.read()) != -1) { bos.write(data); // 4. 내용 쓰기 } */ byte[] arr = new byte[1024]; while(bis.read(arr) != -1) { bos.write(arr); } System.out.println("버퍼 사용 : " + chk.timeStop() + "ms"); //105ms -> 10ms // 5. 자원 정리 bis.close(); bos.flush(); bos.close(); } }
*시간을 재기 위한 클래스
package chap11.ex06.buffer; public class TimeChecker { long start=0; long end=0; /** * 시작 시 현재 시간 기준으로 ms로 환산한다. */ public void timeStart() { start = System.currentTimeMillis(); } /** * 종료 시 걸린 시간을 ms로 반환한다. * @return 시작과 종료 사이의 ms */ public long timeStop() { end = System.currentTimeMillis(); return end-start; } }
기본타입 입출력 보조 스트림
바이트 스트림은 기본 타입 데이터(int, String, long...)을 전송할 수 없다.
따라서 Data스트림을 사용하면 된다.
이 때 파일에 입력한 순서대로 값을 가져와야 한다.
쓸 때는 write~(), 읽을 때는 read~()를 사용하면 된다.
클래스는 보내지 못한다.
package chap11.ex07.data; import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; public class DataInput { public static void main(String[] args) throws Exception { // 자바 고유 데이터 타입을 파일로부터 불러온다. // 쓴 순서대로 불러와야 한다. (String, int, Boolean) // 1. 파일 경로 생성 + 2-1. 스트림 준비 FileInputStream fis = new FileInputStream("C:/img/temp/data.dat"); // 2-2. 스트림 준비 BufferedInputStream bis = new BufferedInputStream(fis); DataInputStream dis = new DataInputStream(bis); // 3. 읽어 오기 String name = dis.readUTF(); int salary = dis.readInt(); boolean promotion = dis.readBoolean(); System.out.println(name + "/" + salary + "/" + promotion); // 4. 자원 정리 dis.close(); } }
package chap11.ex07.data; import java.io.BufferedOutputStream; import java.io.DataOutputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; public class DataOutput { public static void main(String[] args) throws Exception { // 자바 고유의 데이터 타입을 파일로 내보낼 수 있다. // 1. 파일 경로 지정 + 2-1 주 스트림 준비 FileOutputStream fos = new FileOutputStream("C:/img/temp/data.dat"); // 2-2 보조 스트림 준비 BufferedOutputStream bos = new BufferedOutputStream(fos); DataOutputStream dos = new DataOutputStream(bos); // 3. 쓰기 (이름 String, 급여 int, 승진 boolean) dos.writeUTF("홍길동"); dos.writeInt(700); dos.writeBoolean(false); // 4. 자원 정리 dos.flush(); dos.close(); } }
Object Stream
Data Stream에서 클래스를 보내지 못하는 것을 보완한 것이 Object Stream이다.
객체, 배열, 클래스 등 모든 형태를 다룰 수 있다.
class 경우에는 보낼 때는 직렬화를 통해서, 가져올 때는 역직렬화를 통해서 전송할 수 있다.
보내려는 class는 반드시 Serializable 인터페이스를 구현 받아야 한다.
직렬화란?
규격을 통해서 Object를 쪼개서 전송하는 것. 역직렬화는 반대로 규격을 통해 Object를 다시 조립하여 받는 것
package chap11.ex08.obj; import java.io.Serializable; // 클래스 객체는 전송 시 직렬화가 필요하다. // 읽어들일 때는 역직렬화가 필요하다. // 클래스 객체는 반드시 Serializable 인터페이스가 구현되어 있어야 한다. // 왜? 인터페이스는 규격이다. 쪼개거나 합칠 때 규격이 있으면 훨씬 간편해진다. public class Sample implements Serializable { int num = 11; String team = "edu"; String job = "manager"; public String method() { return "method 호출하신 분?"; } }
package chap11.ex08.obj; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.ObjectInputStream; import java.util.HashMap; public class ObjInput { public static void main(String[] args) throws Exception { // 1. 파일 위치 지정 + 2-1. 주 스트림 준비 FileInputStream fis = new FileInputStream("C:/img/temp/obj.dat"); // 2-2. 보조 스트림 준비 BufferedInputStream bis = new BufferedInputStream(fis); ObjectInputStream ois = new ObjectInputStream(bis); // 3. 읽어오기 int num = ois.readInt(); String name = ois.readUTF(); int[] scores = (int[]) ois.readObject(); // Object가 최상위이기 때문에 캐스팅 HashMap<String, String> map = (HashMap<String, String>) ois.readObject(); Sample sample = (Sample) ois.readObject(); //일반 데이터 타입 System.out.println(num); System.out.println(name); //배열 System.out.println(scores[0]+" / "+scores[1] + " / "+ scores[2]+" / "+scores[3]); //해시맵 System.out.println(map); //클래스 System.out.println(sample.job + " / " + sample.num + " / " + sample.team); System.out.println(sample.method()); // 4. 자원 정리 ois.close(); } }
package chap11.ex08.obj; import java.io.BufferedOutputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.ObjectOutputStream; import java.util.HashMap; public class ObjOutput { public static void main(String[] args) throws Exception { // 클래스 객체를 제외한 나머지 타입은 기존 DataOutput과 사용법이 동일하다. // 클래스 타입 경우는 writeObject() 메소드를 사용한다. // 클래스 객체의 경우는 직렬화를 해야한다. // 1. 파일 위치 지정 + 2-1. 주 스트림 준비 FileOutputStream fos = new FileOutputStream("C:/img/temp/obj.dat"); // 2-2. 보조 스트림 준비 BufferedOutputStream bos = new BufferedOutputStream(fos); ObjectOutputStream oos = new ObjectOutputStream(bos); // 3. 쓰기 oos.writeInt(123); oos.writeUTF("홍길동"); // Array oos.writeObject(new int[] {90,95,90,100}); //map HashMap<String, String> map = new HashMap<>(); map.put("name", "kim"); map.put("phone", "010-1234-5789"); oos.writeObject(map); //class 객체 oos.writeObject(new Sample()); // 4. 자원 정리 oos.flush(); oos.close(); } }
properties
map 인터페이스를 구현받는 자료구조
프로퍼티즈 객체에 값을 넣고 (map이기 때문에 put()을 사용) store()를 통해 Stream으로 데이터를 보내야 한다.
이 때 store()가 flush() 역할을 해주므로 생략 가능하다.
프로퍼티즈 파일에서 값을 찾아오려면 InputStream으로 읽어온 데이터를 load()를 통해 프로퍼티즈 안으로 들어가고 일반적인 map의 형태(keySet()과 get())로 값을 찾아올 수 있다.
package chap11.ex09.prop; import java.io.BufferedOutputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.util.Properties; public class PropWrite { public static void main(String[] args) throws Exception { // 1. 파일 위치 지정 + 2. 스트림 준비 String path = "src/chap11/ex09/prop/profile.properties"; FileOutputStream fos = new FileOutputStream(path); // 2-2. 보조 스트림 준비 BufferedOutputStream bos = new BufferedOutputStream(fos); // 3. 파일 쓰기 Properties prop = new Properties(); // 3-1. 프로퍼티즈 객체 준비 // 3-2. 파일 내용 쓰기 prop.put("id", "admin"); prop.put("password", "1234"); prop.put("name", "kim"); prop.put("email", "admin@email.com"); prop.put("phone", "010-1111-2222"); // 3-3. 파일 내보내기 prop.store(bos, "simple comment"); // 내보낼 스트림, 주석 내용 // 4. 자원 정리 //bos.flush(); -> 프로퍼티즈가 자동으로 flush 기능까지 해서 생략 가능 bos.close(); } }
*생성된 properties 파일
#simple comment #Wed Sep 21 15:40:11 KST 2022 password=1234 phone=010-1111-2222 name=kim id=admin email=admin@email.com
package chap11.ex09.prop; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.util.Properties; public class PropRead { public static void main(String[] args) throws Exception { // 1. 파일 위치 지정 String path = "src/chap11/ex09/prop/profile.properties"; // 2. 스트림 준비(주, 보조) BufferedInputStream bis = new BufferedInputStream(new FileInputStream(path)); // 3. 파일 읽어오기 Properties prop = new Properties(); prop.load(bis); // InputStream으로 읽어 온 데이터가 프로퍼티즈 안으로 들어간다. for (Object key : prop.keySet()) { System.out.println(key + " = " + prop.get(key)); } // 4. 자원 정리 bis.close(); } }
'JAVA' 카테고리의 다른 글
Network (TCP, UDP) (0) 2022.10.07 JAVA NIO (0) 2022.10.07 thread 2 (스레드 제어~스레드 풀) (1) 2022.09.24 thread - 1 (스레드 생성~join) (1) 2022.09.24 컬렉션 프레임워크(List, Set, Map) (1) 2022.09.24