ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 학원 day54. 스트림, 첨부파일 다운로드, 파일에 텍스트 기록
    기록 2022. 11. 21. 16:22

    읽기(입력)전용스트림

    InputStream

    - 데이터를 읽을 때 한 바이트(1byte=8bit)씩 읽어오는 객체

    - 브라우저가 웹서버로 보낸 바이너리 데이터를 읽어오는 객체

    - request.getInputStream()을 실행해서 획득한다.

    Reader

    - 데이터를 읽을 때 한 글자씩 읽어오는 객체

    - 브라우저가 웹서버로 보낸 텍스트 데이터를 읽어오는 객체

    - request.getReader()를 실행해서 획득한다.

    * 브라우저가 서버로 보낸 모든 요청 메세지는 톰캣이 분석해서 요청객체에 저장하고, 요청객체를 서블릿/JSP에 전달하기 때문에 개발자가 직접 InputStream과 Reader를 사용할 일은 없다. 

     

    출력전용 스트림

    OutputStream

    - 1byte씩 출력하는 객체

    - 웹서버가 브라우저로 바이너리 데이터를 출력할 때 사용하는 객체

    - response.getOutputStream()을 실행해서 획득한다.

    - 주로 파일 다운로드를 구현할 때 사용한다.

    Writer

    - 1글자씩 출력하는 객체

    - 웹서버가 브라우저로 텍스트 데이터를 출력할 때 사용하는 객체

    - response.getWriter()을 실행해서 획득한다.

    - 서블릿/JSP에서 HTML 컨텐츠를 응답으로 보낼 때 사용한다.

    - 서블릿 : response.getWriter()를 실행하면 PrintWriter가 획득된다.

    - JSP : pageContext.getWriter()를 실행하면 JspWriter가 획득된다.

    * JSP에서는 out 내장객체 변수에 JspWriter가 대입되어 있고, 

    out.write("<태그>내용</태그>");로 HTML 컨텐츠를 응답으로 보낸다.

    * 서블릿에서는 response.getWriter를 실행해서 PrintWriter를 획득하고,

    PrintWriter의 println("<태그>내용</태그>")로 응답을 보낸다.

     


    첨부파일 업로드 및 파일 다운로드

    < register.jsp >

    < detail.jsp >

     

    < FileDownloader.java >

    // 파일다운로드를 요청하는 URL : http://localhost/web-board/download?no=글번호
    @WebServlet("/download")
    public class FileDownloader extends HttpServlet {
    	
    	private String directory = "c:\\app\\web-workspace\\temp";
    
    	@Override
    	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		
    		// 쿼리스트링으로 전달된 글번호를 조회한다.
    		int boardNo = StringUtils.stringToInt(request.getParameter("no"));
    		
    		// BoardDao객체를 생성하고, 글번호에 해당하는 게시글 정보를 조회한다.
    		BoardDao boardDao = new BoardDao();
    		Board board = boardDao.getBoardByNo(boardNo);		
    		// 첨부파일의 파일명을 조회한다.
    		String fileName = board.getFileName();
    		
    		///////////////////////////////////////////////////////////////////////
    		// 파일 다운로드
    		///////////////////////////////////////////////////////////////////////
    		
    		// 1. 응답컨텐츠의 타입을 지정한다.
    		// 		application/octet-stream은 바이너리 데이터 타입의 기본값이다.
    		//      컨텐츠 타입을 알 수 없는 바이너리 데이터는 application/octet-stream을 컨텐츠 타입으로 지정한다.
    		response.setContentType("application/octet-stream");
    		// 2. 응답메세지의 헤더부에 다운로드되는 파일이름 정보를 추가한다.
    		//      Content-Disposition은 응답 헤더이름이다.
    		//      Content-Disposition을 이용해서 다운로드되는 파일이름 정보를 응답메세지의 응답헤더부에 포함시킨다.
    		//      Content-Disposition의 응답헤더값은 "attachment; filename=파일명"이다.
    		//      "attachment;"는 첨부파일을 브라우저창에서 오픈없이 저장시킨다.
    		//      "filename=파일명"은 다운로드되는 파일명을 지정한다.
    		//      "filename=" + URLEncoder.encode(fileName, "utf-8")는 파일명에 한글이 포함되어 있을 경우, 
    		//       한글이 깨지지 않도록 utf-8방식을 한글을 변환해서 응답으로 보낸다.
    		response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "utf-8"));
    		
    		// 3. 다운로드할 파일을 읽어오는 FileInputStream객체를 생성한다.
    		//      FileInputStream 객체는 파일을 읽어오는 객체다.
    		//      new File(디렉토리, 파일명)은 파일의 정보를 표현하는 객체를 생성한다.
    		//      new FileInputStream(new File(디렉토리, 파일명));은 파일객체가 표현하는 파일을 읽어오는 객체를 생성한다.
    		// 지정된 디렉토리와 파일명으로 저장된 파일을 읽어오는 FileInputStream 객체를 생성한다.
    		InputStream in = new FileInputStream(new File(directory, fileName));
    		// 4. 응답객체가 브라우저로 바이너리 데이터를 출력할 때 사용하는 객체를 획득한다.
    		//      response.getOutputStream()을 실행하면 OutputStream 객체를 반환한다.
    		//      response.getOutputStream()을 실행해서 획득한 OutputStream객체는 브라우저로 출력하는 객체다.
    		// 브라우저로 바이너리데이터를 출력하는 OutputStream 객체를 획득한다.
    		OutputStream out = response.getOutputStream();
    		// 5. IOUtils클래스의 copy(InputStream in, OutputStream out)은 in으로 읽어온 바이너리 데이터를 out으로 내보낸다.
    		IOUtils.copy(in, out);
    		// 6. InputStream과 OutputStream은 컴퓨터의 읽기/쓰기 자원을 사용하기 때문에 읽기/쓰기 작업이 완료되면 사용했던 자원을 반납한다. (반납하지 않으면 다른 곳에서 쓸 수 없게 된다.)
    		in.close();
    		out.close();
    	}
    }

     

    text/plain 은 텍스트파일의 기본값이다.

    application/octet-stream 은 메모장으로 읽을 수 없는 바이너리타입의 기본값이다.


    I/O (Input, Output)

    - java.io 패키지의 클래스

    - 애플리케이션에서 리소스를 읽어오거나, 애플리케이션의 데이터를 목적지로 출력하는 작업을 수행하는 클래스

    Stream

    - 데이터의 흐름이다.

     

    ByteStream

    - 한 번에 1byte씩 읽거나 쓰는 스트림

    - 텍스트데이터와 바이너리데이터(그림, 영상, 파일)를 읽고 쓸 수 있다.

    - 종류

       InputStream

           리소스로부터 1byte씩 읽어오는 스트림

           주요메소드

                 int read()   - 1byte씩 읽어서 정수로 반환한다.

                 int read(byte[] buf) - 1byte씩 읽어서 byte[]배열에 순서대로 저장하고, 배열에 저장된 갯수를 반환한다.

                 void close() - 읽기 작업을 위해서 사용했던 컴퓨터의 자원을 반납한다.

       OutputStream

           리소스로 1byte씩 출력하는 스트림

           주요메소드

                 void write(int value) - 1byte씩 출력한다.

                 void write(byte[] buf, int offset, int length) - byte배열의 데이터를 offset 위치에서 length만큼 출력한다.

                 void flush() - 임시저장소(버퍼)에 저장된 모든 데이터를 내보낸다.

                 void close() - 쓰기 작업을 위해서 사용했던 컴퓨터의 자원을 반납한다.

     

    - 대표적인 클래스

       FileInputStream      - 파일로부터 1byte씩 데이터를 읽어온다.

       FileOutputStream   - 파일로 1byte씩 데이터를 출력한다.

       BufferdInputStream - 다른 InputStream의 읽기 성능을 향상시킨다.

       BufferdOutputStream - 다른 OutputStream의 쓰기 성능을 향상시킨다.

       DataInputStream - 데이터 타입 그대로 읽어온다.

       DataOutputStream - 데이터 타입 그대로 출력한다.

       ObjectInputStream - 직렬화된 객체를 스트림으로 읽어서 객체로 복원한다.(역직렬화)

       ObjectOutStream - 객체를 스트림으로 출력한다.(직렬화)

       PrintStream - 대표적인 출력스트림이다.

     

    CharacterStream

    - 한 번에 1글자씩 읽거나 쓰는 스트림

    - 텍스트데이터만 읽고 쓸 수 있다.

    - 종류

       Reader

            리소스로부터 1글자씩 읽어오는 스트림

       Writer

            리소스로 1글자씩 출력하는 스트림

    - 대표적인 클래스

         FileReader - 한 글자씩 읽어온다.

         FileWriter - out.write으로 텍스트 출력(줄바꿈 불가능, 버퍼기능이 있음)

         BufferedReader - 한 줄씩 읽어온다.

         BufferedWriter

         InputStreamReader

         OutputStreamWriter

         PrintWriter - out.println으로 텍스트 출력(줄바꿈 가능)


    파일에 텍스트 기록하기(출력하기)

    FileOutputStream 이용
    FileOutputStream 텍스트
    PrintStream 이용
    PrintStream 텍스트
    FileWriter 이용
    FileWriter 텍스트

    - > flush()는 8196박스가 다 안차도 올려보내준다.

     

    PrintWriter 이용
    PrintWriter 텍스트

    FileWriter와 PrintWriter는 버퍼에 저장했다가 flush를 실행하여 내보낸다. flush 하기 전에는 파일에 기록이 안된다.

    텍스트를 출력할 때는 PrintWriter를 주로 사용한다.

    파일에 기록할 때 OutputStream을 쓰기도 하지만 파일 다운로드를 할 때에도 OutputStream을 쓴다.

    파일에 뭔가를 기록하는 것은 text를 기록하는 것이다.

    그런데 text를 빼고는 모든 행위가 복사인 경우가 많다. 


    파일의 데이터 읽어오기

    FileInputStream은 데이터를 한 바이트씩 읽어온다.

    D 한글자만 넣었을 경우 더이상 읽어올 게 없어서 -1이 반환된다.

    in.read()로 한byte씩 읽어서 value에 담는다. 

     

    영어의 경우 2BYTE로 표현되는데 앞이 0이기 때문에 1BYTE만 넣어도 그대로 나온다.

    한글의 경우 깨져서 나온다. 2BYTE를 합쳐서 하나의 글자가 완성되기 때문이다.

    하지만, CharacterStream을 사용하면 한글자씩 읽기 때문에 깨지지 않는다.


    텍스트 데이터의 유형

    텍스트 데이터 분석시, 무형식의 데이터보다는 데이터가 어떤 데이터인지를 알려주는 메타정보(ex. <tilte>, "title")가 추가된 데이터를 분석할 일이 대부분이다. (공공데이터포털 사이트의 데이터도 대부분 csv, json, xml 등으로 되어 있다.)

    그런데  csv, json, xml 전용 라이브러리가 있기 때문에 갖다가 쓰면 된다.


    분석의 대상이 되는 데이터를 읽어올 때는 BufferedReader를 사용한다. 텍스트를 한 줄씩 읽어온다.

    다른 스트림은 읽어올 게 없으면 -1을 반환하지만 BufferedReader의 경우만, 읽어올 게 없으면 null을 반환한다.

     

    텍스트를 다룰 때는 두가지를 기억하자! 

    출력할 때는 printWriter, 읽어올 때는 BufferedReader를 사용한다.

    위의 코드를 다음과 같이 라이브러리를 통해 코드를 간략하게 만들수도 있다.

    Apache.org에서 Commons프로젝트에서 IO라이브러리(commons-io-2.11.0-bin.zip)을 다운로드 받고 그 안의 

    commons-io-2.11.0 jar 를 이클립스 lib폴더에 추가한다. build path - addjar

    jpg 파일을 읽어온 것을 확인할 수 있다.

     

    자원(텍스트 데이터, 바이너리 데이터)의 복사

    - 대부분의 입/출력 작업은 자원을 복사하는 작업이다.

    - 원본 리소스를 읽어와서 대상 리소스로 출력하는 것이다.

    예시

    - 첨부파일 업로드 처리 : 서버로 업로드된 첨부파일을 읽어서 지정된 경로에 파일로 출력하는 것이다.

    - 첨부파일 다운로드 처리 : 서버의 지정된 폴더에 저장된 파일을 읽어서 브라우저와 연결된 출력스트림으로 출력하는 것이다.


    - BufferedInputStream, BufferedOutputStream은 다른 스트림의 성능을 향상시켜준다.

    - 스트림은 다른 스트림과 연결해서 사용할 수 있다.

    - FileInputStream은 만번의 read()를 실행시켜야 하지만 BufferedInputStream을 붙이면 2번만 read()를 실행한다.

     

     

    댓글

Designed by Tistory.