[JAVA] 9.입출력 스트림

min·2024년 10월 6일

JAVA

목록 보기
10/10

입출력 스트림

입출력 스트림의 종류

java.io 패키지는 여러 종류의 스트림 클래스를 제공하고 있는데, 스트림 클래스는 크게 두 종류로 구분된다.

  • byte 기반 스트림: 그림, 멀티미디어 등의 바이너리 데이터를 읽고 출력할 때 사용
  • character 기반 스트림: 문자 데이터를 읽고 출력할 때 사용

바이트 출력 스트림: OutputStream

OutputStream은 바이트 기반 출력 스트림의 최상위 클래스로 추상 클래스이다. FileOutputStream, PrintStream, BufferedOutputStream, DataOutputStream 클래스는 모두 OutputStream 클래스를 상속받고 있다.

리턴 타입메소드설명
voidwrite(int b)1바이트를 출력
voidwrite(byte[] b)매개값으로 주어진 배열 b의 모든 바이트를 출력
voidwrite(byte[] b, int off, int len)매개값으로 주어진 배열 b[0ff] 부터
len개 까지의 바이트 출력
voidflush()출력 버퍼에 잔류하는 모든 바이트를 출력
voidclose()출력 스트림을 닫음

write(int b)

write(int b) 메소드는 매개 변수르 주어지는 int(4byte)에서 끝 1byte만 출력 스트림으로 보낸다.


import java.io.FileOutputStream;
import java.io.OutputStream;

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

		OutputStream os = new FileOutputStream("C:/Temp/test1.db");
		
		byte a = 10;
		byte b = 20;
		byte c = 30;
		
		os.write(a);
		os.write(b);
		os.write(c);
		
		os.flush();	//출력 버퍼에 잔류하는 모든 바이트 출력
		os.close();	//출력 스트림을 닫음
		
	}
		
}

write(byte[] b)

write(byte[] b) 메소드는 매개값으로 주어진 배열의 모든 바이트를 출력 스트림으로 보낸다.


import java.io.FileOutputStream;
import java.io.OutputStream;

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

		OutputStream os = new FileOutputStream("C:/Temp/test2.db");
		
		byte[] array = {10, 20, 30};
		
		os.write(array);
		
		os.flush();	//출력 버퍼에 잔류하는 모든 바이트 출력
		os.close();	//출력 스트림을 닫음
		
	}
		
}

write(byte[] b, int off, int len)

write(byte[] b, int off, int len)메소드는 b[off] 부터 len개의 바이트를 출력 스트림으로 보낸다.


import java.io.FileOutputStream;
import java.io.OutputStream;

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

		OutputStream os = new FileOutputStream("C:/Temp/test3.db");
		
		byte[] array = {10, 20, 30, 40, 50};
		
		os.write(array, 1, 3);
		
		os.flush();	//출력 버퍼에 잔류하는 모든 바이트 출력
		os.close();	//출력 스트림을 닫음
		
	}
		
}

바이트 입력 스트림: InputStream

InputStream은 바이트 기반 입력 스트림의 최상위 클래스로 추상 클래스이다. FileInputStream, BufferedInputStream, DataInputStream 클래스는 모두 InputStream을 상속받는다.

리턴 타입메소드설명
intread()1byte를 읽고 읽은 바이트 리턴
intread(byte[] b)읽은 바이트를 매개값으로 주어진 배열에 저장하고
읽은 바이트 수 리턴
intread(byte[]b, int off, int len)len개의 바이트를 읽고 매개값으로 주어진 배열에서
b[off]부터 len개까지 저장. 읽은 바이트 수 리턴
voidclose()입력 스트림을 닫음

read()

read() 메소드는 입력 스트림으로부터 1byte를 읽고 int(4byte) 타입으로 리턴합니다. 따라서 리턴 된 4byte 중 끝 1byte에만 데이터가 들어있다.
더 이상 입력 스트림으로부터 바이트를 읽을 수 없다면 -1을 리턴한다. 이것을 이용하면 읽을 수 있는 마지막 바이트까지 반복해 1byte 씩 읽을 수 있다.

import java.io.FileInputStream;
import java.io.InputStream;

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

		InputStream is = new FileInputStream("C:/Temp/test1.db");
		
		while(true) {
			int data = is.read();
			if(data == -1) break;
			System.out.println(data);
		}
		
		is.close();	
		
	}
		
}

10
20
30

read(byte[] b)

