본문 바로가기
BACK-END/Java

[Java] API-Stream(Input & Output)

by 로햐 2021. 11. 25.

Ⅰ. Input/Output 

1-1. 입출력(IO)

컴퓨터 내부-외부의 장치와 프로그램이 정보를 주고받는 행위.

자바에서는 입출력을 처리하기 위해 Stream이라는 API를 사용한다. 관련 패키지는 java.io.*


Ⅱ. stream

2-1. Stream

Stream이란?

프로그램이 외부매체와 입출력을 하기 위해 열어준 통로를 말한다.

단방향 통신이기 때문에, 입력과 출력 중 하나의 기능만 한다.

FIFO(First In First Out).


2-2. Stream 종류

2-2-1. 기반스트림

-바이트(1byte) 기반 : input/output 계열 : FileInputStream / FileOutputStream

-문자(2byte) 기반 : Reader/Writer 계열 : FileReader / FileWriter

 

2-2-2. 보조스트림

//-문자 변환 : InputStreamReader / OutputStreamWriter

-성능 향상 : BufferedInputStream / BufferedOutputStream

-객체 입출력 : ObjectInputStream / ObjectOutputStream (직렬화/역직렬화)

-문자 입력 : BufferedReader, / BufferedWriter


Ⅲ. File 클래스

파일이나 폴더를 만드는 클래스. java.io패키지의 File을 import 해서 사용한다.

 

3-1. 생성

File file1 = new File("test.txt");
file1.createNewFile();//현재 프로젝트 폴더에 파일 생성

File forder1 = new File("test");
forder1.mkdir();//현재 프로젝트 폴더에 폴더 생성(make directory)


File file2 = new File("C:\\test.txt");
file2.createNewFile();//경로 지정하여 파일 생성

3-2. File 클래스에서 자주 사용하는 method

메소드 의미 반환형
.isFile() 파일이면 true, 폴더면 false boolean
.getName() 파일 이름 String
.getParent 상위 폴더 String
.length() 파일 용량 long
.list() String[] 배열로 받기 String[]

Ⅳ. 기반 스트림

3-1. 바이트 기반 스트림

1byte만 지나갈 수 있는 Stream. 1byte = 8bit

자바는 특별한 경우를 제외하고 Number type은 Sined다. 

따라서 바이트 기반 스트림을 통과할 수 있는 크기는 -128~127.

따라서 해당 숫자의 아스키코드 값으로 옮겨진다.

 

※ 아스키코드

10진수 아스키코드 값 10진수 아스키코드 값 10진수 아스키코드 값
48 0 65 A 97 a
49 1 66 B 98 b
50 2 67 C 99 c

 

3-1-1. FileOutputStream

파일와 연결 Stream을 만들어 데이터를 출력. 사용이 종료되면 .close()로 자원 반납.

File을 못찾는 경우 예외가 발생하기 때문에 예외처리를 해준다.

FileOutputStream fileOut = new FileOutputStream("test.txt");//직접 경로 입력 가능

 

  파일 생성 통로 연결
해당 경로의 파일이 없음 O O
해당 경로의 파일이 있음 X O

 

  • 이어쓰기 옵션

파일에서 출력해도 같은 파일명으로 출력하면 뒤의 내용이 덮어씀. 이어쓰기 옵션으로 파일에 덧붙이기가 가능하다.

FileOutputStream fOut = new FileOutputStream("test.txt",true);//이어쓰기 옵션 true.

fOut.write(65);
fOut.write(97);
//결과 : Aa

 

  • 사용하는 메소드
메소드 의미
.write() 1바이트를 출력
.flush() 버퍼 모두 출력. 버퍼 비우기
.close() 자원 반납 후 스트림 닫기

※ .write() 메소드의 경우 인자에서 오류날 수 있으므로 IOException 예외처리를 해준다.


※자원반납 

그대로 두어도 사용이 종료된 자원은 Garbage Collector가 memory 영역을 돌아다니면서 처리하지만, 메모리의 누수를 야기하기 때문에 사용이 끝난 자원은 반납해주는 편이 매우매우 좋다.

 

  • 방법

1. finally 구문 : 해당 객체를 닫는 .close() 메소드 호출을 예외처리의 finally 구문에 넣어 자원반납 실행.

