자바

[Java] I/O 입출력

Atriel 2023. 11. 23. 16:04

 

이미지 같은걸 처리할땐 바이트 기반 스트림을 사용한다.

 

 

PipedInputStream : 소스값이 파이프와 필터를 거치며 필요한 값을 추출 (마치 정수기의 물의 여과과정)

 

Source -> [pipe1] - [filter1] - [pipe2] - [filter2] - [pipe3] - [filter3] - Result

 

주로 프로세스를 다룰때 사용

 

FilterInputStream : 보조스트림으로 용도에 따라 4가지가 있음

       - BufferedInputStream

 

ByteArrayInputStream : 바이트로 구성된 Array를 읽어옴

StringbufferedInputStream : 문자열 읽어오는 스트림

 

 

 

 

 

InputStream

바이트 기반 입력스트림의 최상위 클래스로 추상클래스임

  -  FileInputStream

  -  BufferedInputStream

  -  DataInputStream

 

OutputStream

바이트 기반 출력 스트림의 최상위 클래스로 추상클래스임

 -  FileOutputStream

 -  BufferedOutputStream

 -  DataOutputStream

 -  PrintStream

 

flush() : DB의 commit()처럼 해당명령어를 통해 메모리에서 디스크로 내려줘야함

 

Reader

문자 기반 입력 스트림의 최상의 클래스, 추상 클래스

- FileReader

- InputStreamReader

- BufferedReader

 

Writer

문자 기반 출력 스트림의 최상의 클래스, 추상 클래스

- FileWriter

- OutputStreamWriter

- BufferedWriter

- printWriter

 

File Class

파일 시스템의 파일을 표현하는 클래스

File file = new File("파일 경로")

File file = new File("C:/Users....")

 

 

파일/ 디렉토리 메소드

리눅스와 유사함 (같은계열인 유닉스, 맥도 비슷)

 

                       생성 / 삭제

 

                       정보 리턴

 

 

 

FileInputStream / FileOutputStream

파일로 부터 바이트 단위로 읽을 때 사용

그림, 오디오, 비디오, 텍스트 파일등 모든 데이터로 파일로 저장

 

파일을 읽어올때 파일이 존재 하지 않으면 FileNotFoundException 오류가 뜨니 예외처리를 해주자

FileInputStream fis = new FileInputStream("C:/data/test.txt")

FileOutputStream fos = new FileOutputStream("C:/data/test.txt");

FileOutputStream fos = new FileOutputStream ("C:/data/test.txt", true); // 기존 파일에 이어서 작성

FileReader / FileWritter

텍스트 파일로 부터 문자단위로 읽을 때 사용

그림, 오디오, 비디오 등 파일은 읽기 불가능

 

파일을 읽어올때 파일이 존재 하지 않으면 FileNotFoundException 오류가 뜨니 예외처리를 해주자

FileReader fr = new FileReader("C:/data/test.txt");

FileReader fr = new FileReader(new File("C:/data/test.txt"));

FileWriter fw = new FileWriter("C:/data/test.txt"); 

FileWriter fw = new FileWriter("C:/data/test.txt", true);

 

 

 

 

보조스트림

 

자바의 장점!

자바가 스트림류에 특화되있어서 매우 빠름

기반 스트림을 먼저 생성한 후 이를 이용해 보조 스트림생성

( + NIO: 요즘은 잘 안쓰지만 성능을 좀더 향상시키기 위한다면 사용, 따로 공부해야함)

 

Java NIO에 대해 알아보자 (1/2)

NIO(New Input Output) Java NIO는 기존 IO 패키지를 개선하기 위해 나온 패키지다. 그럼 어떤것을 개선 하였을까? 위 그림은 Java에서 IO를 처리하는 전체적인 구조를 보여주는 그림이다. C/C++처럼 직접 메

velog.io

 

보조스트림의 종류

문자 변환(InputStreamReader/OutputStreamWriter),

입출력 성능(BufferedInputStream/BufferedOutputStream),

기본 데이터 타입 출력(DataInputStream, DataOutputStream),

객체 입출력(ObjectInputStream/ObjectOutputStream) 등의 기능을 제공하는 보조스트림이 있음

 

빨간색 하이라이트 부분만 다룰 예정..

객체 입출력은 자바의 상징적인 기능

 

■ 문자 변환 보조 스트림

