본문 바로가기

Java/Java 2

[Java] 7. 입출력 프로그래밍

반응형

자바 IO

 

스트림 : 자료의 입출력을 도와주는 중간 매개체

 

 

 

스트림

  • java.io : 입출력을 위한 패키지 즉 자바의 기본 입출력 프로그래밍 방법
  • 대용량의 데이터를 순차적 처리하는 프로그램에 적합
  • 단방향으로 입력 스트림과 출력 스트림을 각각 사용해야 한다.

 

스트림의 종류

  • 문자 스트림
  • 바이트 스트림
  • # 보조 스트림

 

-> 데이터 전달 방식에 따라 구분

 

 

바이트 스트림

  • 바이너리 데이터 입출력
  • 1바이트 단위로 처리
  • 이미지 및 동영상 송수신 할 경우에 적합
  • 주요 클래스 : InputStream, OutputStream 클래스

문자 스트림

  • 텍스트 데이터 입출력
  • 2바이트 단위로 처리
  • 텍스트 및 Json, HTML 데이터 송수신 할 경우에 적합
  • 주요 클래스 : Reader, Writer 클래스

보조 스트림

  • 기존 스트림과 결합해 사용
  • FilterInputStream과 FilterOutputStream을 상속받는 클래스
    • BufferInputStream / BufferdOutputStream
      • 버퍼 사용해 입출력 효율과 편의 증대
    • BufferedReader / BufferedWriter
      • 라인 단위의 입출력
    • InputStreamReader / OutputStreamReader
      • 바이트 스트림을 문자 스트림처럼 사용
      • 문자 인코딩 변환 지원
    • DataInputStream / DataOutputStream
      • 자바 원시자료형 데이터 처리에 적합

 

 

package com.dinfree_1115;

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

public class BasicIOTest {
	public static void main(String[] args) {
		InputStream in = System.in;		// System 클래스 변수 in과 out이 연결된 InputStream과 OutputStream -> 키보드와 콘솔로 연결
		OutputStream out = System.out;
		
		int input;
		try {
			System.out.print("## Input 1~3 character : "); //input 1byte from keyboard
			
			input = in.read();			//read 메서드는 1바이트인 숫자나 영문만 가능 [한글은 2바이트]
			System.out.println("## 1byte read and print");
			System.out.println(input);
			out.write(input);
			//out.flush();
			
			/* 
			//input 3byte from keyboard
			byte [] b=new byte[3];
			in.read(b);
			System.out.println("## 3byte read and print");
			out.write(b);
			*/
			
			//입력내용을 모두 처리하려면 반복해서 읽도록 해야 하므로 처리가 불편
			
			out.close();
			
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		
	}

}

 

package com.dinfree_1115;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStreamReader;

public class Ch7Ex4 {

	public static void main(String[] args) {
		File rfile = new File("c:/tmp/tmpfile.txt");
		File wfile = new File("c:/tmp/tmpfile_new.txt");
		
		try {

			BufferedReader reader = new BufferedReader(new FileReader(rfile));	//라인 단위 입출력 지원, 보조 스트림으로 기본 스트림과 결합해서 사용
			BufferedWriter writer = new BufferedWriter(new FileWriter(wfile));	//문자 스트림인 FileReader과 FileWriter 결합

			String s;
			while((s=reader.readLine()) != null) {		//BufferedReader 객체인 reader의 readLine 함수를 이용해 읽어온다.
				writer.write(s+"-라인종료\r\n");	//BufferedWriter 객체인 writer의 write 함수를 이용해 읽어온 라인을 작성.
			}
			reader.close(); writer.close(); //스트림 종료까지 필수
			//rfile.delete();
			
		} catch (Exception e) { //스트림 사용시 예외처리 확인
			e.printStackTrace();
		}
		System.out.println("Done...");
	}

}

자바 NIO

스트림 기반 자바 IO은 블로킹 기반으로 동시작업이 불가능한 문제를 해결

-> New IO / Non-blocking IO로 비동기 논블로킹 처리

-> 스트림이 아닌 채널을 사용해 동시에 많은 접속 가능

-> 단일 작업에 입출력 처리가 오래걸리지 않은 프로그램에 적합

 

 

스레드

자바 IO에서 동시작업을 위해서 사용

-> 대규모의 클라이언트인 경우 부하가 발생해 성능이 저하

 

버퍼