try{
	FileOutputStream fOut=new FileOutputStream("test.txt")
		fOut.write(12);
	} catch (FileNotFoundException e) {
		e.printStackTrace();
	} catch (IOException e) {
		e.printStackTrace();
	}finally{
		try{
			fOut.close();//자원반납 도중 예외가 발생할 수 있으므로 예외처리
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

2. try with resource : try에 예외가 발생할 수 있는 객체 생성을 넣어 처리. 여러개가 있다면 ;으로 연결하여 기술한다.

try의 {}에서 벗어나면 자동으로 자원반납. JDK 7 버전 이상부터 가능.

try(FileOutputStream fOut=new FileOutputStream("test.txt")){
	fOut.write(12);
} catch (FileNotFoundException e) {
	e.printStackTrace();
} catch (IOException e) {
	e.printStackTrace();
}

3-1-2. FileInputStream

파일에서 프로그램으로 데이터를 입력. 사용이 종료되면 .close()로 자원 반납. 

FileInputStream fileIn = new FileInputStream("test.txt");//직접 경로 입력 가능
  • 사용하는 메소드
메소드 의미
.read() 1바이트를 읽고 해당 값 날리기
.close() 자원 반납 후 스트림 닫기
    ※ .read() 값이 비어있으면 -1이 출력된다.
  • 사용 로직 
FileInputStream fIn = new FileInputStream("test.txt");
int value = 0;

while ((value = fIn.read()) != -1) {//대입으로 .read()한번만 처리
	System.out.println(value);
}

4-2. 문자 기반 스트림

2byte까지 지나갈 수 있는 Stream.

 

4-2-1. FileWriter

2byte가 이동하기 때문에 문자 단위 이동 가능. 이어쓰기 옵션도 가능하다.

try(FileWriter fw =new FileWriter("test.txt")){
	char[] ch = { 'a', 'b', 'c', '\n' };
	String str = "def";
	fw.write(ch);
	fw.write(str);//.write()는 오버로딩된 메소드라 여러 자료형 입력 가능
} catch (IOException e) {
	e.printStackTrace();
}

 

  • 사용하는 메소드
메소드 의미
.append() 뒤에 연결하여 출력
.write() 문자를 출력
.flush() 버퍼 모두 출력. 버퍼 비우기
.close() 자원 반납 후 스트림 닫기

4-2-2. FileReader

2byte가 이동하기 때문에 문자 단위 이동 가능. 

출력되는 내용은 아스키코드 값으로 나온다. 따라서 변환 과정이 필요하다.

try(FileReader fr = new FileReader("test.txt")){
	int value = 0;
	while ((value = fr.read()) != -1) {
	System.out.print((char)value);
	}
} catch (FileNotFoundException e) {
	e.printStackTrace();
} catch (IOException e) {
	e.printStackTrace();
}
  • 사용하는 메소드
메소드 의미
.read() 1바이트를 읽고 해당 값 날리기
.close() 자원 반납 후 스트림 닫기

Ⅴ. 보조 스트림

기반 스트림의 부족한 부분을 보조해주는 역할로, 단독 사용은 불가능하다.

바이트 기반 스트림(InputStream / OutputStream)의 보조 스트림은 InputStream / OutputStream,

문자 기반 스트림(Reader / Writer)의 보조 스트림은 Reader / Writer 이 붙어있다.

 

5-1. Buffer

기반 스트림은 1byte씩 옮겨지면서 지연시간이 생기지만, Buffer 보조 스트림으로 버퍼에 모았다가 한번에 처리.

처리 속도가 향상된다.

 

5-1-1. BufferedReader

문자로 읽어온다.

  • 기반메소드 FileReader 사용 : 파일에서 입력받기
BufferedReader br = new BufferedReader(new FileReader("test.txt"));
  • 기반메소드 InputStreamReader 사용 : 사용자에게서 입력받기
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int num = Integer.parseInt(br.readLine());
  • 사용 로직
//방법 1. while을 통해서 null 전까지 돌리기
try(BufferedReader br=new BufferedReader(new FileReader("c_buffer.txt"))){
	String str=null;
	while((str=br.readLine())!=null) {
		System.out.println(str);
	}
} catch (FileNotFoundException e) {
	e.printStackTrace();
} catch (IOException e) {
	e.printStackTrace();
}
		
		
//방법 1-1. while 대신 for문에서 break로 탈출하는 구문 만들기
try (BufferedReader br = new BufferedReader(new FileReader("c_buffer.txt"));) {
	for (;;) {
		String str = br.readLine();
	if (str == null)
		break;
		System.out.println(str);
	}
} catch (FileNotFoundException e) {
	e.printStackTrace();
} catch (IOException e) {
	e.printStackTrace();
}
				
		
//방법 2. stream.collect(Collectors.joining(문자열))을 사용
try(BufferedReader br=new BufferedReader(new FileReader("c_buffer.txt"))){
	String s=br.lines().collect(Collectors.joining("\n"));//stream 요소들을 joining으로 결합
	System.out.println(s);
} catch (FileNotFoundException e) {
	e.printStackTrace();
} catch (IOException e) {
	e.printStackTrace();
}
		
		
//방법 2-2. List 인스턴스에 집어넣기. 꺼내먹기
try(BufferedReader br=new BufferedReader(new FileReader("c_buffer.txt"))){
	List<String> list = br.lines().collect(Collectors.toList());
	//String형 list를 만들고 stream 요소들을 리스트에 하나씩 할당
	for(String str:list) {
		System.out.println(str);//리스트를 하나씩 출력
	}
	System.out.println("리스트에 넣으면 이렇게 따로도 사용할 수 있게 됨 : "+list.get(2));
} catch (FileNotFoundException e) {
	e.printStackTrace();
} catch (IOException e) {
	e.printStackTrace();
}
		
			
//방법 3. Path 클래스, ArrayList를 이용하여 파일의 내용을 출력하기.
Path path = Paths.get("c_buffer.txt");// Path를 이용하여 해당 파일의 경로를 반환해온다
Charset cs = StandardCharsets.UTF_8;// UTF_8 포멧(지정가능)으로 받아오는 문자셋
List<String> list = new ArrayList<String>();// String형의 ArrayList를 생성

try {
	list = Files.readAllLines(path, cs);
// path 경로의 파일을 cs 문자셋으로 리스트에 모든 라인을 받는다.
} catch (IOException e) {// IOException 예외처리(readAllLines에 대한 예외처리)
	e.printStackTrace();//오류가 나는 지점의 단계별로 에러를 출력.
}
for (String readLine : list) {//for each문.
	System.out.println(readLine);// readLine에 list의 내용물을 하나씩, list의 끝까지 돌린다.
	}
}

5-1-2. BufferedWriter

문자로 읽어온다. .newLine()으로 개행 추가 가능.

  • 기반 스트림 FileWriter 사용
BufferedWriter bw = new BufferedWriter(new FileWriter("test.txt"));
  • 기반 스트림 OutputStream 사용
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

 

5-1-3. BufferedInputStream / BufferedOutputStream

바이트 기반인 것, 출력에서 .newLine()이 안되는 것을 제외하고는 Reader/Writer 보조스트림과 동일하다.


5-2. Object

객체 단위로 처리.

 

5-2-1. ObjectOutputStream

객체 단위로 파일에 출력할 수 있게 돕는 보조스트림. 기반 스트림이 OutputStream 계열이므로 바이트 스트림이다.

따라서 객체가 1byte 통로를 통과할 수 있도록 직렬화가 필요하다. 

public void saveFile(String fileName){
	Student st = new Student("name",22,"운동부");

	try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(fileName))) {
		oos.writeObject(st);// NotSerializableException->Student(model.vo)클래스에 직렬화
	} catch (FileNotFoundException e) {
		e.printStackTrace();
	} catch (IOException e) {
		e.printStackTrace();
	}
}

