컴퓨터 이야기/프로그래밍

버퍼를 이용한 파일 읽기/쓰기,

래빗 크리스 2009. 12. 6. 18:26



버퍼를 이용한 파일 읽기와 쓰기는 서로 대응되는 메소드를 이용하면 되므로,
이곳에서는 파일을 Write 하는 방법만 기술합니다.
FileOutputStream 는 FileInputStream, BufferedOutputStream 는 BufferedInputStream 입니다.

덤으로, DB 에 Long Raw 로 저장된 내용을 가져와서 이미지 파일을 생성해 보겠습니다.
커넥션 맺는 부분은 환경에 따라 다르므로 이곳에서는 설명을 하지 않아요.
import 해야 하는 패키지는 머리를 굴려서 생각해 보세요..

Connection 과 PreapredStatement, ResultSet 등은 java.sql 패키지,
File FileOutputStream BufferedOutputStream 등은 java.io 패키지에 존재합니다.

Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;

File file = null;
FileOutputStream fos = null;
BufferedOutputStream bos = null; 

 try { 

  conn = ... ; /* 이 부분은 환경에 맞춰서 코딩해 주세요. */

  StringBuffer sb = new StringBuffer(); // 사실은 쿼리가 긴데 편의를 위해서 줄였고요, String 보다는 StringBuffer 가 좋져
  sb.append("select id, image from tableA");
  ps = conn.prepareStatement(sb.toString());
  conn.setString(1, ...); // PreparedStatement 라고 해서 반드시 파라미터가 있어야 하는 것은 아니지만..
  ...
  rs = ps.executeQuery();

  int cnt = 0; // 진행상황을 보려구 설정하였습니다.
  while(rs.next()){ 

   byte[] photo = rs.getBytes("photo"); // 이진파일을 다루려면 getString 하면 안 되고, getBytes 해야 합니다.
   String resno = rs.getString("id"); // 아이디에 맞춰서 파일을 생성하기 때문에.. 아이디를 따 왔습니다. 물론, Unique
   file = new File("/data1/dir1/" +resno+ ".jpg"); // 경로는 환경에 맞게 맞추세요. Stream 대상을 정의합니다.
   fos = new FileOutputStream(file); // 먼저는 Buffer 에 넣지만 다시 File 쪽으로 보내는 거죠.
   bos = new BufferedOutputStream(fos); // Buffer 에 넣기 때문에 남아있는 메모리 사이즈는 신경써야 하죠. 
   bos.write(photo, 0, photo.length); // Buffer 에 담은 것을 파일에 I/O 합니다.
   bos.flush(); // FileOutputStream 에는 flush 가 없지요. flush 를 해야지 메모리에 남기지 않고 몽땅 파일에 저장해요.

   if(++cnt % 100 == 0) System.out.println("Progress : "+cnt+"..");  // 이 부분은 진행상황을 보려구요..

  }   /* while(rs.next()){ */ 

 }catch(Exception e){

  StringBuffer sbLog = new StringBuffer(); // 버퍼에 담았다가 저장
  sbLog.append("\n"); // 다른 로그와 섞일까봐..
  sbLog.append("+++.메소드나 JSP 명을 넣으면 구분하기 쉽겠죠..\n");
  sbLog.append("+++.Exception:" +e.toString()+  "..\n");
  System.out.println(sbLog); // println 이기 때문에 맨 뒤에는 sbLog.append("\n"); 불필요.

 }finally{

  if (rs != null) try{ rs.close(); } finally { rs = null; } // ResultSet 도 close() 하는 습관을 들이세요.
  if (ps != null) try{ ps.close(); } finally { ps = null; } // PreparedStatement 도 close() 하는 습관을 들이세요.
  if (conn != null) try{ conn.close(); } finally { conn = null; } // Connection 도 close() 하는 습관을 들이세요.
  if (bos != null) try{ bos.close(); } finally { bos = null; } // BufferedOutputStream 도 close() 하는 습관을 들이세요.
  if (fos != null) try{ fos.close(); } finally { fos = null; } // FileOutputStream 도 close() 하는 습관을 들이세요.

 }


개략적으로 다시 설명하면,
File 개체를 생성해서 필요한 파일을 설정하고
(File 개체를 생성해도 파일이 실제로 생성되는 것은 아닙니다. 물론 이미 생성된 파일이라도 열어놓지도 않죠..),
FileOutputStream 과 BufferedOutputStream 를 이용하여 필요한 개체를 차례로 생성하고
(new BufferedOutputStream(new FileOutputStream(new File("..."))) 하는 분도 있던데 말리지는 않지만..),
저장할 내용을 BufferedOutputStream.write() 하고 BufferedOutputStream.flush() 로 버퍼 내용을 떨어낸 다음
(fush() 는 반드시 기술해 주어야 합니다. 간혹 메모리에서 파일로 저장하기 전에 close() 할 수 있습니다),
BufferedOutputStream.close() 와 FileOutputStream.close() 작업을 합니다
(BufferedOutputStream 와 FileOutputStream 양쪽 모두 close() 해 주세요.).

정상적으로 처리가 된다면 불필요 하게 예외 처리와 예외 처리를 위한 준비작업을 할 필요는 없겠지요.
그러나, 어떤 조건이나 상황에서든 예외는 발생하기 때문에 반드시 예외 처리를 해 주어야 합니다.