read(byte[] b) 메소드는 입력 스트림으로부터 매개값으로 주어진 배열의 길이만큼 바이트를 읽고 해당 배열에 저장한다. 그리고 읽은 바이트 수를 리턴한다. 실제로 읽은 바이트 수가 배열의 길이보다 적을 경우, 읽은 수 만큼 리턴한다.
입력 스트림으로부터 바이트를 더 이상 읽을 수 없다면 -1을 리턴한다. 이것을 이용하면 읽을 수 있는 마지막 바이트까지 반복해서 읽을 수 있다.
많은 양의 바이트를 읽을 때는 read() 보단 read(byte[] b)를 사용하는 것이 효율적이다.

import java.io.FileInputStream;
import java.io.InputStream;

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

		InputStream is = new FileInputStream("C:/Temp/test2.db");
		
		byte[] buffer = new byte[100];
		
		while(true) {
			int readByteNum = is.read(buffer);
			if(readByteNum == -1) break;
			for(int i=0; i<readByteNum; i++) {
				System.out.println(buffer[i]);
			}
		}
		
		is.close();	
		
	}
		
}

10
20
30

read(byte[]b, int off, int len)

read(byte[]b, int off, int len) 메소드는 입력 스트림으로부터 len개의 바이트만큼 읽고, 매개값으로 주어진 바이트 배열 b[off]부터 len개까지 저장한다. 그리고 읽은 바이트 수인 len개를 리턴한다. 실제로 읽은 바이트 수가 len개 보다 작을 경우에는 읽은 수만큼만 리턴한다.
입력 스트림으로부터 바이트를 더 이상 읽을 수 없다면 -1을 리턴한다.
read(byte[] b)와의 차이점은 한 번에 읽어들이는 바이트 수를 len 매개값으로 조절할 수 있고, 배열에서 저장이 시작되는 인덱스를 지정할 수 있는 점이다. 만약 off를 0으로 len을 배열의 길이로 준다면 read(byte[] b)와 동일하다.

import java.io.FileInputStream;
import java.io.InputStream;

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

		InputStream is = new FileInputStream("C:/Temp/test3.db");
		
		byte[] buffer = new byte[5];
		
		int readByteNum = is.read(buffer, 2, 3); // buffer[]2, buffer[3], buffer[4]에 각각 저장
		
		if(readByteNum != -1) {
			for(int i=0; i<buffer.length; i++) {
				System.out.println(buffer[i]);
			}
		}
		
		is.close();	
		
	}
		
}

0
0
20
30
40

문자 출력 스트림: Writer

Writer는 문자 기반 출력 스트림의 최상위 클래스로 추상 클래스이다.
FileWriter, BufferedWriter, PrintWriter, OutputStreamWriter 클래스는 모두 Writer 클래스를 상속하고 있다.

리턴 타입메소드설명
voidwrite(int c)매개값으로 주어진 한 문자를 보냄
voidwrite(char[] cbuf)매개값으로 주어진 배열의 모든 문자를 보냄
voidwrite(char[] cbuf, int off, int len)매개값으로 주어진 배열에서 cbuf[off]부터
len개까지의 문자를 보냄
voidwrite(String str)매개값으로 주어진 문자열을 보냄
voidwrite(String str, int off, int len)매개값으로 주어진 문자열에서 off 순번부터
len개까지의 문자를 보냄
voidflush()출력 버퍼에 잔류하는 모든 문자를 출력
voidclose()출력 스트림을 닫음

write(int c)

write(int c) 메소드는 매개 변수로 주어지는 int(4byte)에서 끝 2byte(1개의 문자)만 출력 스트림으로 보낸다. 매개 변수가 int 타입이므로 4byte 모두를 보내는 것은 아니다.

import java.io.FileWriter;
import java.io.Writer;

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

		Writer writer = new FileWriter("C:/Temp/test7.txt");
		
		char a = 'A';
		char b = 'B';
		char c = 'C';
		
		writer.write(a);
		writer.write(b);
		writer.write(c);
		
		writer.flush();
		writer.close();	
		
	}
		
}

write(char[] cbuf)

write(char[] cbuf) 메소드는 매개값으로 주어진 char[] 배열의 모든 문자를 출력 스트림으로 보낸다.


import java.io.FileWriter;
import java.io.Writer;

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

		Writer writer = new FileWriter("C:/Temp/test8.txt");
		
		char[] array = {'A', 'B', 'C'};
		
		
		writer.write(array);
		
		writer.flush();
		writer.close();	
		
	}
		
}