  • OS 커널의 시스템 메모리를 직접 사용하는 Buffer 클래스

채널

  • 입출력이 동시에 가능한 양방향 입출력 클래스
  • Natvie IO, Scatter/Gather 구현으로 효율적으로 IO관리

셀렉터

  • 네트워크 프로그래밍 효율 증가
  • 클라이언트당 스레드 하나 생성하는 IO 개선하는 Reactor 패턴 구현체

NIO의 채널

  • FileChannel
    • 파일 입출력을 위해 사용
  • DatagramChannel
    • 네트워크를 이용 UDP 통신
  • SocketChannel
    • 네트워크를 이용 TCP 통신
  • ServerSocketChannel
    • 서버 연결을 지원하기 위해 사용

 

Path를 이용하는 경우 / FileChannel를 이용하는 경우

 

Path를 이용하는 경우 

Path path = Paths.get("tmp/testfile.txt");				//Path 클래스로 파일에 대한 참조 생성
try(BufferedWriter writer = Files.newBufferedWriter(path, Charset.forName("UTF-8"))){
	writer.write("To be, or not to be. That is the question.");	//BufferedWriter 클래스의 write 메서드를 이용해 작성
}catch(IOException ex){
	ex.printStackTrace();
}

 

FileChannel를 이용하는 경우

FileInputStream fis = new FileInputStream("c:/tmp/testfile.txt");
FileChannel fileChannel2 = fis.getChannel();			//FileInputSteram으로 파일 채널 생성

ByteBuffer buffer = ByteBuffer.allocateDirect(data.length());	//채널에 사용할 ByteBuffer 생성
Charset charset = Charset.forName("UTF-8");

buffer = charset.encode("Hello World");
int byteCnt = fileChannel.write(buffer);			//FileChannel의 write() 메서드로 데이터 출력
fileChannel.close();

 

자바 IO   -> 스트림, 단방향, 단일 작업에 입출력 많음

자바 NIO -> 채널,    양방향, 동시작업 가능해 동시에 많은 접속 가능

 


파일 입출력

 

파일과 디렉토리

 

텍스트 파일과 바이너리 파일

  • 텍스트 파일
    • 파일 내용이 일반텍스트
  • 바이너리 파일
    • 이진 형식으로 이루어진 파일
  • 입출력시 파일 내용에 따라 처리가 달라진다.

 

java.io 패키지를 이용한 파일 입출력

  • File클래스를 통해 핸들링하며 다양한 정보 참조 가능
  • FileReader등 입력 스트림으로도 경로 기반 파일 처리 가능

  •  java.io.File
    • 파일과 디렉토리 자체에 대한 정보 제공 클래스
    • 파일이나 디렉토리 관리나 파일 생성 클래스
    • java.nio.file.Path로 변환 가능

Java IO 파일 입출력

  • 텍스트 파일인 경우 문자 스트림 클래스
  • 바이너리 파일인 경우 바이트 스트림 클래스
  • 정해진 경로를 기반으로 파일 생성 -> 파일로부터 입력 스트림과 출력 스트림 생성 -> 읽기/쓰기 작업 수행

 

텍스트 파일의 경우

//경오 지정하지 않은 경우 프로젝트 폴더 기준
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
BufferedReader bw = new BufferedWriter(new FileWriter("b.txt"));
//File 클래스 사용하지 않고도 파일 생성 및 참조 가능

String s;
while((s=br.readLine()) !=null){	//BufferedReader를 이용해 a 텍스트파일을 String 변수에 읽어오기
	bw.write(s+"\n");		//BufferedWriter를 이용해 b 텍스트파일에 String 변수를 쓰기
}

 

이진 파일의 경우

//경오 지정하지 않은 경우 프로젝트 폴더 기준
BufferedReader is = new BufferedReader(new FileReader("a.jpg"));
BufferedReader os = new BufferedWriter(new FileWriter("b.jpg"));
//File 클래스 사용하지 않고도 파일 생성 및 참조 가능

byte[] buffer = new byte[16384];//버퍼 크기 : 16KB
while(is.read(buffer) != -1) {	//BufferedReader를 이용해 a 이미지파일을 buffer에 읽어오기
	os.write(buffer);	//BufferedWriter를 이용해 b 이미지파일에 buffer를 쓰기
}

 

이미지 프로그램

package com.dinfree_1115;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class BinaryFileTest {
	public static void main(String[] args) {
		try {
			BufferedInputStream is = new BufferedInputStream(new FileInputStream("a.jpg"));
			BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream("b.jpg"));

			byte[] buffer = new byte[16384];
			while(is.read(buffer) != -1) {
				os.write(buffer);
			}
			is.close();
			os.close();
		
			
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}

}

 

메모장 프로그램

package com.dinfree_1115;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Scanner;

public class Ch7Ex5 {

