데이터 입출력

이동주·2025년 3월 19일

JAVA

목록 보기
28/30

입출력 스트림

  • 프로그램을 기준으로 데이터가 들어오면 입력 스트림, 데이터가 나가면 출력 스트림
  • 프로그램이 다른 프로그램과 데이터를 교환하기 위해서는 양쪽 프로그램 모두 입력 스트림과 출력 스트림이 필요하다!

IPC 프로그램

  • 자바는 데이터 입출력과 관련된 라이브러리를 java.io 패키지에서 제공함

스트림의 종류

  • 바이트 스트림 : 그림, 멀티미디어, 문자 등 모든 종류의 데이터를 입출력할 때 사용
    -> 바이트 스트림의 최상위 클래스 : InputStream(입력), OutputStream(출력)
  • 문자 스트림 : 문자만 단독으로 입출력할 때 사용함
    -> 문자 스트림의 최상위 클래스 : Reader, Writer
  • 스트림은 위의 기능들을 기본으로 함!

바이트 스트림

바이트 출력 스트림(OutputStream)

  • OutputStream은 바이트 출력 스트림의 최상위 클래스로 추상 클래스임
    -> 객체로 생성 불가능함
  • 모든 바이트 출력 스트림 클래스는 해당 클래스를 상속받아서 생성됨

  • OutputStream 클래스에는 모든 바이트 출력 스트림이 기본적으로 가져야 할 메소드가 정의됨

  • write() : 메모리에만 기록함

  • flush() : 출력을 위해 반드시 사용

  • close() : 스트림을 닫기 위해 사용 (꼭 사용해줘야 함)

  • 버퍼 : 저장했다가 기록하는 것

  • 만들어진 데이터베이스 파일을 읽는 방법

  1. Visual Studio Code 프로그램 실행 및 해당 데이터베이스 파일 열기
  2. view > extensions > hex editor 설치
  3. F1키 누르고 Hex Editor Open Active File in Hex Editor 설치 (16진수로 볼 수 있음)

1바이트 출력

  • write(int b) 메소드 : 매개값 int에서 끝 1byte만 출력함. 매개변수는 int 타입!

바이트 배열 출력

  • write(byte[] b) 메소드 : 매개값으로 주어진 배열의 모든 바이트를 출력함
  • 배열의 일부분을 출력하려면 write(byte[] b, int off, int len) 메소드를 사용함

바이트 입력 스트림 (InputStream)

  • InputStream은 바이트 입력 스트림의 최상위 클래스로, 추상 클래스임
  • 모든 바이트 입력 스트림은 InputStream 클래스를 상속받아 만들어짐

  • InputStream 클래스에는 바이트 입력 스트림이 기본적으로 가져야 할 메소드가 정의됨

1바이트 입력

  • read() 메소드 : 입력 스트림으로부터 1byte를 읽고 int 타입으로 리턴함.
  • 리턴된 4byte중 끝 1byte에만 데이터가 들어 있음

  • 더 이상 입력 스트림으로부터 바이트를 읽을 수 없다면 read() 메소드는 -1을 리턴함
  • 읽을 수 있는 마지막 바이트까지 반복해서 한 바이트씩 읽을 수 있음

바이트 배열로 읽기

  • read(byte[]b) 메소드 : 입력 스트림으로부터 주어진 배열의 길이만큼 바이트를 읽고 배열에 저장한 다음 읽은 바이트 수를 리턴
  • read(byte[]b)도 입력 스트림으로부터 바이트를 더 이상 읽을 수 없다면 -1을 리턴
  • 읽을 수 있는 마지막 바이트까지 반복해서 읽을 수 있음

문자 입출력 스트림

문자 출력 (Writer)

  • Writer : 문자 출력 스트림의 최상위 클래스
  • 모든 문자 출력 스트림 클래스는 Writer 클래스를 상속받아 생성됨
  • 문자로만 출력받으며 Ascii 코드 사용 불가능
  • 스트림은 순차적으로 읽어들이고 내보내는 작업 수행!

  • Writer 클래스에는 모든 문자 출력 스트림이 기본적으로 가져야 할 메소드가 정의됨

  • 코드 실행의 순차적으로 출력됨!

문자 입력 (Reader)

  • Reader는 문자 입력 스트림의 최상위 클래스로, 추상 클래스에 해당됨
  • 모든 문자 입력 스트림 클래스는 Reader 클래스를 상속받아서 생성됨

  • Reader 클래스에는 문자 입력 스트림이 기본적으로 가져야 할 메소드가 정의된다