Binary 스트림을 문자변환 보조 스트림을 통해 문자열(필요한 데이터)로 변환


 

  성능 향상 보조 스트림

입출력 소스를 그대로 사용하지않고 버퍼에 데이터 들을 모아서 한꺼번에 처리 -> 성능 향상

 

 

객체 입출력 보조 스트림

객체를 파일 or 네트워크로 입출력할수 있는 기능 제공

직렬화(Serialization) 필수!

-> 잘 안쓰는 이유.. 잘 안보인다!

Properties나 Json, XML을 사용하자

 

 

직렬화 / 역직렬화

 

직렬화 : Serializable 인터페이스를 implements 해서 구현

객체 직렬화 시 private 필드를 포함한 모든 필드를 바이트로 변환하지만 transient키워드를 사용한 필드는 직렬화에서 제외

◆ 자바에서 야심차게 내놨지만 잘 사용하지 않음

 

역직렬화: 직렬화된 객체를 역직렬화할 때는 직렬화 했을 때와 같은 클래스 사용 단, 클래스 이름이 같더라도 클래스 내용이 변경된 경우 역직렬화 실패

 

[FileBasic.java]

package com.multi.ex01.file;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Arrays;

public class FileBasic {
	// 파일 경로(Path)란?
	//  - File이 저장되어 있는 보조기억장치(HDD, SSD)의 실제 물리적인 경로(위치)
	
	// 절대 경로 vs 상대 경로
	
	// 1. 절대 경로 - 익숙한 것
	// - Root(윈도우-'c:\', 리눅스-'\')로 부터 표기되는 절대적인 경로
	// C:\dev_source\work_space_java_multi1030\13_IO\covid.txt
	// c:\test\data.txt
	// 빠르게 이스케이프 문자 적용하는 방법은 "" 안에 경로를 복사하는 것을 추천 ★★★★★
	
	// 2. 상대 경로
	// - 프로그램의 실행 위치(나)로부터 표기되는 상대적인 경로 '.'현재, '..'이전으로 표기되는 경로
	// - os console 명령어로부터 파생된 개념
	// - '.' : 현재 위치, '..' : 상위폴더(이전) 경로, './../../' 현재-상위-상위 경로
	// - ex) './covid.txt', 'covid.txt', './../14_IO/covid.txt'
	public static void main(String[] args) {
		// 상대 경로로 열기
//		File file1 = new File("./covid.txt"); // 상대 경로로 열림(open)
		File file1 = new File("covid.txt"); // 파일/폴더의 경로명
		
		// 절대 경로로 열기
//		File file2 = new File("C:\\dev_source\\work_space_java_multi1030\\13_IO\\covid.txt");
		File file2 = new File(file1.getAbsolutePath()); // 절대경로로 열기
		
		// 상대, 절대 경로 출력
		System.out.println(file1.getPath()); // 상대 경로
		System.out.println(file2.getPath()); // 절대 경로
		System.out.println(file1.getAbsolutePath()); // 상대여도 절대경로 보이는 방법
		System.out.println("------------------------------------------------");
		
		// 부모(상위 폴더)
		System.out.println(file1.getParent()); // 상대경로로 읽어서 부모를 찾을수 없다.
		System.out.println(file2.getParent());
		System.out.println("------------------------------------------------");
		
		// 권한 물어보기
		System.out.println(file1.canRead()); 	// 읽기 true
		System.out.println(file1.canWrite()); 	// 쓰기 true
		System.out.println(file1.canExecute()); // 실행 true
		System.out.println("------------------------------------------------");
		
		// 권한 설정 (윈도우는 쓰기 권한만 가능)
		file1.setWritable(false); // 읽기전용 만들기
		System.out.println(file1.canWrite()); 	// 쓰기 못함
		file1.setWritable(true);
		System.out.println(file1.canWrite()); 	// 쓰기 가능!
		System.out.println("------------------------------------------------");
		
		// 파일 이름 변경
//		File file = new File("./covid2.txt");
//		boolean result = file1.renameTo(file);
//		System.out.println(result);
		// 이클립스에서 파일구조가 변경되는 경우 반드시 새로고침을 해야 반영된다. F5
		
		// 수정된 시간 출력 -> 사용 이력
		System.out.println(file1.lastModified());
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
		System.out.println(sdf.format(file1.lastModified())); // 마지막 수정 시간
		
		// 파일 길이
		System.out.println(file1.length() + "byte");
		System.out.println(file1.length() / 1024 + "kbyte");
		System.out.println(file1.length() / 1024.0 / 1024.0 + "Mbyte");
		// byte, k, M, G, T, P -> 높아짐
		
		// 파일 삭제
//		file1.delete();
		
		// 디렉토리(폴더) 다뤄보기
		File folder = new File("./");
		if(folder.isDirectory()) {
			System.out.println("디렉토리 입니다.");
		}
		
		// 디렉토리가 가진 자식(파일+폴더) 가져오기
		System.out.println(Arrays.toString(folder.listFiles()));
		System.out.println(folder.listFiles());
	}
}

 

