Back-end/Java Language

입출력(I/O)

prden 2021. 6. 7. 13:36

1.1 의미 :

입출력은 컴퓨터 내부 또는 외부의 장치와 프로그램 간의 데이터를 주고받는 것을 의미한다. 

 

1.2 스트림 :

한쪽에서 다른 한쪽으로 데이터를 전달하려면 1. 두 대상을 연결하고, 2. 데이터를 전송할 수 있는 무언가가 필요한데 이를 스트림이라고 한다. 즉, 데이터를 운반하는 데 사용되는 연결 통로가 스트림인 것이다. 

 

1.3 바이트기반 스트림 : 

1) 입력 스트림 : FileInputStream(파일), ByteArrayInputStream(메모리), PipedInputStream(프로세스), AudioInputStream(오디오 장치)

2) 출력 스트림 : FileOutputStream, ByteArrayOutputStream, PipedOutputStream, AudioOutputStream

-> 이들은 모두 InputStream Ehsms OutputStream의 자손들이며, 각각 읽고 쓰는데 필요한 추상 메서드를 자신에 맞게 구현해 놓았다. 

 

1.4 보조 스트림:

보조 스트림은 실제 데이터를 주고받는 스트림이 아니기 때문에 데이터를 입출력할 수 있는 기능은 없지만, 스트림의 기능을 향상하거나 새로운 기능을 추가할 수 있다. 그래서 보조 스트림만으로는 입출력을 처리할 수 없고, 스트림을 먼저 생성한 다음 이를 이용해서 보조 스트림을 생성해야 한다. 

// 먼저 기반 스트림을 생성하기
FileInputStream fis = new FileInputStream("test.txt");
// 기반 스트림을 이용해서 보조스트림을 생성한다. 
BufferedInputStream bis = new BufferedInputStream(fis);
bir.read(); // 보조 스트림인 BufferedInputStream으로부터 데이터를 읽는다. 

 

1.5 문자기반 스트림 : Reader, Writer

바이트 기반은 입출력의 단위가 1 byte이라는 뜻이다. java에서는  char형이 1byte가 아니라 2 byte이기 때문에 바이트 기반의 스트림으로 2 byte인 문자를 처리하는 데는 어려움이 있다. 이를 보완하기 위해 등장한 것이 문자 기반의 스트림이다. 

InputStream -> Reader

OutputStream -> Writer

 

1.6 관련 메소드

1) abstract int read() :

1byte를 읽어온다(0~255 사이의 값) 더 이상 읽어 올 데이터가 없으면 -1을 반환한다. abstract메서드라서 inputStream의 자손들은 자신의 상황에 알맞게 구현해야 한다. 

2) int read(byte [] b) :

 배열 b의 크기만큼 읽어서 배열을 채우고 읽어 온 데이터의 수를 반환한다. 반환하는 값은 항상 배열의 크기보다 작거나 같다. 

3) void flush() :

 스트림 버퍼에 있는 모든 내용을 출력 소스에 쓴다. 

4) void writed(byte [] b, int off, int len) :

 주어진 배열 b에 저장된 내용 중에서 off번째부터 len개만큼만을 읽어서 출력 소스에 쓴다. 

 

*스트림에 읽고 쓰는 방법

class IOEx1{
	public static void main(String [] args){
    	byte[] inSrc = {0,1,2,3,4,5,6,7,8,9};
        byte[] outSrc = null;
        
        ByteArrayInputStream input = null;
        ByteArrayOutputStream output = null;
        
        input = new ByteArrayInputStream(inSrc);
        output new ByteArrayOutputStream();
        
        int data = 0;
        
        while((data = input.read())!=-1){
        	output.write(data); //void write(int b)
            }
        outSrc = output.toByteArray(); // 스트림의 내용을 byte 배열로 반환한다. 
        
        //아래와 같이 한 번에 배열의 크기만큼 읽고 쓸 수도 있다. 
        //input.read(temp,0,temp.length); // 읽어온 데이터를 배열 temp에 담는다. 
        //output.write(temp,5,5); // temp[5]부터 5개의 데이터를 write한다.
        
        System.out.println("Input Source :" + Array.toString(inSrc));
        System.out.println("Output Source :" + Array.toString(outSrc));
        }
     }

 

※파일 다운로드 예시 코드

package com.legalcounsel.Common;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;

@Controller
public class FileDownloadCtr {
    static final Logger LOGGER = LoggerFactory.getLogger(FileDownloadCtr.class);

    /**
     * 파일(첨부파일, 이미지등) 다운로드.
     */
    @RequestMapping("/fileDownload")
    public void fileDownload(HttpServletRequest request, HttpServletResponse response) {
        String path = LocaleMessage.getMessage("info.filePath");

        //Querystring을 통해 받아 오는 경우
        String filename = request.getParameter("filename");
        String downname = request.getParameter("downname");
        String realPath = "";

        if (filename == null || "".equals(filename)) {
            filename = downname;
        }

        try {
            filename = URLEncoder.encode(filename, "UTF-8");
        } catch (UnsupportedEncodingException ex) {
            LOGGER.error("UnsupportedEncodingException");
        }

        realPath = path + downname.substring(0,4) + "/" + downname;

        File file1 = new File(realPath);
        if (!file1.exists()) {
            System.out.println("##### 다운로드하려는 파일이 존재하지 않습니다. #####");
            return ;
        }

        // 파일명 지정실제로 파일이 저장된 위치에서 해당 첨부파일을 읽어서 byte[] 형태로 변환
        response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
        try {
            OutputStream os = response.getOutputStream();
            FileInputStream fis = new FileInputStream(realPath);

            int ncount = 0;
            byte[] bytes = new byte[512];

            while ((ncount = fis.read(bytes)) != -1 ) {
                os.write(bytes, 0, ncount);
            }
            fis.close();
            os.close();
        } catch (FileNotFoundException ex) {
            LOGGER.error("FileNotFoundException");
        } catch (IOException ex) {
            LOGGER.error("IOException");
        }
    }

}