write(char[] cbuf, int off, int len)

write(char[] cbuf, int off, int len) 메소드는 cbuf[off]부터 len개의 문자를 출력 스트림으로 보낸다.

import java.io.FileWriter;
import java.io.Writer;

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

		Writer writer = new FileWriter("C:/Temp/test9.txt");
		
		char[] array = {'A', 'B', 'C', 'D', 'E'};
		
		
		writer.write(array, 1, 3);
		
		writer.flush();
		writer.close();	
		
	}
		
}

write(String str), write(String str, int off, int len)

Write는 문자열을 좀 더 쉽게 보내기 위해서 write(String str)와 write(String str, int off, int len) 메소드를 제공한다.
write(String str) 메소드는 문자열 전체를 출력 스트림으로 보내고, write(String str, int off, int len) 메소드는 주어진 문자열 off 순번부터 len개까지의 문자를 보낸다.

import java.io.FileWriter;
import java.io.Writer;

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

		Writer writer = new FileWriter("C:/Temp/test10.txt");
		
		String str = "ABC";
		
		
		writer.write(str);
		
		writer.flush();
		writer.close();	
		
	}
		
}

문자 입력 스트림: Reader

Reader는 문자 기반 입력 스트림의 최상위 클래스로 추상 클래스이다.
FileReader, BufferedReader, InputStreamReader 클래스는 모두 Reader 클래스를 상속하고 있다.

리턴 타입메소드설명
intread(int c)1개의 문자를 읽고 리턴
intread(char[] cbuf)읽은 문자들을 매개값으로 주어진 문자 배열에 저장하고
읽은 문자 수를 리턴
intread(char[] cbuf, int off, int len)len개의 문자를 읽고 매개값으로 주어진 문자 배열에서
cbuf[off]부터 len개까지 저장. 읽은 문자 수 리턴
voidclose()입력 스트림을 닫음

read()

read() 메소드는 입력 스트림으로부터 1개의 문자(2byte)를 읽고 int(4byte) 타입으로 리턴한다. 따라서 리턴된 4byte 중 끝에 있는 2byte에 문자 데이터가 들어 있다.
read() 메소드가 리턴한 int 값을 char 타입으로 변환하면 읽은 문자를 얻을 수 있다.
더 이상 입력 스트림으로부터 문자를 읽을 수 없다면 -1을 리턴한다.

import java.io.FileReader;
import java.io.Reader;

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

		Reader reader = new FileReader("C:/Temp/test7.txt");
		
		while(true) {
			int data = reader.read();
			if(data == -1)break;
			System.out.println((char)data);
		}
		
		reader.close();
		
	}
		
}

A
B
C

read(char[] cbuf)

read(char[] cbuf) 메소드는 입력 스트림으로 부터 매개값으로 주어진 문자 배열의 길이만큼 문자를 읽고 배열에 저장한다. 그리고 읽은 문자 수를 리턴한다. 실제로 읽은 문자 수가 배열의 길이보다 적을 경우 읽은 수만큼만 리턴한다. 입력 스트림으로부터 문자를 더 이상 읽을 수 없다면 -1을 리턴한다.

import java.io.FileReader;
import java.io.Reader;

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

		Reader reader = new FileReader("C:/Temp/test8.txt");
		
		char[] buffer = new char[100];
		
		while(true) {
			int readCharNum = reader.read(buffer);
			if(readCharNum == -1) break;
			for(int i=0; i<readCharNum; i++) {
				System.out.println(buffer[i]);
			}
		}
		
		reader.close();
		
	}
		
}

A
B
C

read(char[] cbuf, int off, int len)

read(char[] cbuf, int off, int len) 메소드는 입력 스트림으로부터 len개의 문자만큼 읽고 매개값으로 주어진 문자 배열에서 cbuf[off]부터 len개까지 저장한다. 그리고 읽은 문자 수인 len개를 리턴 한다. 실제로 읽은 문자 수가 len개보다 적을 경우에는 읽은 수만큼만 리턴한다.

import java.io.FileReader;
import java.io.Reader;

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

		Reader reader = new FileReader("C:/Temp/test9.txt");
		
		char[] buffer = new char[5];
		
		int readCharNum = reader.read(buffer, 2, 3);
		if(readCharNum != -1) {
			for(int i=0; i<buffer.length; i++) {
				System.out.println(buffer[i]);
			}
		}
		
		
		reader.close();
		
	}
		
}


