레이블이 java인 게시물을 표시합니다. 모든 게시물 표시
레이블이 java인 게시물을 표시합니다. 모든 게시물 표시

Java - 파일 쓰기 성능 비교

1. 자바에서 파일 쓰기 구현시 어떤 방법이 빠른지 테스트.
- FileWriter fw = new FileWriter(LOG_HOME+"writer.log");
- BufferedWriter bw = new BufferedWriter(new FileWriter(LOG_HOME+"writer.log"));
- FileOutputStream fos = new FileOutputStream(LOG_HOME+"outputstream.log");
- BufferedOutputStream fos = new BufferedOutputStream(
               new FileOutputStream(LOG_HOME+"bufferedoutputstream.log"));
- FileChannel fc =
       (new FileOutputStream(new File(LOG_HOME+"filechannel.log"))).getChannel();
// Byte Buffer 매번 생성
- FileChannel fc =
       (new FileOutputStream(new File(LOG_HOME+"filechannel.log"))).getChannel();
// ByteBuffer 재사용

2. 테스트 결과
                                                           1K    2K      5K     10K      50K
FileWriter                                               31    32      94     203     1281
FileWriter + BufferedWriter                        15    31      94     188     1000
FileOutputStream                                     32    47    109     188     1063
FileOutputStream + BufferedOutputStream    31    47    109     203     1578
FileChannel                                             47    63    109     219     2906
FileChannel + Byte Buffer 재사용                 31    47    188     250     2766

FileWriter와 FileOutputStream의 성능이 높게 나옴.
BufferedWriter 등의 경우 GC를 유발하는 문제가 있기 때문에 성능 저하 요인이 될 수 있으나, 테스트 결과로는 FileWriter + BufferedWriter의 경우가 성능이 제일 좋음.

Java - 성능 향상 (프로그래밍)

* 자바에 적합한 프로그래밍 방법을 사용하여 성능 향상 효과를 얻을 수 있음.

* final 사용
final 클래스는 컴파일러에 의해 하위 클래스에 의해서 오버라이딩이 불가능한 클래스로 인식되어 컴파일시 동적 메소드 호출 기능을 제거하여 메소드 호출을 최적화. 따라서 일반 메소드 호출보다 훨씬 빠름.
클래스 전체를 final로 사용하는 것은 문제가 발생할 가능성이 많으므로 꼭 필요한 경우가 아니라면 피하는 것이 좋음.
메소드 단위로 final을 사용하는 것이 효율적.

* String 대신 StringBuffer 사용
String은 자바가상머신에 의해 StringBuffer 로 변환되어 처리됨.
String 결합(concat) 연산은 내부적으로 StringBuffer로 변환되어 결합 후 다시 String으로 변환되기에 많은 자원이 소모됨.
따라서 String보다는 StringBuffer 혹은 char 배열을 사용하는 것이 빠름.

* 임시 객체 생성 자제
반복문이나 자주 사용하는 메소드 내에서 생성하는 임시 객체들은 가비지 컬렉터에게 부하를 줌.
따라서 반복문이나 자주 사용하는 메소드 내에서 임시 객체 생성을 피하는 것이 좋음.

Java - 성능 저하 원인

* 멀티스레드, 가비지컬렉션, 런타임 바인딩 등은 자바에서 제공하는 편리한 기능이나 프로그램 실행 속도를 느리게하는 원인이 된다. 이러한 기능을 지원하기 위해 보다 많은 자원과 계산이 필요하기 때문.

* 동적 바인딩 / 동적 클래스 로딩
자바는 런타임시 필요한 클래스들을 바인딩. C는 컴파일시 처리. 상대적으로 자바가 함수 호출이 느림.
동적 클래스 로딩은 실행중에 자바 가상 머신에 의해 안전한지 검사하고 초기화하기 때문에 성능 저하를 유발.

* 가비지 컬렉션
사용되지 않는 객체의 메모리를 자동으로 가용 자원으로 돌려주는 유용한 기능이나, 백그라운드에서 스레드로 수행되어야 하기 때문에 성능 저하를 유발.

* 멀티스레드
멀티스레드 사용에 있어 중요한 부분이 스레드간 충돌을 방지하고, 공유 자원에 대한 일관성을 유지하는 것으로 이를 동기화라고 한다.
동기화를 위해 synchronized 키워드를 사용하는데, 스레드 모니터에서는 모든 스레드를 관리하며 synchronized 설정된 스레드가 한 순간에 한 번만 사용되도록 해야한다.
JDK에서 제공되는 많은 메소드들이 synchronized 선언되어 있으며, 백그라운드에서 스레드모니터가 항상 스레드 관리 작업을 수행하는데 많은 자원이 소모되어 성능 저하를 유발

Java - 문자열로된 숫자 자리수 채우기

* String.format 을 사용하여 빈 자리를 0으로 채울 수 있다.
 


* 사용예
System.out.pringln( String.format("%03d", 3) ); => 003
System.out.pringln( String.format("%02d", 2) ); => 02
System.out.pringln( String.format("%02d", 10) ); => 10