[StreamIO.java]

package com.multi.ex02.io_basic;

import java.io.InputStream;
import java.io.OutputStream;

public class StreamIO {
	// Stream이란? - (한방향 빨대다!)
	// - Binary(이진) 데이터를 다루는 Stream = 1byte씩 처리 가능
	// - 활용 : 이미지나 동영상 파일, 네트워크, 프로그램간 데이터 전송 때
	
	// IO 객체 사용시의 코딩 테크닉 - 고전 ver.
	// 1. 가장 윗단에 IO객체를 선언하고, null로 초기화한다. 이름은 앞글자를 줄여서 선언한다.
	// 2. try-catch문을 열고, e.printStackTrace 선언 및 finally 문 선언
	// 3. IO 객체를 오픈한다. -> try안에서
	// 4. 필요한 IO을 수행한다. 보통 while문으로 수행
	// 5. finally에 사용한 IO객체'들'을 정리한다.
	
	public static void main(String[] args) {
		InputStream is = null;
		OutputStream os = null;
		
		try {
//			is = new InputStream(); // InputStream은 abstract class라 생성 불가! 
			is = System.in; // open 코드를 대체하는 코드, 콘솔 입력
			os = System.out; // 콘솔 출력
			
			// 동작부
			System.out.println("숫자를 입력해주세요.");
			int read = is.read();
			os.write(read);
			// write를 강제화 하는 방법
			// 1. flush : write 도중에 데이터를 강제로 밀어내는 방법, 명시적으로 사용
			// 2. close : 자원을 정리하면서 flush와 동일하게 강제로 밀어내주는 기능
			os.flush();
		} catch (Exception e) {
			e.printStackTrace(); //개발할때만 남기고 운영할땐 지우는게 좋다. 빌드버전이 되면 코딩안되게 장치해놓는게 좋음
		} finally {
			if(is != null) {
				try {
					is.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			if(os != null) {
				try {
					os.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}
}

 

[StreamRW]

package com.multi.ex02.io_basic;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class StreamRW {
	// reader : 문자열 단위로 읽어오는 기능
	// writer : 문자열 단위로 쓰는 기능 
	// java에서 문자열은 2byte를 기준으로 함
	
	// IO 객체 사용시의 코딩 테크닉 - 고전 ver.
	// 1. 가장 윗단에 IO객체를 선언하고, null로 초기화한다. 이름은 앞글자를 줄여서 선언한다.
	// 2. try-catch문을 열고, e.printStackTrace 선언 및 finally 문 선언
	// 3. IO 객체를 오픈한다. -> try안에서
	// 4. 필요한 IO을 수행한다. 보통 while문으로 수행
	// 5. finally에 사용한 IO객체'들'을 정리한다.
	
	public static void main(String[] args) {
		InputStreamReader isr = null;
		OutputStreamWriter osw = null;
		
		try {
			// open부
			isr = new InputStreamReader(System.in); // InputStream를 Reader로 감싸서 연다.
			osw = new OutputStreamWriter(System.out);

			// System.out.println("문자열을 입력해주세요.);
			osw.append("문자열을 입력해주세요.\n"); // System.out.println과 같은 스트림으로 출력한다.
			osw.flush();
			
			char[] buffer = new char[1024]; // buffer의 크기는 2의 제곱 값을 정한다. // 512, 1024 ...
			int size = isr.read(buffer);
			
			osw.append("read size : " + size +"\n");
			osw.append("입력된 문자열 : " + new String(buffer) +"\n"); 	   // char[]을 문자열로 바꾸는 방법1
			osw.append("입력된 문자열 : " + String.valueOf(buffer) +"\n");   // char[]을 문자열로 바꾸는 방법2
			osw.flush();
			
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			
		}
	}
}