B
C
D


보조 스트림

보조 스트림이란 다른 스트림과 연결이 되어 여러 편리한 기능을 제공해주는 스트림을 말한다. 보조 스트림은 자체적으로 입출력을 수행할 수 없기 때문에 입출력 소스와 바로 연결되는 InputStream, OutputStream, Reader, Writer 등에 연결해서 입출력을 수행한다. 보조 스트림은 문자 변환, 입출력 성능 향상, 기본 타입 입출력 등의 기능을 제공한다.

보조 스트림 연결하기

보조 스트림을 연결하려면 보조 스트림을 생성할 때 자신이 연결될 스트림을 생성자의 매개값으로 제공하면 된다.

보조스트림 변수 = new 보조스트림(연결스트림)
InputStream is = ...;
InputStreamReader reader = new InputStreamReader(is);

보조스트림의 생성자 매개값은 InputStream, OutputStream, Reader, Writer 이외에 또 다른 보조스트림이 될 수 있다. 이 말은 보조 스트림을 연속적으로 연결 할 수 있다는 뜻이다.

InputStream is = System.in;
InputStreamReader reader = new InputStreamReader(is);
BufferedReader br = new BufferedReader(reader);

문자 변환 보조 스트림

소스 스트림이 바이트 기반 스트림(InputStream, OutputStream, FileInputStream, FileOutputStream)이면서 입출력 데이터가 문자라면 Reader와 Writer로 변환해서 사용하는 것을 고려할 수 있다. 문자 입출력은 Reader와 Writer가 편리하기 때문이다.

OutputStreamWriter

OutputStreamWriter는 바이트 기반 출력 스트림에 연결되어 문자 출력 스트림인 Wirter로 변환하는 보조 스트림이다.

Writer writer = new OutputStremWriter(바이트 기반 출력 스트림)
FileOutputStream fos = FileOutputStream("C:/Temp/test1.txt");
Writer writer = new OutputStreamWriter(fos);

InputStreamReader

InputStreamReader는 바이트 기반 입력 스트림에 연결되어 문자 입력 스트림인 Reader로 변환하는 보조 스트림이다.

Reader reader = new InputStreamReader(바이트 기반 출력 스트림)
FileInputStream fis = FileInputStream("C:/Temp/test1.txt");
Reader reader = new InputStreamReader(fos);
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;

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

		write("문자 변환 스트림을 사용합니다.");
		String data = read();
		System.out.println(data);
		
	}
	
	public static void write(String str) throws Exception{
		FileOutputStream fos = new FileOutputStream("C:/Temp/test1.txt");
		Writer writer = new OutputStreamWriter(fos); //보조스트림 연결
		
		writer.write(str);
		writer.flush();
		writer.close();
	}
	
	public static String read() throws Exception {
		FileInputStream fis = new FileInputStream("C:/Temp/test1.txt");
		Reader reader = new InputStreamReader(fis); //보조스트림 연결
		
		char[] buffer = new char[100];
		int readCharNum = reader.read(buffer);
		reader.close();
		String data = new String(buffer, 0, readCharNum);
		return data;
	}
		
}

문자 변환 스트림을 사용합니다.

성능 향상 보조스트림

프로그램의 실행 성능은 입출력이 가장 늦은 장치를 따라간다. CPU와 메모리가 아무리 뛰어나도 하드 디스크의 입출력이 늦어지면 프로그램의 실행 성능은 하드 디스크의 처리 속도에 맞춰진다. 네트워크로 데이터를 전송할 때도 마찬가지로 느린 네트워크 환경이라면 컴퓨터 사양이 아무리 좋아도 속도는 느릴 수 밖에 없다.

이 문제에 대한 완전한 해결책은 될 수 없지만, 프로그램이 입출력 소스와 직접 작업하지 않고 중간에 메모리 버퍼와 작업함으로써 실행 성능을 향상시킬 수 있다.
예를 들어 프로그램은 직접 하드 디스크에 데이터를 보내지 않고 메모리 버퍼에 데이터를 보냄으로써 쓰기 속도가 향상된다. 버퍼는 데이터가 쌓이기를 기다렸다가 꽉 차게 되면 데이터를 한꺼번에 하드 디스크로 보냄으로써 출력 횟수를 줄여준다.