※ 직렬화란?

방법 : 넘기려는 객체의 클래스에 Serializable 인터페이스를 implements하여 구현.

직렬화를 하면 모든 필드를 byte로 변환한다. transient 키워드를 사용한 필드는 직렬화에서 제외.

public class Student implements Serializable{
	//코드들...
}

5-2-2. ObjectInputStream

객체 단위로 읽어들이는 보조 스트림. InputStream임으로 byte단위 이동. 역직렬화가 필요하다.

public void readFile(String fileName) {
	try(ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName))) {
		Student st = (Student) ois.readObject();//역직렬화
		System.out.println(ph);
	} catch (FileNotFoundException e) {
		e.printStackTrace();
	} catch (IOException e) {
		e.printStackTrace();
	} catch (ClassNotFoundException e) {
		e.printStackTrace();
	}
}

 

※ 역직렬화란?

바이트단위로 불러들인 파일을 객체로 복원한다.

Student st = (Student) ois.readObject();//역직렬화

보조스트림의

기본 타입 입출력 : DataInputStream / DataOutputStream (항상 문자형으로 받으므로 다른 타입으로 변환)

-> parse해서 변환하는거랑 비슷한가?

'BACK-END > Java' 카테고리의 다른 글

[JAVA] Sevlet, JSP  (1) 2022.01.16
[JAVA] API-JDBC  (1) 2021.12.07
[Java] API-Collection과 Map  (0) 2021.11.23
[Java] API 기초와 java.lang  (1) 2021.11.22
[Java] 객체지향의 활용  (0) 2021.11.21