보조 스트림

  • 다른(바이트, 문자) 스트림과 연결되어 여러 편리한 기능을 제공해주는 스트림
  • 자체적으로 입출력을 수행할 수 없음
  • 입출력 소스로부터 직접 생성된 입출력 스트림에 연결해서 사용함

  • 입출력 스트림에 보조 스트림을 연결하려면 보조 스트림을 생성할 때 생성자 매개값으로 입출력 스트림을 제공
  • 보조스트림 변수 = new 보조스트림(입출력스트림(기본 스트림));
  • 보조스트림은 또 다른 보조스트림과 연결되어 스트림 체인으로 구성할 수 있음

  • 보조스트림2 변수 = new 보조스트림2(보조스트림1);

문자 변환 스트림 (많이 사용함)

InputStream을 Reader로 변환

  • InputStream을 Reader로 변환하려면 InputStreamReader 보조 스트림을 연결
  • 스트림을 가지고는 줄 단위로 읽고 쓰기가 불편하기 때문에 변환을 시행함!
  • Reader, Writer는 줄 단위로 읽고 쓰는 기능이 있음!

OutputStream을 Writer로 변환

  • OutputStream을 Writer로 변환하려면 OutputStreamWriter 보조 스트림을 연결
  • 스트림을 가지고는 줄 단위로 읽고 쓰기가 불편하기 때문에 변환을 시행함!
  • Reader, Writer는 줄 단위로 읽고 쓰는 기능이 있음!

성능 향상 스트림

메모리 버퍼로 실행 성능을 높이는 보조 스트림

  • 프로그램이 중간에 메모리버퍼와 작업해서 실행 성능 향상이 가능함
  • 출력 스트림의 경우 직접 하드 디스크에 데이터를 보내지 않고 메모리 버퍼에 데이터를 보냄으로써 출력 속도를 향상
  • 입력 스트림에서도 버퍼를 사용하면 읽기 성능이 향상됨

  • 바이트 스트림 : BufferedInputStream, BufferedOutputStream
  • 문자 스트림 : BufferedReader, BufferedWriter

기본 타입 스트림

  • 바이트 스트림에 DataInputStream과 DataOutputStream 보조 스트림을 연결하면 기본 타입 값을 입출력할 수 있음

프린트 스트림

  • 프린터와 유사하게 출력하는 print(), println(), printf() 메소드를 가진 보조 스트림

  • PrintStream : 바이트 출력 스트림과 연결됨
  • PrintWriter : 문자 출력 스트림과 연결됨

직렬화와 역직렬화 (개념 중요!)

  • 리플렉션을 활용하여 객체를 저장했다가 읽어들이는데 사용

직렬화

  • 메모리에 생성된 객체를 파일 또는 네트워크로 출력하기 위해 필드값을 일렬로 늘어선 바이트로 변경하는 것!
  • 객체를 파일로 저장하는 역할!
  • ObjectOutputStream : 바이트 출력 스트림과 연결되어 객체를 직렬화 함

역직렬화

  • 직렬화된 바이트를 객체의 필드값으로 복원하는 것
  • 파일에 내용을 읽어들이면 객체로 만드는 것
  • ObjectInputStream : 바이트 입력 스트림과 연결되어 객체를 복원하는 역직렬화

Serializable 인터페이스

  • 멤버가 없는 빈 인터페이스
  • 객체를 직렬화할 수 있다고 표시하는 역할을 함
  • 인스턴스 필드값은 직렬화 대상임
  • 정적 필드값과 transient로 선언된 필드값은 직렬화에서 제외되므로 출력되지 않는다

serialVersionUID 필드

  • 직렬화할 때 사용된 클래스와 역직렬화할 때 사용된 클래스는 동일한 클래스여야 함
  • 클래스 내용이 다르더라도

File(많이 사용)

  • File 클래스로부터 File 객체를 생성함
  • exists() 메소드로 파일 또는 폴더의 존재여부를 확인함
  • exists() 메소드가 false를 리턴할 경우 다음 메소드로 파일 또는 폴더를 생성함

  • exists() 메소드의 리턴값이 true라면 다음 메소드를 사용함

package ch18.sec11;

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