기본적으로 출력 스트림은 내부에 작은 버퍼를 가지고 있지만 이것만으로는 불충분하다. 보조스트림 중에는 메모리 버퍼를 추가로 제공하여 프로그램의 성능을 향상시키는 것들이 있다.
바이트 기반 스트림에서는 BufferedInputStream, BufferedOutputStream이 있고 문자 기반 스트림에서는 BufferedReader, BufferedWriter가 있다.

BufferedOutputStream과 BufferedWriter

BufferedOutputStream은 바이트 기반 출력 스트림에 연결 되어 버퍼를 제공해주는 보조 스트림이고, BufferedWriter는 문자 기반 출력 스트림에 연결되어 버퍼를 제공해주는 보조 스트림이다.
BufferedOutputStream과 BufferedWriter는 프로그램에서 전송한 데이터를 내부 버퍼에 쎃아 두었다가 버퍼가 꽉 차면, 버퍼의 모든 데이터를 한 번에 보낸다. 프로그램 입장에서 메모리 버퍼로 데이터를 고속 전송하기 때문에 출력 성능이 향상되는 효과를 얻게된다.

BufferedOutputStream bos = new BufferedOutputStream(바이트 기반 출력 스트림) 
BufferedWriter bw = new BufferedWriter(문자 기반 출력 스트림)

BufferedOutputStream과 BufferedReader

BufferedOutputStream은 바이트 기반 입력 스트림에 연결되어 버퍼를 제공해주는 보조 스트림이고, BufferedReader는 문자 기반 입력 스트림에 연결되어 버퍼를 제공해주는 보조 스트림이다.
BufferedOutputStream과 BufferedReader는 입력 소스로 부터 자신의 내부 버퍼 크기만큼 데이터를 미리 읽고 버퍼에 저장해둔다. 프로그램은 외부의 입력 소스로부터 직접 읽는 대신 버퍼로부터 읽음으로써 성능이 향상된다.

BufferedInputStream bis = new BufferedInputStream(바이트 기반 입력 스트림) 
BufferedReader br = new BufferedReader(문자 기반 입력 스트림)
import java.io.*;

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

		String originalFilePath1 = Test.class.getResource("originalFile1.jpg").getPath();
		String targetFilePath1 = "C:/Temp/targetFile1.jpg";
		FileInputStream fis = new FileInputStream(originalFilePath1);
		FileOutputStream fos = new FileOutputStream(targetFilePath1);
		
		//버퍼 보조스트림 연결
		String originalFilePath2 = Test.class.getResource("originalFile2.jpg").getPath();
		String targetFilePath2 = "C:/Temp/targetFile2.jpg";
		FileInputStream fis2 = new FileInputStream(originalFilePath2);
		FileOutputStream fos2 = new FileOutputStream(targetFilePath2);
		BufferedInputStream bis = new BufferedInputStream(fis2);
		BufferedOutputStream bos = new BufferedOutputStream(fos2);
		
		long nonBufferTime = copy(fis, fos);
		System.out.println("버퍼를 사용하지 않을 때:\t" + nonBufferTime +"ns");
		

		long bufferTime = copy(bis, bos);
		System.out.println("버퍼를 사용했을 때:\t" + bufferTime +"ns");
		
		fis.close();
		fos.close();
		bis.close();
		bos.close();
		
	}
	
	static int data = -1;
	public static long copy(InputStream is, OutputStream os) throws Exception {
		long start = System.nanoTime();
		
		while(true) {
			data  = is.read();
			if(data == -1) break;
			os.write(data);
		}
		os.flush();
		
		long end = System.nanoTime();
		
		return(end-start);
	}
	
}

BufferedReader는 라인 단위로 문자열을 읽는 매우 편리한 readLine()메소드를 제공한다.
readLine()은 엔터키(캐리지 리턴(\r)+라인피드(\n)) 이전의 모든 문자열을 읽고 리턴한다. 이 메소드를 이용하면 키보드에서 입력한 내용 및 파일 내용을 라인 단위로 읽을 수 있다.

기본 타입 입출력 보조 스트림

DataInputStream과 DataOutputStream 보조 스트림을 연결하면 기본 타입인 boolean, char,short, int, long, float, double을 입출력 할 수 있다.

DataInputStream dis = new DataInputStream(바이트 기반 입력 스트림);
DataOutputStream dos = new DataOutputStream(바이트 기반 출력 스트림);