Java - JSch를 사용하여 SFTP 파일 업로드 하기

* JSch 라이브러리를 사용하여 SFTP 접속 및 파일 업로드
  (http://www.jcraft.com/jsch/)


import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpATTRS;
import com.jcraft.jsch.SftpException;


JSch jsch = new JSch();
Session session = null;
ChannelSftp channelSftp = null;
   
/**
 * SFTP 접속
 * @param ip 아이피
 * @param port 포트
 * @param id 로그인아이디
 * @param pw 로그인비밀번호
 */
public void connect(String ip, int port, String id, String pw)
{
    // 연결 시도
    session = jsch.getSession(id, ip, port);
    session.setPassword(pw);
    java.util.Properties config = new java.util.Properties();
    config.put("StrictHostKeyChecking", "no");
    session.setConfig(config);
    session.connect(); 
   
    // 방식 설정
    Channel channel = session.openChannel("sftp");
    channel.connect();
    channelSftp = (ChannelSftp)channel;
}

/**
 * SFTP 접속 종료
 */
public void disconnect()
{
    if (channelSftp != null)
        channelSftp.disconnect();

    if (session != null)
        session.disconnect();
}
   
/**
 * 폴더 확인 및 생성
 * @param dir 폴더명(경로포함)
 */
public void checkDir(String dir)
{
    SftpATTRS attrs = null;

    // 폴더 체크
    try
    {
        attrs = channelSftp.stat(dir);
    }
    catch(Exception e)
    {
        attrs = null;
    }
   
    // attrs가 널이면 폴더 존재 X
    if (attrs == null)
    {
        channelSftp.mkdir(dir); // 폴더 생성
    }
}
   
   
/**
 * 폴더 이동
 * @param dir 폴더명(경로포함)
 */
public void moveDir(String dir)
{
    // 폴더 이동..
    channelSftp.cd(dir);
}   
   
/**
 * 파일 업로드.
 * @param fileName 파일명(경로포함)
 * @param fileData 파일내용
 * @return
 */
public boolean fileUpload(String fileName, byte[] fileData)
{
    OutputStream os = channelSftp.put(fileName);
    os.write(fileData);
    os.flush();
    os.close();
}

Java - 문자열로된 날짜 유효성 체크하기

* java.text.DateFormat.setLenient(boolean lenient)를 활용하여 체크.
  lenient를 false로 설정하면 유효한 날짜가 아닐 경우 ParseException이 발생.




import java.text.SimpleDateFormat;

/**
 * 문자열로 된 날짜 형식이 유효한지 체크
 * @param dateStr
 * @return 유효하면 true, 아니면 false
 */
public static boolean checkDateYYYYMMDD(String dateStr)
{
    try {
        SimpleDateFormat sdfYYYYMMDD = new SimpleDateFormat("yyyyMMdd");
        sdfYYYYMMDD .setLenient(false);
        sdfYYYYMMDD .parse(dateStr); //ex) dateStr="20201232"이면 ParseException 발생
        return true;
    } catch(ParseException e) {
        return false;
    } catch(Exception e) {
        return false;
    }
}

Java - StringBuilder와 StringBuffer의 차이

StringBuilder와 StringBuffer의 차이는 멀티쓰레드 지원 여부.

*** StringBuilder ***
멀티쓰레드에서 동기화 지원 X
StringBuffer 보다 빠름

*** StringBuffer ***
멀티쓰레드에서 동기화 지원 O
StringBuilder 보다 느림

Java - 만 나이 계산

*** 생년월일을 기준으로 현재 나이 계산 ***
 public int getAge(int birthYear, int birthMonth, int birthDay)
{
        Calendar current = Calendar.getInstance();
        int currentYear  = current.get(Calendar.YEAR);
        int currentMonth = current.get(Calendar.MONTH) + 1;
        int currentDay   = current.get(Calendar.DAY_OF_MONTH);
      
        int age = currentYear - birthYear;
        // 생일 안 지난 경우 -1
        if (birthMonth * 100 + birthDay > currentMonth * 100 + currentDay) 
            age--;
      
        return age;
}

Java - 이미지 크기 변경

String imgSourcePath= "test_image.jpg";       // 원본 이미지 파일명 (경로 포함)
String imgTargetPath= "test_imageNew.jpg";    // 새 이미지 파일명(경로 포함)
String imgFormat = "jpg";                     // 새 이미지 포맷. jpg, gif 등
int newWidth = 640;              // 새 이미지 넓이
int newHeight = 360;             // 새 이미지 높이



imgResize(imgSourcePath, newImgFilePath, imgFormat, newWidth, newHeight);


/**
 * Image Resize
 */
public void imgResize(String imgSourcePath, String imgTargetPath, String imgFormat, int newWidth, int newHeight)
{
    try
    {
        // 원본 이미지 가져오기
        Image imgSrc = ImageIO.read(new File(imgSourcePath));

        // 이미지 리사이즈
        // Image.SCALE_DEFAULT : 기본 이미지 스케일링 알고리즘 사용
        // Image.SCALE_FAST    : 이미지 부드러움보다 속도 우선
        // Image.SCALE_SMOOTH  : 속도보다 이미지 부드러움을 우선
        // Image.SCALE_AREA_AVERAGING  : 평균 알고리즘 사용
        Image resizeImage = imgSrc.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH);

        // 새 이미지  저장하기
        BufferedImage newImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
        Graphics g = newImage.getGraphics();
        g.drawImage(resizeImage, 0, 0, null);
        g.dispose();
        ImageIO.write(newImage, imgFormat, new File(imgTargetPath));
    }
    catch (Exception e)
    {
    }
}

