WebRowSet 을 이용한 JDBC 활용하기 2부

ResultSet 이용하기


아래에 이어질 예제는 JDK5.0과 Oracle 데이터베이스 10.2를 이용하여 진행하고 있음을 밝혀둡니다.

자.. 'student'라는 테이블에 아래와 같은 데이터를 갖는 간단한 데이터베이스가 있다고 합시다.

SQL> select * from student;

사용자 삽입 이미지






시작에 앞서, 위의 student 테이블을 가지고있는 데이터베이스에서 각 레코드를 조회하여 result set을 얻어오는
간단한 java 어플리케이션을 짜 보도록 합시다.

[code]
public class DatasourceConnector {
    public static void main(String[] args) {

        Connection con = null;
        OracleDataSource ds = null;

        try {

            ds = new OracleDataSource();
            ds.setUser("<dbuser>");
            ds.setPassword("<password>");
            ds.setURL("jdbc:oracle:thin:@localhost:1521:<sid>");

        } catch (SQLException e) {
            e.printStackTrace();
        }

        try {

            con = ds.getConnection();
            Statement stmt = con.createStatement();
            ResultSet rs = stmt.executeQuery("select * from student ");

            for (int j = 0; j < rs.getMetaData().getColumnCount(); j++) {
                System.out.print(
                    rs.getMetaData().
                    getColumnName(j + 1) + "\t");
            }

            while (rs.next()) {
                System.out.print("\n");
                for (int i = 0; i < rs.getMetaData().getColumnCount(); i++) {
                    System.out.print(rs.getString(i + 1) + "\t");
                }
            }

            rs.close();
            stmt.close();
            con.close();

        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
[/code]

예제의 자바 클래스는 connection 인스턴스를 최기화 하고, 수행할 SQL문자열을 포함하는 statement 를 생성한 후
result set을 조회하는 아주 일반적인 JDBC 코딩 양식을 보여주고 있습니다. 위 코드를 DatasourceConnector.java란
이름으로 저장하고 컴파일, 실행을 하면

>javac DatasourceConnector.java
>java DatasourceConnector

아래와 같은 결과를 출력하게 됩니다.

ID    FNAME  LNAME   AGE
200  Jack      Dakota    21
100  John      Doe        26

다음편으로 ..

2008/11/09 14:30 2008/11/09 14:30
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

WebRowSet 을 이용한 JDBC 활용하기 1부

RDBMS는 Data 질의와 갱신에을 위해 가장 광범위하게 이용되는 영구 저장 메카니즘(persistance storage mechanism) 입니다. Java Database Connectivity (JDBC) 는 Java 프로그램이 RDBMS 상의 데이터를 SQL을 이용하여  조작할 수 있게끔 해주는 프레임워크의 API 모임입니다.

Java 프로그램에서 데이터베이스의 데이터를 조회하거나 갱신하는데는 일련의 순서가 있습니다.
첫째로, 프로그램은 접속하고자하는 DataBase에 커넥션이 맺어져야 합니다.
이 커넥션을 맺는데는 몇 가지 다른 방법이 있습니다.. 관습적인 방법으로는 벤더에서 제공하는 JDBC드라이버를 로딩한 후 java.sql.DriverManger 클래스의 getConnection() 메소드를 호출하는 방법이 있을수 있습니다.
또 다른 한가지 방법은 접속하고자하는 데이터베이스를 개발한 회사에서 제공해 주는 java.sql.Connection 인터페이스를 구현한 클래스를 이용하는 방법이 있을수 있고,  Java EE 컨테이너에서처럼 JNDI (Java Naming Direvtory Interface) lookup을 통해 커넥션을 맺는 방법도 있겠네요.
어느 방법을 이용하든 Java 프로그램은 java.sql.Connection 인터페이스를 이용하여 데이터베이스와 커넥션을 맺게됩니다.
둘째로, 위에서 얻어온 Connection 객체로부터 Query를 DataBase로 전송하기위한 java.sql.Statement 인터페이스를 생성합니다.
마지막으로 Statement의 실행 결과를 java.sql.ResultSet 인스턴스로 돌려 받습니다.

본 포스팅에서는 JDBC version 3.0을 지원하는 JDK version 5.0에서 새로이 등장한 WebRowSet을 이용하는 방법을 알아보겠습니다.  
JDBC 3.0은 데이터의 생성과 변형을 손쉽게 해 낼 수 있는 몇 가지 기능을 제공합니다.


WebRowSet 계층구조


본격적인 WebRowSet의 이야기에 앞서 WebRowSet 인터페이스의 상속 계층 구조를 먼저 살펴 보도록 하겠습니다.
WebRowSet Hierarchy

WebRowSet inheritance Hierarchy(출처:OnJava)


상속관계에서 Root는 java.aql.ResultSet 인터페이스 입니다. 이 인터페이스의 인스턴스는 데이터베이스가 해석할수 있는 query를 포함하는 java.sql.Statement 인스턴스를 실행함으로써 얻어지는 표 형식의 데이터입니다. 기본적으로 result set은 앞으로만 탐색할 수 있고 업데이트를 할 수 없습니다. default result set을 가지고는 임의의 위치에 있는 데이터를 다룰 수 없다는 말이 됩니다.

자. result set에 담아진 임의의 위치에 있는 테이터를 제어하려면 어떤 방법이 있을까요? result set으로 무엇을 하길 원하는지에 따라 달라집니다. 예를들어 JavaBeans component model을 지원하기위해서는 java.sql.ResultSet의 서브인터페이스인 javax.sql.RowSet 인터페이스를 이용할 필요가 있겠죠.

자바프로그램에서 데이타베이스를 액세스하는것은 꽤나 무거운 오퍼레이션이기 때문에 이런 경우 메모리에 올라와있는 데이타 캐시는 성능의 주요한 key factor가 되는데요. 메모리에 적재된 데이타를 이용하기위해서 javax.sql.RowSet의 서브인터페이스인 javax.sql.rowset.CachedRowSet을 이용할 수 있습니다.CachedRowSet인터페이스의 인스턴스는 원하는 데이터를 가져오기위해 항상 데이터 베이스에 접속하지 않고 이미 메모리 상에 올라온 데이터를 통하여 원하는 결과를 가져올 수있능 능력이 있습니다. 이에 더해  CachedRowSet은 스크롤, 데이터 변경이 가능하고, serializable 합니다. 또한 스프레드시트와 같은 표형식의 데이터 소스에도 잘 작동 합니다.

위에 기술한 모든 기능들과, 거기에 더해 result set의 출력을 XML로 한다든지 하는 기능이 필요하다면 javax.sql.rowset.WebRowSet이 적절한 해답일 수 있습니다. WebRowSet인터페이스에 대해 썬에서는 JDK 5.0에 이미 reference implementation클래스로 com.sun.rowset.WebRowSetImpl 클래스를 제공하고 있습니다.

javax.sql.rowset 패키지의 마지막 서브인터페이스인 javax.sql.rowset.JoinRowSet은 result set 내의 object를 대상으로 SQL JOIN문과 같은 조작을 수행 할 수 있는 기능을 제공합니다.

다음편으로 계속..

2008/11/09 13:59 2008/11/09 13:59
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

finalize 메소드의 오버라이딩을 자제해야 하는 이유.

모든 자바 클래스의 최상위 부모클래스인 java.lang.Object 클래스에는 finalize() 메소드가 존재하며, Java API 에는 이 메소드는 '가비지 컬렉터가 레퍼런스를 잃은 클래스의 인스턴스를 가비지 컬렉션할 때 호출된다' 라고 기술하고 있습니다.

이 메소드는 객체인스턴스가 가비지 콜렉션에 의해 소멸되는 시점에 특정한 동작을 수행해야 할때도 요긴하게 사용할 수 있는 메소드입니다만 일반적인 경우 불필요하게 이 finalize() 메소드를 오버라이딩하는 것은 자제해야합니다.

이유는 'finalize 메소드에 의한 Collection 지연과 OOME(Out of Memory Exception)발생 가능성'때문입니다.
특정 Class에 finalize 메소드가 정의되어 있는 경우, 이 Class Type의 Object는 Garbage Collection 발생시 즉각적으로 Collection 되지 않습니다. 대신 Finalization Queue에 들어간 후 Finalizer에 의해 정리가 되는데요. Finalizer는 Object의 finalize 메소드를 실행한 후 메모리 정리 작업을 수행하게됩니다.
만일 finalize 메소드를 수행하는데 오랜 시간이 걸린다면 그 만큼 객체가 오랫동안 메모리를 점유하게 되고 이로 인해 OOME가 발생할 확률이 높아집니다.
이런 이유로 finalize 메소드는 되도록 사용하지 말아야 합니다.

2008/11/06 11:08 2008/11/06 11:08
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

Sun Tech Days 2008 개발자 컨퍼런스 무료 등록자에 선정되다.

재작년까지만 해도 개발자 세미나 컨퍼런스에 곧잘 다녀오곤 했는데 올해는 유달리 움직이지 못하고 있었다.
Sun Tech Days 2008 개발자 컨퍼런스가 서울에서 개최된다는 소식을 접하고 참석하고 싶다는 굴뚝같은 마음을
평일 개최된다는 거랑 의외로 비싼 등록비가 좌절케 했는데..

뜻밖에 오늘 테크데이운영사무국으로부터 컨퍼런스 무료등록 대상이 되었다는 메일이 도착했다.
썬 코리아 눈에 들 만한 것도 없고, 당첨 운도 지지리 없는 내게 이런 뜻하지 않은 행운이...  

자. 비용 부담은 사라졌다.. 문제는 평일 진행된다는 거... 프로젝트 진행상황을 봐서 짬을 내 다녀와도
될거 같은데.. 그냥 연차를 쓰고 참석을..? (불끈!!)

Sun Techdays 2008 Seoul

 
2008/09/24 17:13 2008/09/24 17:13
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다
  1. 저두요!!
    저두 초대 메일 왔는데... 시간이... ㅜㅜ
    (과장님 같이 땡땡이 하실래요;;;;)

  2. Blog Icon
    서비

    음.. 난 일정이 빡빡하지 않으면 참석하는 방향으로..
    일단 세션 선택해서 신청은 했거든..

  3. 서비님은 과장님이신가 보군요.. 선 테크 데이 무료로 가볼까 하고 이벤트에 두 번이나 신청했는데 당첨이 안되는 군요. 같은 팀은 당첨되서 쿠폰으로 가는데, 저는 회사에 교육신청해서 가게 되었습니다. 갔다와서 보고서를 써야하는 압박이 있지만..

  4. Blog Icon
    서비

    이걸로 제 올한해 행운이 끝나는건 아닌지 아쉬워 하고 있습니다. ^^;;

double 값을 문자열 형식의 퍼센트값으로 변환하기

2008/08/01 23:09

서비 JAVA , , ,

double을 퍼센트(%)로 표현하기위해 여러가지 방법을 이용할 수 있지만  java.text 패키지의 NumberFormat 클래스
API를 이용하면 아래와 같이 간단히 double값을 퍼센트 문자열로 변환할 수 있다.

[code]
package javacodesnipet;

import java.util.Locale;
/**
 *
 * @author 신윤섭
 */
public class NumberFormatPercent {
 public static void main(String[] args){  
    //아래 double 값을 퍼센트 문자열로 표현해 보자
    double value = 0.343234532d;
    //NumberFormat 객체로 부터 PercentInstance를 얻어온다.
    java.text.NumberFormat pformat = java.text.NumberFormat.getPercentInstance(Locale.KOREA);
    //퍼센트로 표현할 소수점 이하의 자리수를 정한다.
    pformat.setMaximumFractionDigits ( 4 );
    //자... 이제 double을 String형식의 퍼센트로 변환하자.
    String sPercent = pformat.format ( value);
    //값을 확인 해 보자 -> 34.3235% 과 같이 표현 된다.
    System.out.println(sPercent);
    }
}
[/code]

2008/08/01 23:09 2008/08/01 23:09
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

String 타입의 날짜를 Date 타입으로 변환하기

2008/07/22 01:59

서비 JAVA , , , ,

우리는 java.util.Date 혹은 java.sql.Date 타입의 객체에서 특정한 형식의 문자열로 날짜를 가져오기 위해서
java.text.SimpleDateFormat 클래스를 이용할 수 있다는 것을 알고 있다.
[code]
package javacodesnipet;
/**
 * @author 신윤섭
 */
public class SimpleDateFormatTest {
 
 public static void main(String[] args){
 
  // 현재 일시 정보를 갖는 Date 객체를 생성한다.
  java.util.Date currentDate = new java.util.Date();  
  //Date객체로부터 특정한 형식의 문자열로 일시를 만들어내기 위한 포매터를 생성한다.
  java.text.SimpleDateFormat format = new java.text.SimpleDateFormat("yyyy년MM월dd일 HH시mm분ss초");
  //포매터를 이용하여 Date객체로부터 문자열을 만들어낸다.
  String dateString = format.format(currentDate);
  //변환된 문자열을 확인한다.  결과 : 2007년07월22일 02시21분42초
  System.out.println(dateString);  
 
 }
}
[/code]
위의 코드는 흔히 사용하는 코드일 것이다.

그런데 이 SimpleDateFormat 클래스의 parse() 메소드를 이용하면 역으로 문자열 형식의 날짜로부터
Date객체를 생성 해낼 수도 있다.
[code]
package javacodesnipet;
/**
 * @author 신윤섭
 */
public class SimpleDateFormatTest {
 
 public static void main(String[] args){
  try {
   // "2007-07-22" 이란 문자열로 2007년 7월 22일의 정보를 갖는 Date객체를 만들어보자
   String textDate = "2007-07-22";

   // 입력할 날짜의 문자열이 yyyy-MM-dd 형식이므로 해당 형식으로 포매터를 생성한다.
   java.text.SimpleDateFormat format = new java.text.SimpleDateFormat("yyyy-MM-dd");

   //SimpleDateFormat.parse()메소드를 통해 Date객체를 생성한다.
   //SimpleDateFormat.parse()메소드는 입력한 문자열 형식의 날짜가
   //포맷과 다를경우 java.text.ParseException을 발생한다.
   java.util.Date date = format.parse(textDate);

   //위에서 만든 date객체가 정말 7월22일인지 확인 해보자.
   java.text.SimpleDateFormat format1 = new java.text.SimpleDateFormat("yyyy년MM월dd일 HH시mm분ss초");
   String dateString = format1.format(date);
   //Date객체의 날자를 확인한다..  결과 : 2007년07월22일 00시00분00초
   System.out.println(dateString);
  } catch (java.text.ParseException ex) {
   ex.printStackTrace();
  }
 
 }
}
[/code]

2008/07/22 01:59 2008/07/22 01:59
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다
  1. 유용한 자료 감사합니다.
    블로그에는 본문을 제외한 링크만을 옮겨둡니다.

  2. Blog Icon
    컴공

    이것때메 고민하던차에 잘보고 갑니다^^

  3. Blog Icon
    멍청돋네 ㅡㅡ

    저렇게 하면 최종 결과물은 String 입니다만?

    뭐가 Date타입입니까?

    SimpleDateFormat을 이용해서 parse하면 Date타입이지만
    다시 format하면 무조건 스트링타입이 됩니다.

    따라서 String -> Date 변환이 아니라
    String -> String(패턴지정) 이 됩니다.

    Date타입에는 따로 패턴을 줄수 없는것으로 알고 있습니다.

  4. Blog Icon
    정창용

    java.util.Date date = format.parse(textDate); <-- 여기까지가 포매터를 이용해서 String -> Date 변환이 이뤄진거고 그 아래 내용은 정말 제대로 변환되었는지 확인을 위한 테스트 코드로 보여집니다.

    다른 사람의 블로그에서 도움을 얻어갔으면 고맙다는 글을 못달지언정 본인의 난독증을 굳이 광고할 필요가 있을까 싶군요. 닉네임부터 똑바로 다는 예절부터 배우십시오.

  5. Blog Icon
    이정대

    공감합니다.

  6. 지나가던 사람이지만.. 댓글적은분 정말 멍청하네요.ㅎㅎ

  7. Blog Icon
    지현
  8. Blog Icon
    보나

    좋은 글 잘보고갑니다. 이것때문에 헤맸었는데 덕분에 해결되었어요 감사합니다♡

  9. 알짜베기로 잘 알려주셨네요~! 잘 보고 갑니다 :)

  10. Blog Icon
    ahm

    도움이 많이 되었습니다.

자바 파일복사 코드와 성능 2 :: Java File Copy Code & Perfomance Issue. part 2

2008/07/13 21:21

서비 JAVA , , , , , ,

지난 포스트를 통해 자바로 파일을 복사하는 몇가지 방법을 알아보았다.
이번시간에는 각 코드의 성능을 간단히 확인해 보고자 한다.

[code]
/*
 * author 신윤섭
 */
package filecopy;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * Stream을 이용한 파일복사 코드 스니핏
 * @author 신윤섭
 */
public class StreamCopy {

 /**
  * source에서 target으로의 파일 복사
  * @param source
  * @param target
  */
 public void copy(String source, String target) {
  //복사 대상이 되는 파일 생성
  File sourceFile = new File( source );
 
  //스트림 선언
  FileInputStream inputStream = null;
  FileOutputStream outputStream = null;
 
  try {
   //스트림 생성
   inputStream = new FileInputStream(sourceFile);
   outputStream = new FileOutputStream(target);
   
   int bytesRead = 0;
   //인풋스트림을 아웃픗스트림에 쓰기
   byte[] buffer = new byte[1024];  
   while ((bytesRead = inputStream.read(buffer, 0, 1024)) != -1) {
    outputStream.write(buffer, 0, bytesRead);
   }
   
  } catch (Exception e) {
   e.printStackTrace();
  }finally{
   //자원 해제
   try{
    outputStream.close();
   }catch(IOException ioe){}
   try{
    inputStream.close();
   }catch(IOException ioe){}
  }

 }
}
[/code]
[code]
/*
 * author 신윤섭
 */
package filecopy;

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

/**
 * Buffer를 이용한 파일복사 코드 스니핏
 * @author 신윤섭
 */
public class BufferCopy {

 /**
  * source에서 target으로의 파일 복사
  * @param source
  * @param target
  */
 public void copy(String source, String target) {
  //복사 대상이 되는 파일 생성
  File sourceFile = new File( source );
 
  //스트림, 버퍼 선언
  FileInputStream inputStream = null;
  FileOutputStream outputStream = null;
  BufferedInputStream bin = null;
  BufferedOutputStream bout = null;
 
  try {
   //스트림 생성
   inputStream = new FileInputStream(sourceFile);
   outputStream = new FileOutputStream(target);
   //버퍼 생성
   bin = new BufferedInputStream(inputStream);
   bout = new BufferedOutputStream(outputStream);
   
   //버퍼를 통한 스트림 쓰기
   int bytesRead = 0;
   byte[] buffer = new byte[1024];
   while ((bytesRead = bin.read(buffer, 0, 1024)) != -1) {
    bout.write(buffer, 0, bytesRead);
   }

  } catch (Exception e) {
   e.printStackTrace();
  } finally {
   //자원 해제
   try{
    outputStream.close();
   }catch(IOException ioe){}
   try{
    inputStream.close();
   }catch(IOException ioe){}
   try{
    bin.close();
   }catch(IOException ioe){}
   try{
    bout.close();
   }catch(IOException ioe){}
  }
 }
}
[/code]
[code]
/*
 * author 신윤섭
 */
package filecopy;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.channels.FileChannel;
import java.io.IOException;

/**
 * NIO Channel을 이용한 파일복사 코드 스니핏
 * @author 신윤섭
 */
public class ChannelCopy {

 /**
  * source에서 target으로의 파일 복사
  * @param source 복사할 파일명을 포함한 절대 경로
  * @param target 복사될 파일명을 포함한 절대경로
  */
 public void copy(String source, String target) {
  //복사 대상이 되는 파일 생성
  File sourceFile = new File( source );

  //스트림, 채널 선언
  FileInputStream inputStream = null;
  FileOutputStream outputStream = null;
  FileChannel fcin = null;
  FileChannel fcout = null;

  try {
   //스트림 생성
   inputStream = new FileInputStream(sourceFile);
   outputStream = new FileOutputStream(target);
   //채널 생성
   fcin = inputStream.getChannel();
   fcout = outputStream.getChannel();
   
   //채널을 통한 스트림 전송
   long size = fcin.size();
   fcin.transferTo(0, size, fcout);

  } catch (Exception e) {
   e.printStackTrace();
  } finally {
   //자원 해제
   try{
    fcout.close();
   }catch(IOException ioe){}
   try{
    fcin.close();
   }catch(IOException ioe){}
   try{
    outputStream.close();
   }catch(IOException ioe){}
   try{
    inputStream.close();
   }catch(IOException ioe){}
  }
 }
}
[/code]

이상의 샘플코드를 이용하여 700Mbytes 짜리 파일을 5번 복사하여 그 시간을 측정해 본 결과는 아래와 같다.
테스트는 Win XP Pro sp3, Intel Core2 Duo 2GHz, 2Gbytes, 5400rpm의 노트북용 HDD 에서 JDK 1.6.0_06
을 이용하여 이루어졌다.

결과는 아래와 같다.

스트림을 이용한 파일 카피

Stream을 이용한 파일 복사


버퍼를 이용한 파일 카피

Buffer를 이용한 파일 복사


채널을 이용한 파일 카피

Channel을 이용한 파일 복사



프로파일러를 이용하여 측정한 값이기 때문에 프로파일러의 처리량 만큼의 차이는 있겠지만 상대적 성능 비교
에는 문제가 없으리라 생각 된다.
실측에서도 예상대로 Stream , Buffer, Channel 순으로 파일 복사 시간이 줄어들고 있음을 볼 수있다.

이번에는 조금 더 들여다 보기로 하자. 700m짜리 파일을 한번 복사하는데 어떤 클래스와 메소들이 참여하고
있는지, 그리고 메소드가 몇번이나 호출되고 있는지 확인 해 보는것도 재미있을 것이다.

스트림이용

FileInputStream.read()실행에 대부분의 시간을 소비하고 있다.


스트림을 이용한 파일복사이다. FileInputStream.read()메소드가 71만여번 호출되고있으며 실행시간의 대부분을
이 메소드를 실행 하는데 소비하고 있음을 알 수 있다.

버퍼이용

Stream보다는 나아졌다고는 하나 역시 read()메소드가 대부분의 실행시간을 소비하고 있다.


Buffer를 이용한 방법. 위의 Stream을 이용한 방법에 비해 수행시간이 약간은 줄어들었지만 이는 Buffer를 활용
함으로써 FileOutputStream.write() 수행시간을 줄인데 따른 성능 향상이며, FileInputStream.read()메소드는
약 9만번 호출되고 있다.

채널이용

위 두 방식과는 확연히 다른 동작 성향을 보여주고 있다.


마지막으로 채널을 이용한 파일복사의 경우 위 두 경우와 비교하여 호출되는 메소드나 호출횟수등 전혀 다른
동작 성향을 보이고 있다. read 도 하지 않은채 FileDispatcher.write() 메소드를 단 한번 호출 하는것으로 파일
복사를 끝내고 있다. 이 FileDispatcher.write() 하부구조에서는 OS의 네이티브IO를 호출하고 있으리라 미루어
짐작할 수 있다.

이상으로 파일복사(스트림전송)의 세가지 방식과 그 성능에 대해 간략하게 알아보았다.
위 실험 결과는 크기가 비교적 큰 파일의 복사에서 나타나는 성향며, 다수의 작은 크기의 파일을 복사한다면
그 결과가 달라질 수도 있음을 밝혀둔다.

io작업이 필요한데 JDK 1.4 이상의 버전을 이용할 수 있다면 나은 성능을 보장하는 nio를 사용하지
않을 이유가 없어보인다.

2008/07/13 21:21 2008/07/13 21:21
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다
  1. 안녕하세요 ^^
    글이 내용이 유용해서 좋아서 제가 퍼갔습니다. ^^
    문제가 있으시다면, 언제든지 알려 주세요 ^^

    링크는 다음과 같습니다. ^^
    http://cafe.naver.com/javacircle/31059

  2. Blog Icon
    서비

    도움이 되셨다니 기쁩니다.
    담아가셔도 크게 개의치 않습니다. ^^

  3. 감사합니다 ^^

  4. Blog Icon
    lahuman

    늘 사용하는 Stream 관련 좋은 정보 감사합니다.

  5. Blog Icon
    야기

    자바 성능검사를 어떻게 하셨는지 궁금합니다 ^^;

  6. Blog Icon
    서비

    글에 관심가져 주셔서 감사합니다.
    해당 프로파일러에 대한 정보는 http://www.yunsobi.com/blog/462
    글을 참고해 주시면 감사하겠습니다.

  7. Blog Icon

    생각보다 성능차이가 많이 나네요. 유용한 자료 잘 보고 갑니다.

    아 그리고 BufferedInputStream 생성자의 인자로 넘겨준 InputStream은 BufferedInputStream의 close()가 호출 될 때
    같이 close 됩니다. Channel 의 경우도 Lazy pattern 으로 생성되었다가 InputStream이 close 될 때 같이 close 되네요.
    이 글을 보고 혹시나 해서 궁금해서 소스를 뒤져보니 그렇게 되어있네요. 덕분에 배우고 갑니다 ^^

  8. Blog Icon
    컴장이

    좋은글 퍼갈께요.
    출처는 남기겠습니다.
    감사합니다.

  9. Blog Icon
    엘리냥

    파일 복사로 고민하던 차에 좋은 정보 얻어갑니다!!
    저런 성능 테스트 부분은 정말 유용하네요.
    성능 테스트하는 것도 더 알아봐야겠어요~

  10. Blog Icon
    노란사자

    좋은글 감사합니다.
    출처를 표기하고 퍼가겟습니다.

  11. Blog Icon
    이홍재

    좋은글 감사합니다.

    해당사항 담아갈게요.

    출처표기하겠습니다.

    담아가는 곳은 http://blog.naver.com/hongjae83

    문제가 될시 삭제하겠습니다.

    감사합니다.

  12. 좋은 정보 공유해주셔서 감사합니다

  13. Blog Icon
    jini

    좋은 정보 감사합니다.

  14. Blog Icon
    sbkim

    감사합니다^^~~~

  15. 감사합니다.
    http://blog.daum.net/andro_java/210
    채널카피 올렸습니다.

  16. 감사합니다. 많은 도움이 되었습니다.
    퍼갈께요. http://cafe.naver.com/stweb

  17. Blog Icon
    지나가던개발자

    이걸 안드로이드에 적용시켰더니 파일 복사 속도가 대략 3분의 1로 줄었습니다. 엄청난 성능입니다. 감사합니다.

자바 파일복사 코드와 성능 1. :: Java File Copy Code & Perfomance Issue. part 1

2008/07/13 00:05

서비 JAVA , , , , , ,

자바로 파일을 복사할 수 있는 방법은 크게 3가지 정도가 있다.
InputStream, OutputStream을 이용한 방법, Buffer를 이용한 방법, Channel을 이용한 방법이 그것이다.
물론 Buffer를 이용하면서도 단순히 Stream에 Buffer 필터를 적용할 수도, MappedByteBuffer를 쓸 수도 있고
Channel을 이용하면서도 inputChannel과 outputChannel을 이용하거나 transterTo()를 이용하는 등
다양한 방법을 구사할 수 있다.
여기서는 자바로 구현 할 수 있는 대표적인 파일 복사 코드를 살펴보고 각 코드간의 성능에 대한 이야기도 나눠
보도록 하겠다.

Java입문서등을 통하여 io (Input/Output)부분을 언급하며 나오는 개념이 Stream일 것이다. 스트림의 개념을
설명하고 처음 접하는 코드는 아래와 유사할 것이다. 파일을 인풋스트림으로 읽어들인 후 그 길이만큼 아웃풋
스트림에다 흘려보내는 방식으로 파일을 복사할 수 있다.

[code java] FileInputStream inputStream = new FileInputStream(file); FileOutputStream outputStream = new FileOutputStream(saveFullPath); int bytesRead = 0; byte[] buffer = new byte[1024]; while ((bytesRead = inputStream.read(buffer, 0, 1024)) != -1) { outputStream.write(buffer, 0, bytesRead); } outputStream.close(); inputStream.close(); [/code]

* InputStream과 OutputStream을 이용한 기본적인 파일 복사 코드.
위 코드는 기본적인 Stream의 사용법을 잘 보여주고 있지만 성능상에 심각한 문제를 안고 있다.
파일크기(정확하게는 스트림의 길이)만큼 while문을 돌면서 끊임없이 읽고쓰기를 반복하고 있는데
이는 CPU, DISK모두에게 부담을 주는 결과를 초래한다.

이어지는 코드가 아마 가장 널리쓰이고 흔하게 볼수 있는 코드 일 것이다. 위에서 살펴본 Stream간의 데이터
전송이 썩 좋은 성능을 내지 못하기 때문에, 스트림을 버퍼를 장착(wrapping, chainning)하여 입출력 횟수를 줄여
성능 향상을 꾀하고 있다.

[code java] FileInputStream inputStream = new FileInputStream(file); FileOutputStream outputStream = new FileOutputStream(saveFullPath); BufferedInputStream bin = new BufferedInputStream(inputStream); BufferedOutputStream bout = new BufferedOutputStream(outputStream); int bytesRead = 0; byte[] buffer = new byte[1024]; while ((bytesRead = bin.read(buffer, 0, 1024)) != -1) { bout.write(buffer, 0, bytesRead); } bout.close(); bin.close(); outputStream.close(); inputStream.close(); [/code]

* Stream에 Buffer Filter를 연결하여 성능을 향상.
위와같은 방법으로 충분히 만족할만 한가? 그렇다고 할수도있고 아니라고 할수도 있다. 위 두 방식은 스트림으로
데이터를 전송하는데 항상 cpu의 연산을 필요로 한다. 즉 스트림을 처리하는동안 cpu가 계속해서 명령을 처리
해줘야 한다는것이다.(비록 cpu사용율은 얼마 안될지 모르지만.. )

컴퓨터의 입장에서 본다면 IO는 상당히 느린 작업중의 하나이다. 이런 작업을 조금이라도 빨리 처리하기위해
하드웨어 혹은 운영체제 수준에서 많은 기법들을 제공하고 있다.
자바는 버전 1.4에 이르러서 기존 io와는 차별화된 nio(new io) 패키지가 추가되었는데 이 nio를 통하여
운영체제가 제공해 주는 향상된 io기능을 활용할 수 있게 되었다. 그 대표적인 것이 Channel과 Selector일 것이다.
아래와 같은 코드는 JDK 1.4이상부터 사용 가능하며 transferTo() 메소드를 호출하면 내부적으로 OS의 네이티브IO
기능을 활용하여 더욱 효율적인 스트림 전송이 가능하다.
 
[code java] FileInputStream inputStream = new FileInputStream(file); FileOutputStream outputStream = new FileOutputStream(saveFullPath); FileChannel fcin = inputStream.getChannel(); FileChannel fcout = outputStream.getChannel(); long size = fcin.size(); fcin.transferTo(0, size, fcout); fcout.close(); fcin.close(); outputStream.close(); inputStream.close(); [/code]

* Channel을 이용한 네이티브OS 기능 사용하기.

이상으로 3가지 대표적인 자바 파일복사 코드를 살펴보았다. 다음 포스트에서는 각 방식의 성능 차이에 대해
알아보도록 하겠다.

자바 파일복사 코드와 성능 2

2008/07/13 00:05 2008/07/13 00:05
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다
  1. 안녕하세요 ^^
    글이 내용이 유용해서 좋아서 제가 퍼갔습니다. ^^
    문제가 있으시다면, 언제든지 알려 주세요 ^^

    링크는 다음과 같습니다. ^^
    http://cafe.naver.com/javacircle/31058

  2. Blog Icon

    유익한 내용.. 출처 남기고 퍼가겠습니다 ^^

  3. Blog Icon
    SSH

    잘 썼습니다! 파일채널은 첨 써보는데 잘되네요!!

  4. 좋은 내용 감사합니다.

  5. Blog Icon
    우주인

    좋은 글 감사 합니다. 출처 남기고 퍼가겠습니다^^

  6. Blog Icon
    dennis

    좋은 정보 감사합니다.

Java Profiler JProbe 8.0 출시!! :: 자바 프로파일러

Quest Software에서 Java cde, memory, coverage 프로파일러인 JProbe 8.0을 출시하였습니다.
JProbe는 YourKit 이나 JProfiler 와 유사한 기능을 제공하면서 다른 두 프로파일러에 비해 저렴한 가격을 장점으로 꼽고 있습니다.
JProbe 8.0은 두가지 특징적인 기능이 포함되었습니다.
첫번째로 자바 어플리케이션의 프로파일링을 좀 더 원활히 진행하기위해 Eclipse 플러그인을 지원하여 IDE를 통하여 개발, 테스트 및 성능평가에 이르는 프로세스를 단축하여 좀 더 높은 생산성을 제공합니다.
또다른 특징으로는 UI개선을 통한 사용성 향상을 꼽을 수 있습니다. Data Visualization기능을 통하여 좀 더 빠르고 효율적으로 memory allocation 문제를 진단할 수 있습니다.
JProbe는 상용제품이긴 하지만 Quest Software에서는 JProbe Freeware라는 이름으로 기능에 제한을 둔 Eclips 플러그인을 배포하고 있습니다.

  Freeware Commercial
Main Features    
# installations unlimited per license
Memory Heap Dump Analysis
Memory JProbe Snapshot Analysis X
Performance Analysis X
Code Coverage X
Automation X
Quest Support JProbe Community Quest Support


넷빈즈에는 이미 JProfiler에 버금가는 프로파일러가 내장되어 있기 때문에 그닥  필요를 느끼지는 않지만 넷빈즈 유저로써 '넷빈즈용 플러그인도 배포하면 좋을텐데..' 하는 아쉬움이 남는것도 사실입니다.

JProbe에 관심있는 개발자 분들은 http://www.quest.com/common/registration.aspx?requestdefid=18937 를 방문 하시면 더 많은 정보를 얻을 수 있습니다.

2008/07/07 23:50 2008/07/07 23:50
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

JVM에서 얻어오는 시간이 시스템시간과 차이가 날 때.




자바에서 현재 시각을 가져오는 방법으로 java.lang.System 클래스를 이용하여
System.currentTimeMillis() 와 같이 쓸 수 있습니다.
문제는 이렇게 얻어온 현재 시각과 시스템 시간 사이에 차이가 발생할 수 있다고 하는군요.
 
JDK 1.3.1 이전 버전에서는 currentTimeMillis()를 호출할 때마다 시스템 시간을 얻어왔으나..
JDK 1.3.1 이후 버전의 JVM에서는 성능상의 이슈로 JVM을 가동할 때(자바 어플리케이션을 구동 할 때)
시스템 시간을 가져온 이후에는 JVM에서 자체적으로 시간을 계산하는 방식을 바뀌었기 때문입니다.

JDK 1.3.1 이후 버전에서는 자바 구동옵션에 -XX:+UseGetTimeOfDay 를 적용하여 매번 시스템 시간을
가져올 수 있으나 권장하진 않는다는군요.

자바 포럼 : http://forum.java.sun.com/thread.jspa?threadID=765165&messageID=4368968


2008/05/29 17:16 2008/05/29 17:16
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

Java에 OpenID 적용 관련 아티클

  • Enterprise Java Community: Using OpenID
  • OpenID 적용 서비스 Best Practice
  • Java로 만드는 OpenID Consumer
  • 2008/04/22 20:14 2008/04/22 20:14
    Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

    소켓통신 서버/클라이언트 통신시 IO Blocking 상태에 빠지는 코드와 해결 방안

    2008/04/03 19:15

    서비 JAVA , , ,

    java study 질답 게시판에서 서버-클라이언트 소켓 통신을 하는데 통신이 단절된다는 내용의 질문을 접했습니다.

    질문자의 원글 보기..


    코드를 보면 지극히 정석으로 코드를 작성 해 둔 상황입니다. 하지만 동작 중 어느 순간이 되면 통신이 안되기 시작하죠..
    이는 비단 자바뿐만 아니라 다른 언어로 소켓 프로그래밍을 하더라도 동일한 현상이 발생할 겁니다.
    원 질문자께서 저 코드로 어디까지 다버깅을 해 보셨는지는 알지 못하겠지만, 제가 판단하건데 동작이 안되는 시점은
    필시 클라언트와 서버 양쪽 모두 while((read = bin.read())!=-1) 문에서 서로의 데이터를 기다리느라
    블록 상태에 빠졌기 때문일 겁니다.

    왜? 무슨 이유로 read() 에서 블록 상태에 빠졌을까요?

    원인은 서버 소켓 쓰레드인 ClientHandler 쪽에서 찾을수 있습니다. 
    서버 소켓 코드를 보시면 클라이언트에서 받은 데이타를 읽는게 끝이나면 클라이언트로 데이타를 전송하는
    절차적 구조로 작성 되어있는데요..

    문제는 클라이언트로부터 데이터가 유입되는
    [code]// received InputStream in = null;
    BufferedInputStream bin = null;
    in = m_socketClient.getInputStream();
    bin = new BufferedInputStream(in);
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    int read;
    while ((read = bin.read()) != -1) {
        baos.write(read);
    }
    [/code]
    부분이 원인입니다... 감이 좀 잡히시나요?

    한번 API를 확인 해 볼 필요가 있겠군요. API를 보시면.. BufferedInputStream의 read() 메소드의 리턴 값을
    the next byte of data, or -1 if the end of the stream is reached. 라고 명시하고 있습니다.
    '스트림의 끝까지 갔을 때 -1을 리턴 한다'라고.. 데이터가 끝났을 때 -1이 아닙니다.

    비록 클라이언트가 보낸 데이타는 끝이 났을지언정 클라이언트와 연결된 스트림은 끝나지 않았단 말이죠.
    쉽게 말하자면 bin.read()에서 block된 상황은 BufferedInputStream인 bin이 끝나지 않았으며, 언젠간
    새로운 데이터가 유입될테니 대기중이다.
    는 얘기지요.

    이제 좀 감이 잡히시죠? ^^
    결국 지금의 코드 대로라면 서버 소켓은 클라이언트에서 보낼 데이터를 영원히(혹은 time out까지) 기다리고 있는거죠..

    이제 원인을 알았으니 해결책에 대한 아이디어도 떠오르셨을거라 생각합니다.
    이런 경우 클라이언트 소켓도 쓰레드로 돌려야 하지만 인풋 스트림과 아웃풋 스트림도 각각 쓰레드로 처리 해
    주셔야 질문과 같이 blocking으로 어플리케이션이 멈춰있는 문제를 회피할 수 있습니다.
     

    2008/04/03 19:15 2008/04/03 19:15
    Trackback Address:이 글에는 트랙백을 보낼 수 없습니다
    1. Blog Icon
      비밀방문자

      관리자만 볼 수 있는 댓글입니다.

    2. Blog Icon
      Nereid

      관리자님 안녕하세요. 프로그래밍중 안되는 부분이 있어
      해결책을 찾아보다가 여기서 같은 케이스를 찾게되서요.

      제가 초보라 해결책이 잘 떠오르지 않는데
      저런경우 인/아웃 스트림 쓰레드 처리에 대하여 좀 알려주실수 있을까요?

      부탁드립니다. 감사합니다.

    Eclipse 3.3 or NetBeans 6.0?

    이클립스넷빈즈

    Eclipse
    vs. NetBeans

    대표적인 두개의 자바 개발환경인 이클립스 3.3과 넷빈즈 6.0에 대한 비교기사가 JavaWorld에 실렸습니다.
    테그놀로지 애널리스트인 Andrew Binstock씨는 이번 리뷰에서 '넷빈즈가 일 냈다.'라는 글을 남길정도로
    넷빈즈의 발전에 주목하고 있습니다.

    이번 리뷰에서 Netbeans 6.0과 Eclipse 3.3에대해 에디터, 랭귀지 지원, 엔터프라이즈 툴, 플러그인의 4가지
    항목으로 비교를 진행 하고 있는데요.
    넷빈즈의 강점으로
     - 쉬운 설치
     - 에디터의 강력함과 쉬운 사용
     - 랭귀지 지원 확대 - 특히, 넷빈즈는 Ruby에 대한 현재 최고의 IDE
     - 플러그인들
    을 꼽고 있습니다.

    두 IDE에 대한 비교결과로 사용상의 편의성과 에디터 기능, 다른 랭귀지 지원에선 넷빈즈가,
    엔터프라이즈 지원과 플러그인 시스템에선 이클립스가 우세하다는 견해를 밝히고 있습니다.

    두 자바 IDE에 대한 전문이 궁금하신분은 아래 url을 방문하시면 됩니다.

    기사 전문 : http://www.javaworld.com/javaworld/jw-03-2008/jw-03-java-ides0308.html
    2008/03/25 13:53 2008/03/25 13:53
    Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

    자바 날짜/시간 계산 예제 코드 :: Java Date Code Snippet

    update java8 부터는 JodaTime에 기반한 패키지가 포함되어 훨씬 간단하고 쉬운 방법으로 일자관련 기능을 사용할 수있습니다. http://www.yunsobi.com/blog/649

    시스템의 밀리초 구하기.(국제표준시각(UTC, GMT) 1970/1/1/0/0/0 으로부터 경과한 시각)
    [code]
    // 밀리초 단위(*1000은 1초), 음수이면 이전 시각
    long time = System.currentTimeMillis ( );
    System.out.println ( time.toString ( ) );
    [/code]

    현재 시각을 가져오기.
    [code]
    Date today = new Date ();
    System.out.println ( today );
    [/code]
    결과 : Sat Jul 12 16:03:00 GMT+01:00 2000

    경과시간(초) 구하기
    [code]
    long time1 = System.currentTimeMillis ();
    long time2 = System.currentTimeMillis ();
    system.out.println ( ( time2 - time1 ) / 1000.0 );
    [/code]

    Date를 Calendar로 맵핑하기
    [code]
    Date d = new Date ( );
    Calendar c = Calendar.getInstance ( );
    c.setTime ( d );
    [/code]

    날짜(년/월/일/시/분/초) 구하기
    [code] import java.util.*;
    import java.text.*;
    SimpleDateFormat formatter = new SimpleDateFormat ( "yyyy.MM.dd HH:mm:ss", Locale.KOREA );
    Date currentTime = new Date ( );
    String dTime = formatter.format ( currentTime );
    System.out.println ( dTime ); [/code]

    날짜(년/월/일/시/분/초) 구하기2
    [code] GregorianCalendar today = new GregorianCalendar ( );
    int year = today.get ( today.YEAR );
    int month = today.get ( today.MONTH ) + 1;
    int yoil = today.get ( today.DAY_OF_MONTH );

    GregorianCalendar gc = new GregorianCalendar ( );
    System.out.println ( gc.get ( Calendar.YEAR ) );
    System.out.println ( String.valueOf ( gc.get ( Calendar.MONTH ) + 1 ) );
    System.out.println ( gc.get ( Calendar.DATE ) );
    System.out.println ( gc.get ( DAY_OF_MONTH ) ); [/code]

    날짜(년/월/일/시/분/초) 구하기3
    [code] DateFormat df = DateFormat.getDateInstance(DateFormat.LONG, Locale.KOREA);
    Calendar cal = Calendar.getInstance(Locale.KOREA);
    nal = df.format(cal.getTime()); [/code]

    - 표준시간대를 지정하고 날짜를 가져오기.
    [code] TimeZone jst = TimeZone.getTimeZone ("JST");
    // 주어진 시간대에 맞게 현재 시각으로 초기화된 GregorianCalender 객체를 반환.
    Calendar cal = Calendar.getInstance ( jst );  
    // 또는
    // Calendar now = Calendar.getInstance(Locale.KOREA);
    System.out.println ( cal.get ( Calendar.YEAR ) + "년 " + ( cal.get ( Calendar.MONTH ) + 1 ) + "월 " + cal.get ( Calendar.DATE ) + "일 " + cal.get ( Calendar.HOUR_OF_DAY ) + "시 " + cal.get ( Calendar.MINUTE ) + "분 " + cal.get ( Calendar.SECOND ) + "초 " ); [/code]
    결과 : 2000년 8월 5일 16시 16분 47초

    영어로된 날짜를 숫자로 바꾸기
    [code] Date myDate = new Date ( "Sun,5 Dec 1999 00:07:21" );
    System.out.println ( myDate.getYear ( ) + "-" + myDate.getMonth ( ) + "-" + myDate.getDay ( ) ); [/code]

    "Sun, 5 Dec 1999 00:07:21"를 "1999-12-05"로 바꾸기
    [code] SimpleDateFormat formatter_one = new SimpleDateFormat ( "EEE, dd MMM yyyy hh:mm:ss",Locale.ENGLISH );
    SimpleDateFormat formatter_two = new SimpleDateFormat ( "yyyy-MM-dd" );
    String inString = "Sun, 5 Dec 1999 00:07:21";
    ParsePosition pos = new ParsePosition ( 0 );
    Date frmTime = formatter_one.parse ( inString, pos );
    String outString = formatter_two.format ( frmTime );
    System.out.println ( outString ); [/code]

    숫자 12자리를, 다시 날짜로 변환하기
    [code] Date conFromDate = new Date();
    long ttl = conFromDate.parse ( "Dec 25, 1997 10:10:10" );
    //예 938291839221
    System.out.println ( ttl );  
    Date today = new Date ( ttl );
    DateFormat format = DateFormat.getDateInstance ( DateFormat.FULL,Locale.US );
    String formatted = format.format ( today );
    System.out.println ( formatted ); [/code]

    특정일로부터 n일 만큼 이동한 날짜 구하기

    특정일의 시간을 long형으로 읽어온다음..
    날짜*24*60*60*1000 을 계산하여.
    long형에 더해줍니다.
    그리고 나서 Date클래스와 Calender클래스를 이용해서 날짜와 시간을 구하면 됩니다

    특정일에서 일정 기간후의 날짜 구하기2
    [code] //iDay 에 입력하신 만큼 빼거나 더한 날짜를 반환 합니다.
    import java.util.*;
    public String getDate ( int iDay ) {
    Calendar temp=Calendar.getInstance ( );
    temp.add ( Calendar.DAY_OF_MONTH, iDay );
    int nYear = temp.get ( Calendar.YEAR );
    int nMonth = temp.get ( Calendar.MONTH ) + 1;
    int nDay = temp.get ( Calendar.DAY_OF_MONTH );
    StringBuffer sbDate=new StringBuffer ( );
    sbDate.append ( nYear );
    if ( nMonth < 10 ) sbDate.append ( "0" );
    sbDate.append ( nMonth );
    if ( nDay < 10 ) sbDate.append ( "0" );
    sbDate.append ( nDay );
    return sbDate.toString ( );
    } [/code]

    현재날짜에서 2달전의 날짜를 구하기
    [code] //오늘 날짜를 기준으루..
    Calendar cal = Calendar.getInstance ( );
    //2개월 전....
    cal.add ( cal.MONTH, -2 );
    System.out.println ( cal.get ( cal.YEAR ) );
    System.out.println ( cal.get ( cal.MONTH ) + 1 );
    System.out.println ( cal.get ( cal.DATE ) ); [/code]

    달에 마지막 날짜 구하기
    [code] for ( int month = 1; month <= 12; month++ ) {
    GregorianCalendar cld = new GregorianCalendar ( 2001, month - 1, 1 );
    System.out.println ( month + "/" + cld.getActualMaximum ( Calendar.DAY_OF_MONTH ) );
    } [/code]

    해당하는 달의 마지막 일 구하기
    [code] GregorianCalendar today = new GregorianCalendar ( );
    int maxday = today.getActualMaximum ( ( today.DAY_OF_MONTH ) );
    System.out.println ( maxday ); [/code]

    특정일을 입력받아 해당 월의 마지막 날짜를 구하는 간단한 예제.(달은 -1 해준다.)...윤달 30일 31일 알아오기.
    [code] Calendar cal = Calendar.getInstance ( ); cal.set ( Integer.parseInt ( args[0] ), Integer.parseInt ( args [1] ) - 1, Integer.parseInt ( args [2] ) ); SimpleDateFormat dFormat = new SimpleDateFormat ( "yyyy-MM-dd" ); System.out.println ( "입력 날짜 " + dFormat.format ( cal.getTime ( ) ) ); System.out.println ( "해당 월의 마지막 일자 : " + cal.getActualMaximum ( Calendar.DATE ) ); [/code]

    해당월의 실제 날짜수 구하기 ( 1999년 1월달의 실제 날짜수를 구하기 )
    [code] Calendar calendar = Calendar.getInstance ( ); calendar.set ( 1999, 0, 1 ); int maxDays = calendar.getActualMaximum ( Calendar.DAY_OF_MONTH ); [/code]

    어제 날짜 구하기

    오늘날짜를 초단위로 구해서 하루분을 빼주고 다시
    셋팅해주면 쉽게 구할수 있죠..
    setTime((기준일부터 오늘까지의 초를 구함) - 24*60*60)해주면 되겠죠..

    어제 날짜 구하기2
    [code] import java.util.*;
    public static Date getYesterday ( Date today ) {
    if ( today == null ) throw new IllegalStateException ( "today is null" );
    Date yesterday = new Date ( );
    yesterday.setTime ( today.getTime ( ) - ( (long) 1000 * 60 * 60 * 24 ) );
    return yesterday;
    } [/code]

    내일 날짜 구하기
    [code] Date today = new Date ( );
    Date tomorrow = new Date ( today.getTime ( ) + (long) ( 1000 * 60 * 60 * 24 ) ); [/code]

    내일 날짜 구하기2
    [code] Calendar today = Calendar.getInstance ( ); today.add ( Calendar.DATE, 1 ); Date tomorrow = today.getTime ( ); [/code]

    오늘날짜에서 5일 이후 날짜를 구하기
    [code] Calendar cCal = Calendar.getInstance(); c.add(Calendar.DATE, 5);[/code]

    날짜에 해당하는 요일 구하기
    [code] //DAY_OF_WEEK리턴값이 일요일(1), 월요일(2), 화요일(3) ~~ 토요일(7)을 반환합니다.
    //아래 소스 일부입니다.
    import java.util.*;
    Calendar cal= Calendar.getInstance ( );
    int day_of_week = cal.get ( Calendar.DAY_OF_WEEK );
    if ( day_of_week == 1 ) m_week="일요일";
    else if ( day_of_week == 2 ) m_week="월요일";
    else if ( day_of_week == 3 ) m_week="화요일";
    else if ( day_of_week == 4 ) m_week="수요일";
    else if ( day_of_week == 5 ) m_week="목요일";
    else if ( day_of_week == 6 ) m_week="금요일";
    else if ( day_of_week == 7 ) m_week="토요일"; [/code]

    콤보박스로 선택된 날짜(예:20001023)를 통해 요일을 영문으로 가져오기
    [code] //gc.get(gc.DAY_OF_WEEK); 하면 일요일=1, 월요일=2, ..., 토요일=7이 나오니까,
    //요일을 배열로 만들어서 뽑아내면 되겠죠.
    GregorianCalendar gc=new GregorianCalendar ( 2000, 10 - 1 , 23 );
    String [] dayOfWeek = { "", "Sun", "Mon", .... , "Sat" };
    String yo_il = dayOfWeek ( gc.get ( gc.DAY_OF_WEEK ) ); [/code]

    두 날짜의 차이를 일수로 구하기

    각각의 날짜를 Date형으로 만들어서 getTime()하면
    long으로 값이 나오거든요(1970년 1월 1일 이후-맞던가?- 1/1000 초 단위로..)
    그러면 이값의 차를 구해서요. (1000*60*60*24)로 나누어 보면 되겠죠.

    두 날짜의 차이를 일수로 구하기2
    [code] import java.io.*;
    import java.util.*;
    Date today = new Date ( );
    Calendar cal = Calendar.getInstance ( );
    // 오늘로 설정.
    cal.setTime ( today );  
    Calendar cal2 = Calendar.getInstance ( );
    // 기준일로 설정. month의 경우 해당월수-1을 해줍니다.
    cal2.set ( 2000, 3, 12 );  
    int count = 0;
    while ( !cal2.after ( cal ) ) {
    count++;
    //다음날로 바뀜
    cal2.add ( Calendar.DATE, 1 );  
    System.out.println ( cal2.get ( Calendar.YEAR ) + "년 " + ( cal2.get ( Calendar.MONTH ) + 1 ) + "월 " + cal2.get ( Calendar.DATE ) + "일" );
    }
    System.out.println ( "기준일로부터 " + count + "일이 지났습니다." ); [/code]

    두 날짜의 차이를 일수로 구하기3
    [code] import java.io.*;
    import java.util.*;
    public class DateDiff {
    public static int GetDifferenceOfDate ( int nYear1, int nMonth1, int nDate1, int nYear2, int nMonth2, int nDate2 ) {
    Calendar cal = Calendar.getInstance ( );
    int nTotalDate1 = 0, nTotalDate2 = 0, nDiffOfYear = 0, nDiffOfDay = 0;

    if ( nYear1 > nYear2 ) {
    for ( int i = nYear2; i < nYear1; i++ ) {
    cal.set ( i, 12, 0 ); nDiffOfYear += cal.get ( Calendar.DAY_OF_YEAR );
    }
    nTotalDate1 += nDiffOfYear;
    } else if ( nYear1 < nYear2 ) {
    for ( int i = nYear1; i < nYear2; i++ ) {
    cal.set ( i, 12, 0 );
    nDiffOfYear += cal.get ( Calendar.DAY_OF_YEAR );
    }
    nTotalDate2 += nDiffOfYear;
    }
    cal.set ( nYear1, nMonth1-1, nDate1 );
    nDiffOfDay = cal.get ( Calendar.DAY_OF_YEAR );
    nTotalDate1 += nDiffOfDay;
    cal.set ( nYear2, nMonth2-1, nDate2 );
    nDiffOfDay = cal.get ( Calendar.DAY_OF_YEAR );
    nTotalDate2 += nDiffOfDay;
    return nTotalDate1-nTotalDate2;
    }
    public static void main ( String args[] ) {
    System.out.println ( "" + GetDifferenceOfDate (2000, 6, 15, 1999, 8, 23 ) );
    }
    } [/code]

    파일에서 날짜정보를 가져오기
    [code] File f = new File ( directory, file );
    Date date = new Date ( f.lastModified ( ) );
    Calendar cal = Calendar.getInstance ( );
    cal.setTime ( date );
    System.out.println("Year : " + cal.get(Calendar.YEAR));
    System.out.println("Month : " + (cal.get(Calendar.MONTH) + 1));
    System.out.println("Day : " + cal.get(Calendar.DAY_OF_MONTH));
    System.out.println("Hours : " + cal.get(Calendar.HOUR_OF_DAY));
    System.out.println("Minutes : " + cal.get(Calendar.MINUTE));
    System.out.println("Second : " + cal.get(Calendar.SECOND)); [/code]

    날짜형식으로 2000-01-03으로 처음에 인식을 시킨후
    7일씩 증가해서 1년정도의 날짜를 출력해 주고 싶은데요.
    [code] SimpleDateFormat sdf = new SimpleDateFormat ( "yyyy-mm-dd" );
    Calendar c = Calendar.getInstance ( );
    for ( int i = 0; i < 48; i++ ) {
    c.clear ( ); c.set ( 2000, 1, 3 - ( i * 7 ) );
    java.util.Date d = c.getTime ( );
    String thedate = sdf.format ( d );
    System.out.println ( thedate );
    } [/code]

    쓰레드에서 날짜 바꾸면 죽는 문제

    Main화면에 날짜와시간이Display되는 JPanel이 있습니다.
    date로 날짜와 시간을 변경하면 Main화면의 날짜와 시간이 Display되는 Panel에
    변경된 날짜가 Display되지 않고 Main화면이 종료되어 버립니다.

    문제소스:
    [code] public void run ( ) {
    while ( true ) {
    try{
    timer.sleep ( 60000 );
    } catch ( InterruptedException ex ) { }
    lblTimeDate.setText ( fGetDateTime ( ) );
    repaint ( );
    }
    }

    public String fGetDateTime ( ) {
    final int millisPerHour = 60 * 60 * 1000;
    String DATE_FORMAT = "yyyy / MM / dd HH:mm";

    SimpleDateFormat sdf = new SimpleDateFormat ( DATE_FORMAT );
    SimpleTimeZone timeZone = new SimpleTimeZone ( 9 * millisPerHour, "KST" );
    sdf.setTimeZone ( timeZone );
    long time = System.currentTimeMillis ( );
    Date date = new Date ( time );
    return sdf.format ( date );
    } [/code]

    해답:
    [code] // 날짜와 요일 구한다. timezone 으로 날짜를 다시 셋팅하시면 됨니다.
    public String getDate ( ) {
    Date now = new Date ( );
    SimpleDateFormat sdf4 = new SimpleDateFormat ( "yyyy/MM/dd HH:mm EE" );
    sdf4.setTimeZone ( TimeZone.getTimeZone ( "Asia/Seoul" ) );
    return sdf4.format ( now );
    } [/code]

    날짜와 시간이 유효한지 검사하려면...?
    [code] import java.util.*;
    import java.text.*;
    public class DateCheck {
    boolean dateValidity = true;
    DateCheck ( String dt ) {
    try {
    DateFormat df = DateFormat.getDateInstance ( DateFormat.SHORT );
    df.setLenient ( false );
    Date dt2 = df.parse ( dt );
    } catch ( ParseException e ) {
    this.dateValidity = false;
    } catch ( IllegalArgumentException e ) {
    this.dateValidity = false;
    }
    }

    public boolean datevalid ( ) {
    return dateValidity;
    }

    public static void main ( String args [] ) {
    DateCheck dc = new DateCheck ( "2001-02-28" );
    System.out.println ( " 유효한 날짜 : " + dc.datevalid ( ) );
    }
    } [/code]

    두 날짜 비교하기(아래보다 정확)

    그냥 날짜 두개를 long(밀리 세컨드)형으로 비교하시면 됩니다...

    이전의 데이타가 date형으로 되어 있다면, 이걸 long형으로 변환하고.
    현재 날짜(시간)은 System.currentTimeMillis()메소드로 읽어들이고,
    두수(long형)를 연산하여 그 결과 값으로 비교를 하시면 됩니다.

    만약 그 결과값이 몇시간 혹은 며칠차이가 있는지를 계산할려면,
    결과값을 Calender의 setTimeInMillis(long millis) 메소드를 이용해
    설정한다음 각각의 날짜나 시간을 읽어오시면 됩니다

    두 날짜 비교하기2
    [code] import java.util.*;
    import java.util.Calendar.*;
    import java.text.SimpleDateFormat;
    public class DayComparisonTest {
    public static void main(String args[]) {
    Calendar cal = Calendar.getInstance();
    SimpleDateFormat dateForm = new SimpleDateFormat("yyyy-MM-dd");
    Calendar aDate = Calendar.getInstance();
    // 비교하고자 하는 임의의 날짜
    aDate.set(2001, 0, 1);
    // 시스템 일시
    Calendar bDate = Calendar.getInstance();
    // 여기에 시,분,초를 0으로 세팅해야 before, after를 제대로 비교함
    aDate.set( Calendar.HOUR_OF_DAY, 0 );
    aDate.set( Calendar.MINUTE, 0 );
    aDate.set( Calendar.SECOND, 0 );
    aDate.set( Calendar.MILLISECOND, 0 );
    bDate.set( Calendar.HOUR_OF_DAY, 0 );
    bDate.set( Calendar.MINUTE, 0 );
    bDate.set( Calendar.SECOND, 0 );
    bDate.set( Calendar.MILLISECOND, 0 );
    if (aDate.after(bDate)) // aDate가 bDate보다 클 경우 출력
    System.out.println("시스템 날짜보다 뒤일 경우 aDate = " + dateForm.format(aDate.getTime()));
    else if (aDate.before(bDate)) // aDate가 bDate보다 작을 경우 출력
    System.out.println("시스템 날짜보다 앞일 경우 aDate = " + dateForm.format(aDate.getTime()));
    else // aDate = bDate인 경우
    System.out.println("같은 날이구만");
    }
    } [/code]

    2008/02/26 11:13 2008/02/26 11:13
    Trackback Address:이 글에는 트랙백을 보낼 수 없습니다
    1. 2010/07/02 17:36
      자바/ 시간 날짜 예제 Tracked from Make me Funny
    1. Blog Icon
      난학생

      찾고 있던 자료인데 감사해요 ^^

    2. Blog Icon
      DKdak

      아이고.. 한참 찾았는데.. 감사합니다.

    3. Blog Icon
      임진우

      유용한 정보 고맙습니다.

      퍼가겠습니다.

    4. Blog Icon
      최경렬

      시간 차이값을 조사하려고 검색 했는데 필요했던 것보다 더 정리를 잘 해 주셨네요.
      감사합니다.
      담아가겠습니다.

    5. Blog Icon
      JW

      깔끔한 정리 감사합니다.
      담아갈께요~

    6. Blog Icon
      정연규

      좋은 정보 감사합니다.
      출처남기고 담아가겠습니다~

    7. Blog Icon
      전병태

      정보 감사합니다.
      출처 남기고 담아가겠습니다.

    8. 잘 정리된 정보 감사합니다.
      D-Day 기능을 구현하고 있었는데 여기에 딱 있네요.

    9. 정말 좋은 정보 감사합니다.
      출처를 명시하고 퍼가겠습니다.
      다시한번 감사드립니다.

    10. Blog Icon
      sdafasdf

      아 ㅡㅡ 패키지 임포트 왜 빼놔요? ㅄ같네

    11. Blog Icon
      ㅋㅋㅋ

      병신은 님 아닌가요?

    12. Blog Icon
      ㄷㄷ

      코딩 한번이라도 제대로 해보신분이긴 한건지;
      그정돈 기본으로 하실 줄 알아야죠

    13. Blog Icon
      쯧쯧

      지금 공부나 제대로 하실지, 일이나 제대로 하고 계실지...... 수준이 보이네요 쯧쯧.. 나중에 마주치지 않기를 바랄 뿐입니다

    14. Blog Icon

      밥은 드시고 다니시나요???

    15. Blog Icon
      개발자

      와~~~ 정리 잘되어있네요 .. 감사합니다^^

    16. Blog Icon
      나같은사람

      정말 아주 아주 좋은정보 감사 함니다.
      이런 자료많이 올려주시면 감사하겠습니다.
      잘쓰겠습니다

    17. Blog Icon
      허어얼

      정리가 넘 잘되었네요 굿굿

    18. Blog Icon
      민경우

      정말 감사합니다 안드로이드 하나도 모르는데 이런 꿀같은 정보가...

    19. Blog Icon
      배우는자

      안녕하세요 요즘 자바 그레고리아 켈린더 함수 배우는 학생인데요

      그 5일뒤 소스를 제가 그대로 적용 시켜봤는데 뭔가 에러가 나더라구요..

      염치없지만.. 제가 이유를 좀 알고싶은데 혹시 가르쳐주실수 있으신가여

    20. Blog Icon
      배우는자

      아 에러 잡았습니다 소스 감사합니다.

    21. Blog Icon
      김정식

      너무 유용하게 잘 봤습니다.^^

    22. Blog Icon
      감사합니다

      감사합니다!!

    23. 잘 보고 베껴 갑니다.
      함께 보려고
      http://blog.daum.net/andro_java/181
      페이지에 올렸습니다.

    24. Blog Icon

      감사합니다. 잘 보고 갑니다

    Java 6의 새로운 기능, 향상된 부분.

    2008/01/20 22:53

    서비 JAVA ,




    Java 6가 릴리즈 된지 꽤 시간이 흘렀지만, 아직까지 어디가 어떻게 변경되고, 향상되었는지 찾아보지 못하고 있었다.
    아래 두 링크의 기사는 java 6의 새로운 기능화, 어떤부분이 개선되었는지 잘 나타내고 있으므로 시간을 내어 꼭 한번
    읽어두도록하자.

    What's New in Java SE 6
    Features and Enhancements

    2008/01/20 22:53 2008/01/20 22:53
    Trackback Address:이 글에는 트랙백을 보낼 수 없습니다