데이터 타입의 크기가 모두 다르므로 DatOutputStream으로 출력한 데이터를 DatInputStream으로 다시 읽어올 때는 출력한 순서와 동일한 순서로 읽어야 한다.


import java.io.*;

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

		FileOutputStream fos = new FileOutputStream("C:/Temp/primitive.db");
		DataOutputStream dos = new DataOutputStream(fos);
		
		dos.writeUTF("홍길동");
		dos.writeDouble(95.5);
		dos.writeInt(1);
		
		dos.writeUTF("제이크");
		dos.writeDouble(90.3);
		dos.writeInt(2);
		
		dos.flush(); dos.close();
		
		FileInputStream fis = new FileInputStream("C:/Temp/primitive.db");
		DataInputStream dis = new DataInputStream(fis);
		
		for(int i = 0; i<2; i++) {
			String name = dis.readUTF();
			double score = dis.readDouble();
			int order = dis.readInt();
			System.out.println(name + " : " + score + " : " + order);
		}
		
		dis.close();
	}
	
}

홍길동 : 95.5 : 1
제이크 : 90.3 : 2

프린터 보조 스트림

PrintStreamPrintWriter는 프린터와 유사하게 출력하는 print(), println() 메소드를 가지고 있는 보조스트림이다. 콘솔 출력 스트림인 System.out이 바로 PrintStream이기 때문에 print(), println() 메소드를 사용할 수 있었다. PrintStream은 바이트 기반 출력 스트림, PrintWriter는 문자 기반 출력 스트림과 연결 된다.

PrintStream ps = new PrintStream(바이트 기반 출력 스트림);
PrintWriter pw = new PrintWriter(문자 기반 출력 스트림);


import java.io.*;

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

		FileOutputStream fos = new FileOutputStream("C:/Temp/printstream.txt");
		PrintStream ps = new PrintStream(fos);

		ps.println("[프린터 보조 스트림]");
		ps.print("마치 ");
		ps.println("프린터가 출력하는 것처럼 ");
		ps.println("데이터를 출력한다.");
		
		ps.flush();
		ps.close();
		
	}
	
}


객체 입출력 보조 스트림

ObjectOutputStreamObjectInputStream 보조 스트림을 연결하면 메모리에 생성된 객체를 파일 또는 네트워크로 출력할 수 있다.
ObjectOutputStream은 객체를 직렬화하는 역할을 하고, ObjectInputStream은 객체로 역직렬화 하는 역할을 한다. 직렬화란 객체를 바이트 배열로 만드는 것이고, 역직렬화란 바이트 배열을 다시 객체로 복원하는 것이다.

ObjectInputStream ois = new ObjectInputStream(바이트 기반 입력 스트림);
ObjectOutputStream oos = new ObjectOutputStream(바이트 기반 출력 스트림);

writeObject() 메소드는 객체를 직렬화해서 출력 스트림으로 보낸다.

oos.writeObject(객체);

readObject() 메소드는 입력 스트림에서 읽은 바이트를 역직렬화해서 다시 객체로 복원한다.

객체 타입 변수 = (객체타입) ois.readObject();

자바는 모든 객체를 직렬화 하지 않는다. java.io.Serializable 인터페이스를 구현한 객체만 직렬화 한다. Serializable 인터페이스는 메소드 선언이 없는 인터페이스이다.
객체를 파일로 저장하거나 네트워크로 전송할 목적이라면 클래스를 선언할 때 implements Serializable을 추가해야한다.

import java.io.Serializable;
import java.util.Date;

public class Board implements Serializable {
	private int bno;
	private String title;
	private String content;
	private String writer;
	private Date date;
	
	public Board(int bno, String title, String content, String wirter, Date date) {
		this.bno = bno;
		this.title = title;
		this.content = content;
		this.writer = writer;
		this.date = date;
	}
	