Java - URL 이미지 파일로 저장하기


String imgUrl = "http://www.a.com/test_image.jpg";  // 이미지 URL
String imgFilePath = "test_image.jpg";              // 저장할 파일명 (경로 포함)
String imgFormat = "jpg";                         // 저장할 이미지 포맷. jpg, gif 등

getImageFromUrl(imgUrl, imgFilePath, imgFormat);






/**
 * Image URL to File
 */
public void getImageFromUrl(String imgUrl, String imgFilePath, String imgFormat)
{
        try
        {
            // Image 가져오기
            BufferedImage image = ImageIO.read(new URL(imgUrl));
                       
            // Image 저장할 파일
            File imgFile = new File(imgFilePath);
           
            // Image 저장
            ImageIO.write(image, imgFormat, imgFile);
        }
        catch (Exception e)
        {
        }
}

Java - SHA1 샘플

* byte 데이터를 입력받아 SHA1로 변환한 결과 문자열을 리턴한다.


public static String convertSHA1(byte[] srcBytes)
    {
        try
        {
            MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
            messageDigest.update(srcBytes);
            byte digestBytes[] = messageDigest.digest();
           
            return String.format("%0" + (2 * digestBytes.length) +  "x", new BigInteger(1, digestBytes));
        }
        catch(Exception e)
        {
        }
       
        return null;
    }

Java - split 사용시 특수문자

* split 사용시 특수문자를 사용하면 에러가 발생

String testStr = "1^2^3^4";
String[] testList = testStr.split("^");   ---> 에러

* 특수문자 앞에 \\ 을 붙이면 에러가 발생하지 않음
String[] testList = testStr.split("\\^");   --->["1", "2", "3", "4"]

Java - 날짜 포맷 (FastDateFormat)

*** 설명 ***
기존 SimpleDateFormat 보다 빠름.
Thread Safe.
Apache Commons Lang 라이브러리 필요.

*** 사용예 ***
FastDateFormat fdf = FastDateFormat.getInstance("yyyyMMdd");
System.out.println("FastDateFormat =" + fdf.format(Calendar.getInstance()));

*** maven repository ***
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.4</version>
</dependency>

Java - 숫자 자리수 채우기

String.format 을 사용하여 빈 자리를 0으로 채울 수 있다.

ex)
System.out.pringln( String.format("%03d", 3) );  => 003
System.out.pringln( String.format("%02d", 2) );  => 02
System.out.pringln( String.format("%02d", 10) );  => 10

Java - JAXB를 사용한 XML to Java Object

JAXB를 이용해서 XML 데이터를 자바 오브젝트로 변경할 수 있다.


*** Maven Depenendcy ***
<dependency>
    <groupId>javax.xml</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.1</version>
</dependency>

*** JAXB 사용예 ***

JAXBContext context = JAXBContext.newInstance(Cars.class);
Unmarshaller un = context.createUnmarshaller();

Cars cars = un.unmarshal(new File(a.xml)); // File, InputStream, URL 등 사용 가능


*** a.xml ***
<Cars>
    <CarList>
        <CarInfo>
            <Name>abc</Name>
            <Year>2001</Year>
        </CarInfo>
        <CarInfo>
            <Name>zzz</Name>
            <Year>1999</Year>
        </CarInfo>
    </CarList>
    <TotalCount>2</TotalCount>
</Cars>

*** Cars.java ***
@XmlRootElement(name = "Cars")
public class Cars
{
    private List<CarInfo> carList;
    private int totalCount;

    public List<CarInfo> getCarList() {
        return carList;
    }

    @XmlElementWrapper(name = "CarList") 
    @XmlElement(name = "CarInfo")
    public void setCarList(List<CarInfo> carList) {
        this.carList = carList;
    }

    public int getTotalCount() {
        return totalCount;
    }

    @XmlElement(name = "TotalCount")
    public void setTotalCount(int totalCount) {
        this.totalCount = totalCount;
    }
}

*** CarInfo.java ***
@XmlRootElement(name = "CarInfo")
public class CarInfo
{
    private String name;
    private int year;

    public String getName() {
        return name;
    }

    @XmlElement(name = "Name")
    public void setName(String name) {
        this.name = name;
    }
  
    public int getYear() {
        return year;
    }

    @XmlElement(name = "Year")
    public void setYear(int year) {
        this.year = year;
    }
}