	public static void main(String[] args) {
		System.out.println("## 간단 메모장 v1.0 ##");
		System.out.print("## 저장할 파일명: ");
		Scanner scanner = new Scanner(System.in);			//scanner 클래스를 이용해 읽어오기
		String filename = scanner.next();					//가져온 문자열을 filename에 지정
		System.out.println("## 저장은 마지막 라인에 q 입력\n");
		
		try {
			BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
			//BufferedReader 보조 클래스와 InputStreamReader를 결합해 가져오기
			
			BufferedWriter writer = new BufferedWriter(new FileWriter("e:/dev/"+filename));
			//BufferedReader 보조 클래스와 OutputStreamReader를 결합해 가져온 데이터를 쓰기
			
			String s;
			while(!(s=reader.readLine()).equals("q")) {		//BufferedReader를 이용해 읽어오다가 q를 누를 경우 쓰기시작 
				writer.write(s+"\r\n");
			}
			reader.close();
			writer.close();
			scanner.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("## 프로그램을 종료 합니다.");
		System.out.println(filename+" 저장되었습니다.!!");	
	}
}

 

데이터를 구분한 메모장 프로그램

  • StringTokenizer를 이용해 데이터를 구분해 처리
  • StringTokenizer
    • 문자열을 지정한 구분자로 문자열을 쪼개주는 클래스
    • Token (토큰)
      • 쪼개진 문자열
    • java.util.StringTokenizer 클래스 [보통 public으로 사용]
      • StringTokenizer(String str)
        • 기본 delimiter는 공백문자열
      • StringTokenizer(String str, String delim)
        • 특정 delimiter를 지정
      • StringTokenizer(String str, String delim, boolean returnDelims)
        • 특정 delimiter로 분리하는 경우에 delim까지 token으로 포함할지 결정
        • true일 경우 포함 / false일 경우 포함 X
      • int countTokens()
        • 남아있는token 개수 반환
        • 전체 token 개수와 구분해서 사용
      • boolean hasMoreElements() / boolean hasMoreTokens()
        • 어떤 위치의 토큰을 사용하는지 기억하고 있는데, 그 위치를 옮기는 방법
        • 같은 값을 반환
      • Object nextElement() / String nextToken()
        • 반환형은 다른 같은 객체를 반환

 

 

StringTokenizer 사용해 쉼표로 구분된 데이터를 읽어 처리해서

addrbook.csv 파일을 읽어 화면에 이름, 전화번호, 이메일을 출력하는 예제

public class AddrBook {
	public static void main(String[] args) {
		File rfile=new File("addrbook.csv");

	
	try {
		BufferedReader reader = new BufferedReader(new FileReader(rfile));
		BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));
		
		String s;
		while((s=reader.readLine()) !=null) {
			StringTokenizer stk = new StringTokenizer(s,",");
			while(stk.hasMoreTokens()) {
				System.out.print(stk.nextToken());
				
				 if(stk.countTokens()==0) { 		
					 System.out.println();
				 }else
					 System.out.print(", ");
				
			}
		}
		
		reader.close();
		writer.close();
		
	} catch (Exception e) {
		// TODO: handle exception
		e.printStackTrace();
	}
 }
}
반응형