	public int getBno() { return bno; }
	public void SetBno(int bno) { this.bno = bno ; }
	public String getTitle() { return title; }
	public void SetTitle(String title) { this.title = title; }
	public String getContent() { return content; }
	public void SetContent(String content) { this.content = content; }
	public String getWriter() { return writer; }
	public void SetWriter(String writer) { this.writer = writer; }
	public Date getDate() { return date; }
	public void setDate(Date date) { this.date = date; }
	
}
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;

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

		writeList();
		List<Board> list = readList();
		
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		for(Board board : list) {
			System.out.println(board.getBno() + "\t" + board.getTitle() + "\t" + 
					board.getContent() + "\t" + board.getWriter() + "\t" + 
					sdf.format(board.getDate()));
		}		
		
	}
	
	
	public static void writeList() throws Exception {
		List<Board> list = new ArrayList<>();
		
		list.add(new Board(1, "제목1", "내용1", "글쓴이1", new Date()));
		list.add(new Board(2, "제목2", "내용2", "글쓴이2", new Date()));
		list.add(new Board(3, "제목3", "내용3", "글쓴이3", new Date()));
		
		FileOutputStream fos = new FileOutputStream("C:/Temp/board.db");
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		oos.writeObject(list);
		oos.flush();
		oos.close();
	}
	
	
	public static List<Board> readList() throws Exception {
		
		FileInputStream fis = new FileInputStream("C:/Temp/board.db");
		ObjectInputStream ois = new ObjectInputStream(fis);
		List<Board> list = (List<Board>) ois.readObject();
		
		return list;
	}
}

1 제목1 내용1 null 2024-10-09
2 제목2 내용2 null 2024-10-09
3 제목3 내용3 null 2024-10-09

입출력 관련 API

Systme.in 필드

자바는 콘솔에서 키보드의 데이터를 입력받을 수 있도록 System 클래스의 in 정적 필드를 제공한다. System.in은 InputStream 타입의 필드이므로 InputStream 변수로 참조 가능하다.
키보드로 부터 어떤 키가 입력 되었는지 확인하려면 InputStream의 read() 메소드로 1byte를 읽으면 된다.

InputStream is = System.in;
int keyCode = is.read();

라인단위로 읽기 위해선 InputStreamReader 보조 스트림을 연결해 Reader로 변환 후 BufferedReader 보조스트림을 추가로 연결한다. 그리고 readLine() 메소드로 읽으면 된다.

InputStream is = System.in;
Reader reader = new InputStreamReader(is);
BufferedReader br = new BufferedReader(reader);
String lineStr = br.readLine();

Scanner 클래스

Scanner 클래스는 입출력 스트림도 아니고, 보조 스트림도 아니다.
Scanner는 문자 파일이나 바이트 기반 입력 스트림에서 라인 단위 문자열을 쉽게 읽도록 하기위해 java.util 패키지에서 제공하는 클래스이다.

Scanner scanner = new Scanner(System.in);
String inputData = scanner.nextLine();

File 클래스

java.io 패키지에서 제공하는 File 클래스는 파일 및 폴더(디렉토리) 정보를 제공해주는 역할을 한다.

File file = new("C:/Temp/file.txt");
File file = new("C:\\Temp\\file.txt");

경로 구분자는 운영체제마다 조금씩 다르다. 윈도우에서는 /, \를 둘 다 사용할 수 있고, 유닉스나 리눅스는 /를 사용해야 한다. 윈도우에서 \를 사용하고 싶으면 이스케이프 문자(\)로 사용해야 한다.

File 객체를 생성했다고 파일이나 폴더가 생성되는 것은 아니다. 그리고 문자열 경로에 실제 파일이나 폴더가 없더라도 예외가 발행하지 않는다. 해당 경로에 실제로 파일이나 폴더가 있는지 확인하고 싶다면, File 객체 생성 후 exists() 메소드를 호출하여 반환값을 확인한다.

boolean isExist = file.exists();

리턴 값이 false일 때, 다음 메소드를 사용해 파일 또는 폴더를 생성할 수 있다.

리턴 값이 ture일 때, 다음과 같은 메소드를 사용할 수 있다.


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

public class Test {	
		
	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() == false) dir.mkdir();
		if(file1.exists() == false) file1.createNewFile();
		if(file2.exists() == false) file2.createNewFile();
		if(file3.exists() == false) file3.createNewFile();
		
		File temp = new File("C:/Temp");
		File[] contents = temp.listFiles();
		
		System.out.println("시간\t\t\t형태\t\t크기\t이름");
		System.out.println("-------------------------------------------------------");
		
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd a HH:mm");
		
		for(File file : contents) {
			System.out.print(sdf.format(new Date(file.lastModified())));
			if(file.isDirectory()) {
				System.out.println("\t<DIR>\t\t\t" + file.getName());
			}
			else {
				System.out.println("\t\t\t"+file.length()+"\t"+file.getName());
			}
		}
		
		System.out.println();

	}
	
	
	
}

0개의 댓글