public class FileExample {
	public static void main(String[] args) throws Exception{
		// 폴더 생성
		File dir = new File("C:/Temp/images");
		
		// 파일 생성!
		File file1 = new File("C:/Temp/file1.txt");
		File file2 = new File("C:/Temp/file2.txt");
		File file3 = new File("C:/Temp/file3.txt");
		
		// 폴더가 존재하지 않을 때!
		if(!dir.exists()) {
			// 폴더 생성
			// mkdir : 해당 폴더(디렉토리)만 생성함, 상위 디렉토리가 존재하지 않으면 생성 불가능
			// mkdirs: 해당 폴더(디렉토리)와 상위 디렉토리까지 모두 생성 (상위 디렉토리가 없을 경우)
			dir.mkdirs();
		}
		
		// 파일이 존재하지 않을 때!
		if(!file1.exists()) {
			// 파일 생성
			file1.createNewFile();
		}
		
		if(!file2.exists()) {
			file2.createNewFile();
		}
		
		if(!file3.exists()) {
			file3.createNewFile();
		}
		
		// C:/Temp를 지정
		File temp = new File("C:/Temp");
		// .listFiles() : 디렉토리의 모든 파일과 하위 디렉토리를 배열로 반환하는 작업
		File[] contents = temp.listFiles();
		
		// 날짜의 형식에 맞춤!
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd a HH:mm");
		
		// File 배열에 저장된 값들을 차례대로 출력
		for(File file : contents) {
			// 25칸의 문자열 공간을 확보하고, 최종 수정시간을 밀리초로 가져옴(file.laseModified())
			System.out.printf("%-25s", sdf.format(new Date(file.lastModified())));
			
			// 해당 파일이 디렉토리(폴더)일때
			if(file.isDirectory()) {
				System.out.printf("%-10s%-20s", "<DIR>", file.getName());
			}
			// 해당 파일이 디렉토리가 아닐 때!
			else {
				System.out.printf("%-10s%-20s", file.length(), file.getName());
			}
			System.out.println();
		}
	}
}

Files 클래스

  • Files 클래스는 정적 메소드로 구성되어 있음. File 클래스처럼 객체로 만들 필요가 없음
  • Files의 정적 메소드는 운영체제의 파일 시스템에게 파일 작업을 수행하도록 위임

  • 상대 경로 : "."(하위폴더), ".."(상위폴더)
  • 절대 경로 : "/", "//"
  • cmd에서 파일 생성 확인 방법 : type 파일명.파일확장자명
  • cmd에서 파일 복사 방법 : copy 파일명1.파일확장자명(복사할 파일) 파일명2.파일확장자명(복사본 파일 이름)
  • cmd에서 파일 삭제 방법 : del 파일명.파일확장자명
package ch18.sec11;

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

public class FilesExam {
	public static void main(String[] args) {
		try {
			String data = "" +
					"id:dongju\n" +
					"email: dongju@mycompany.com\n" +
					"tel: 010-1234-5678";
			
			// Path 클래스 : 파일이나 디렉토리의 경로를 나타냄
			// Paths 클래스 : Path 객체를 생성하기 위해 사용하는 유틸리티 클래스
			// get() 메소드를 통해 경로 문자열을 받고 Path 객체를 생성
			Path path = Paths.get("C:/Temp/user.txt");
			
			// writeString() : Files 클래스에 있는 정적 메소드, 파일에 문자열을 쉽게 작성 가능
			// writeString(a,b,c)
			// a : Path 객체를 생성(Paths)하여 경로를 문자열로 표시 및 생성
			// b : 파일에 쓸 문자열 데이터
			// c : charset.forName("UTF-8") -> 문자 인코딩 방식을 지정함 (생략시 utf-8이 디폴트)
			Files.writeString(Paths.get("C:/Temp/user.txt"), data, Charset.forName("UTF-8"));
			
			// Files.probeContentType(파일경로) : 해당 파일의 확장자나 파일 내용을 나타냄
			System.out.println("파일 유형: " + Files.probeContentType(path));
			
			// Files.size(파일경로)
			// -> 해당 파일의 크기를 출력 (바이트로 출력)
			System.out.println("파일 크기: " + Files.size(path) + " bytes");
			
			// Files.readString(파일경로, 인코딩방식)
			// -> 해당 인코딩 방식을 이용하여 파일을 문자열로 읽어옴
			String content = Files.readString(path, Charset.forName("UTF-8"));
			System.out.println(content);
		}
		catch(Exception e) {
			e.printStackTrace();
		}
	}
}
profile
끄작끄작

0개의 댓글