<?xml version="1.0" encoding="utf-8" ?>
<?xml-stylesheet href="http://rss.egloos.com/style/blog.xsl" type="text/xsl" media="screen"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
	<title>무위자연</title>
	<link>http://spore.egloos.com</link>
	<description>무위자연</description>
	<language>ko</language>
	<pubDate>Tue, 04 Aug 2009 20:30:21 GMT</pubDate>
	<generator>Egloos</generator>
	<image>
		<title>무위자연</title>
		<url>http://pds.egloos.com/logo/1/200408/30/95/b0026995.jpg</url>
		<link>http://spore.egloos.com</link>
		<width>80</width>
		<height>60</height>
		<description>무위자연</description>
	</image>
  	<item>
		<title><![CDATA[ VisualSVN+TortoiseSVN ]]> </title>
		<link>http://spore.egloos.com/4204242</link>
		<guid>http://spore.egloos.com/4204242</guid>
		<description>
			<![CDATA[ 
  <h2><font size="1">출처 : http://pureholic.net/2009/05/26/developing-enviormentvisual-studio-2008-visualsvn-server-tortoisesvn/</font><br />
</h2><h2>윈도우 통합개발 환경 구축하기(Visual Studio 2008 + VisualSVN Server + TortoiseSVN)</h2>		<div class="info">			<span class="date">5월 26th, 2009</span>			<span class="author"><a href="http://pureholic.net/author/admin/" title="동근 작성">동근</a></span>										<span class="addcomment"><a href="http://pureholic.net/2009/05/26/developing-enviormentvisual-studio-2008-visualsvn-server-tortoisesvn/#respond">댓글 남기기</a></span>				<span class="comments"><a href="http://pureholic.net/2009/05/26/developing-enviormentvisual-studio-2008-visualsvn-server-tortoisesvn/#comments">댓글로 바로가기</a></span>								</div>					<p>이제 본겨적으로 개발모드로 들어가기 전에 소스 관리 등을 위한 윈도우 개발환경을 구축할 필요가 있었다. 지금 깔아둔 것이라고는 학교에서 제공되는 Visual Studio 2008 …&nbsp;</p><p>소스관리가 필요하다. 나 같이 만들다가 갑자기 막 뜯어고치고 실패했을 때, 돌아가지 못하는 상황은 종종 발생된다. 그리고 끝도 없이 Ctrl + z 만 누르고 있다. 이제 그런 생활은 안녕! 소스관리모드 돌입!</p><p>&nbsp;</p><p><strong>1. VisualSVN&nbsp; 설치</strong></p><p>역시 소스관리에서 제일 유명하신 Subversion을 설치할 예정인데 Apache 깔고 이럴러면 일이 너무 많기 때문에 한방에 해결해주는 VisualSVN Server로 결정!</p><p>재미있는 것이 VisualVCN Client는 유료인데, Server는 무료다.</p><blockquote><p>Download : <a href="http://www.visualsvn.com/server/">http://www.visualsvn.com/server/</a></p></blockquote><p>부담없는 용량 약 4M의 프로그램을 다운 받아서 설치!</p><p style="text-align: center;"><a title="Flickr에서 PureBuddy님의 VisualSVN Server" href="http://www.flickr.com/photos/purebuddy/3566002198/"><img class="aligncenter" src="http://farm4.static.flickr.com/3390/3566002198_8b44c4bdec.jpg" alt="VisualSVN Server" height="339" width="500"></a>&nbsp;</p><p>&nbsp;</p><p><strong>2. TortoiseSVN 설치</strong></p><p>Subversion의 유명한 GUI 클라이언트 프로그램인&nbsp;TortoiseSVN을 설치한다. 이 녀석은 윈도우의 쉘(explorer) 확장 프로그램으로 탐색기 팝업 메뉴에서 Subversion 작업을 할 수 있게 도와준다.</p><blockquote><p>Download : <a href="http://tortoisesvn.net/downloads">http://tortoisesvn.net/downloads</a><br />
한글언어팩 : <a href="http://tortoisesvn.net/translation_release_gui">http://tortoisesvn.net/translation_release_gui</a></p></blockquote><p>위의 주소에서 부담없이 받을 수 있다. 역시 오픈소스 사랑해요!&nbsp;</p><p>설치를 완료하면 재부팅을 요구한다. 귀찮게 하지만 작업관리자-Task Manager(Ctrl+Alt+Del)로 들어가서 쉘(explorer.exe)만 종료한 뒤 프로그램을 시작할 수 있다. 언어팩은 귀찮으니깐 패스!</p><p>&nbsp;</p><p><strong>3. 저장소(Repository) 만들기</strong></p><p>저장소는 VisualSVN으로도 만들 수 있고 TortoiseSVN을 이용해서도 만들 수 있다. 아래의 이미지를 참고해서편한 스타일로 만들도록 한다. 어차피 현재(2009.05.26) 저장소를 만들 때, 기본적인 파일시스템(Native FS,FSFS)의 방법으로 만들어졌다.</p><p>아래의 이미지는 MediaGestures 라는 프로젝트를 위한 저장소이다.</p><p style="text-align: center;"><a title="Flickr에서 PureBuddy님의 저장소 만들기 using TortoiseSVN" href="http://www.flickr.com/photos/purebuddy/3566002278/"><img class="aligncenter" src="http://farm4.static.flickr.com/3567/3566002278_a96676f704.jpg" alt="저장소 만들기 using TortoiseSVN" height="371" width="500"></a></p><p style="text-align: center;"><a title="Flickr에서 PureBuddy님의 저장소 만들기 using VisualSVN Server" href="http://www.flickr.com/photos/purebuddy/3566002324/"><img class="aligncenter" src="http://farm4.static.flickr.com/3566/3566002324_2cb637c6e8.jpg" alt="저장소 만들기 using VisualSVN Server" height="339" width="500"></a><br />
&nbsp;</p><p><strong>4. 저장소(Repository)의 설정</strong></p><p>만들어진 저장소 안의 conf 디렉토리안에 설정과 관련된 파일들이 존재한다.</p><ul><li>svnserve.conf : svnserve를 사용한 저장소 서버를 구성할 때 사용</li><li>passwd : svnserve에서 사용되는 사용자 ID/PW</li><li>authz : svnserver, Apache에서 사용, 접근 권한 설정 파일</li></ul><p>하지만 이런 설정을 Linux도 아닌 윈도우에서 GUI없이 한다는 것은 매우 불편하다. 그래서 역시 VisualSVNServer를 사용해준다.&nbsp; Properties&nbsp;로 들어가서 간단하게 필요한 User를 추가해주면 알아서 자동으로 된다. 자세한것은 알려하지 말자 머리아프다.</p><p>authz 설정은 Hooks 항목에서 설정할 수 있다. 필요하면^^;</p><p style="text-align: center;"><a title="Flickr에서 PureBuddy님의 SVN 유저설정" href="http://www.flickr.com/photos/purebuddy/3565186161/"><img class="aligncenter" src="http://farm4.static.flickr.com/3372/3565186161_a7646e3144_o.jpg" alt="SVN 유저설정" height="489" width="384"></a><br />
&nbsp;</p><p><strong>5. 저장소(Repository) 기본 디렉터리 생성</strong></p><p>기본적으로 필요한 trunk, branches, tags&nbsp;디렉터리를 생성한다. VisualSVN Server로 저장소를 만들 때 기본으로 함께 만들 수도 있다.</p><p style="text-align: center;"><a title="Flickr에서 PureBuddy님의 기본 디렉터리 생성" href="http://www.flickr.com/photos/purebuddy/3565186225/"><img class="aligncenter" src="http://farm4.static.flickr.com/3374/3565186225_a50be28b45.jpg" alt="기본 디렉터리 생성" height="339" width="500"></a></p><ul><li><div style="text-align: left;">trunk : 개발이 이루어지는 디렉터리</div></li><li><div style="text-align: left;">branches : 프로젝트 안의 작은 프로젝트</div></li><li><div style="text-align: left;">tags : 릴리즈 버젼 보관 장소</div></li></ul><p><strong>6.&nbsp; SVN에 접속하기</strong></p><p>TortoiseSVN을 이용해서 SVN에 접속할려면 바탕화면에서 오른쪽 클릭 -&gt; TortoiseSVN -&gt;Repo-Browser을 클릭하고 URL(VisualSVN Server에 적힌 주소를 사용하면 된다) 입력하면 접속할 수 있다.</p><p style="text-align: center;"><a title="Flickr에서 PureBuddy님의 SVN 연결된 모습" href="http://www.flickr.com/photos/purebuddy/3566002528/"><img class="aligncenter" src="http://farm4.static.flickr.com/3411/3566002528_4f45c5bdc8.jpg" alt="SVN 연결된 모습" height="384" width="500"></a>&nbsp;</p><p><strong>7.&nbsp;프로젝트 Import 하기</strong></p><p>저장소로 프로젝트를 Import하여 이제 사용하는 방법을 알아본다. 간단하게 탐색기에서 임포트할 프로젝트를 SVN &gt; Import 하면 된다.</p><p style="text-align: center;"><a title="Flickr에서 PureBuddy님의 Project Import" href="http://www.flickr.com/photos/purebuddy/3565186343/"><img class="aligncenter" src="http://farm4.static.flickr.com/3335/3565186343_9e0d307cbd.jpg" alt="Project Import" height="408" width="500"></a>&nbsp;</p><p style="text-align: center;"><a title="Flickr에서 PureBuddy님의 프로젝트 임포트 화면" href="http://www.flickr.com/photos/purebuddy/3566002670/"><img class="aligncenter" src="http://farm4.static.flickr.com/3305/3566002670_bc7c717b9b_o.jpg" alt="프로젝트 임포트 화면" height="347" width="466"></a></p><p style="text-align: center;"><a title="Flickr에서 PureBuddy님의 프로젝트 임포트 중" href="http://www.flickr.com/photos/purebuddy/3566002770/"><img class="aligncenter" src="http://farm4.static.flickr.com/3625/3566002770_2b2ae18fe6.jpg" alt="프로젝트 임포트 중" height="229" width="500"></a></p><p><strong>&nbsp;</strong></p><p><strong>8. SVN Checkout 으로 프로젝트 받기</strong></p><p>이제 거의 끝났다. SVN에 있는 프로젝트를 받아서 바뀐 파일들을 쉽게 파악할 수 있도록 <strong>SVN Checkout을 클릭</strong>해서 원하는 위치로 받는다. 그럼 아래의 화면처럼 v(체크)표시는 바뀌지 않은 것들이고 !(느낌표)는 수정된 파일이기 때문에 commit이 필요하다는 것을 의미한다.</p><p style="text-align: center;"><a title="Flickr에서 PureBuddy님의 SVN checkout 완료" href="http://www.flickr.com/photos/purebuddy/3566002718/"><img class="aligncenter" src="http://farm4.static.flickr.com/3361/3566002718_3780cd637c.jpg" alt="SVN checkout 완료" height="396" width="500"></a></p><p>아.. 힘들다. 오늘은 여기까지 SVN을 본격적으로 사용하는 것은 다음 번에 생각하고 일단 여기까지 만족!</p>			 ]]> 
		</description>

		<comments>http://spore.egloos.com/4204242#comments</comments>
		<pubDate>Tue, 04 Aug 2009 20:30:21 GMT</pubDate>
		<dc:creator>vimming</dc:creator>
	</item>
	<item>
		<title><![CDATA[ 자바의 문자깨짐 대책FAQ ]]> </title>
		<link>http://spore.egloos.com/4198440</link>
		<guid>http://spore.egloos.com/4198440</guid>
		<description>
			<![CDATA[ 
  <p>출처:http://www.atmarkit.co.jp/fjava/rensai3/mojibake01/mojibake01.html</p><p>번역:제갈장비</p><p>* 일본어 문자깨짐 해결에 대한 문서를 번역한 것입니다.<br />
* 한글상황에 맞지 않는 코드 부분을 염두에 두시길 바랍니다.</p><p>자바의 문자깨짐 대책FAQ(1)<br />
</p><p>웹브라우저가 문자코드를 판별하는 기준은?</p><p>JSP/Servle 프로그래밍에서 누구든 한번은 만나는 트러블이 문자깨짐이다.<br />
예기치않게 문자깨짐으로인해 디버그로 고생한 경험이 있는 사람도 많을<br />
것이다. 이 연재에서는 JSP/Servle에서 문자열 취급의 기초를 복습하고 <br />
문자깨짐의 해결책을 해설 할 예정이다.(편집국)</p><p>&nbsp;</p><p><span style="color: rgb(255, 255, 255); background-color: rgb(0, 0, 255);">질문1:웹브라우저는 어떻게 문자코드를 판별하는가?<br />
해답:HTTP의 Cotent-Type 헤더이다.</span></p><p>&nbsp;</p><p>HTML 4.01 사양에서는 웹브라우저가 이하의 우선순위로 문자코드를 결정하도록<br />
규정되어 있다.<br />
<span style="color: rgb(255, 255, 255); background-color: rgb(0, 153, 102);">1. HTTP에서 Content-Type 헤더의 charset 파라메타.<br />
2. HTML문서 내의 META선언 및 http-equiv 속성으로 설정된 <br />
&nbsp;&nbsp; Content-Type 헤더의 charset 파라메타.<br />
3. HTML문서 내 각요소의 charset속성.</span></p><p>&nbsp;</p><p>웹서버가 송신하는 HTTP헤더에는 송신내용이 어떠한 성질의 콘텐츠인가를<br />
웹브라우저에 알리기 위해 이하와 같은 Content-Type 헤더를 통하여<br />
콘텐츠의 미디어타입(이하의 예에서는 text/html)을 명시한다.</p><p>&nbsp;</p><p>&nbsp;&nbsp;&nbsp;&nbsp; <span style="background-color: rgb(228, 255, 117);">Content-Type: text/html; charset=Shift_JIS</span></p><p>&nbsp;</p><p>이것에 의해 웹브라우저는 수신한 콘텐츠가 HTML문서인지 영상화일인지 혹은 <br />
외부 어플리케이션이나 플러그인으로 열어야 할 화일인지를 판별한다.</p><p>웹브라우저가 HTML문서의 문자코드를 판별할 때에는 이 미디어타입의 <br />
charset 파라메타를 최우선으로 참조한다.<br />
만약, charset 파라메타나 Content-Type 헤더 자체가 없는 경우에는 <br />
HTML문서 내에 META선언이 있는지 찾는다.<br />
그래도 문자정보를 얻지 못하면 HTML문서의 내용으로 추측하여 문자코드를 <br />
자동판별한다.</p><p>문자코드를 웹브라우저에 확실하게 전달하기 위해서는 웹서버가 송신하는 <br />
Content-Type 헤더를 사용하면 된다.<br />
달리말하면, HTML문서 내에서 META선언을 지정했다 하더라도 아무 효과가 <br />
없는 경우가 많다.<br />
예를 들어, META선언으로 문자코드를 지정하는 이하와 같은 JSP페이지를 <br />
작성해 보자.</p><p>&nbsp;</p><p><span style="background-color: rgb(228, 255, 117);">&lt;%@ page language="java" %&gt;<br />
&lt;html&gt;<br />
&lt;head&gt;<br />
&nbsp; &lt;meta http-equiv="Content-Type" content="text/html; charset=EUC-KR" /&gt;<br />
&nbsp; &lt;title&gt;테스트&lt;/title&gt;<br />
&lt;/head&gt;<br />
&lt;body&gt;<br />
&nbsp; 테스트<br />
&lt;/body&gt;<br />
&lt;/html&gt;</span></p><p>&nbsp;</p><p>이 JSP페이지를 서블릿 컨테너 Tomcat(Tomcat 5.0.28)에서 출력하면 <br />
문자전체가 깨지는 것을 볼 수 있다.<br />
이와같이, JSP파일 내의 META선언에의한 문자코드 지정은 잘 되지 않는다.<br />
왜냐하면, Tomcat은 Content-Type 헤더에 디폴트 문자코드인 ISO-8859-1을 <br />
지정하기 때문에 이것이 META선언보다 우선한다.</p><p>이러한 트러블을 피하기 위해서는 출력할 HTML문서의 문자코드를 Tomcat에 <br />
확실하게 전달할 필요가 있다. 구체적으로는 이하의 2가지 방법이 있다.</p><p><br />
&nbsp;<span style="color: rgb(255, 255, 255); background-color: rgb(0, 0, 255);">- JSP의 경우&nbsp;&nbsp;&nbsp; : page directive로 문자코드를 지정<br />
&nbsp;- 서블릿의 경우 : HttpServletResponse.setContentType 메소드로&nbsp;문자코드를 지정</span></p><p><br />
JSP의 경우, page directive로 문자코드를 바르게 기술해 둔다.<br />
이 page directive 부분에 지정해 두면 META선언에 의한 지정은 불필요하다.<br />
그리고 서블릿의 경우, HttpServletResponse 오브젝트의 <br />
setContentType 메소드를 이용하여 서블릿이 출력할 콘텐츠의 문자코드를 <br />
명시하면 된다.</p><p>&nbsp;</p><p>&nbsp; <span style="background-color: rgb(228, 255, 117);">res.setContentType("text/html; charset=Windows-31J");</span></p><p>&nbsp;</p><p>덧붙여서, 아파치 HTTP서버와 Tomcat을 연동하는 경우, <br />
아파치의 httpd.conf에 이하와 같은 디폴트 문자코드가 지정되어 있으면 <br />
그것이 우선되므로 그 행을 코멘트아웃 처리해야 한다.</p><p>&nbsp;</p><p>&nbsp; AddDefaultCharset ISO-8859-1</p><p><br />
&nbsp;</p><p><span style="color: rgb(255, 255, 255); background-color: rgb(0, 0, 255);">질문2:page directive에서 문자코드를 바르게 지정하는 방법은?<br />
</span></p><p><span style="color: rgb(255, 255, 255); background-color: rgb(0, 0, 255);">해답:contentType 속성과 pageEncoding 속성을 기술한다.</span></p><p>&nbsp;</p><p>JSP파일의 문자코드를 서블릿 컨테너에 전하여 적절한 Content-Type 헤더를 <br />
출력하려면 JSP파일의 선두에 이하의 page directive를 기술하면 된다.</p><p>&nbsp;</p><p>&lt;%@ page language="java" contentType="text/html; charset=Windows-31J"<br />
&nbsp;&nbsp;&nbsp; pageEncoding="Windows-31J" %&gt;</p><p>&nbsp;</p><p>이 2가지의 속성은 각기 다음과 같은 역할을 담당한다.<br />
</p><p><span style="color: rgb(255, 255, 255); background-color: rgb(0, 153, 102);">&nbsp; - contentType&nbsp; 속성 : JSP파일 출력시 문자코드 및 Content-Type 헤더에&nbsp;</span></p><p><span style="color: rgb(255, 255, 255); background-color: rgb(0, 153, 102);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 출력할 문자코드명을 지정<br />
</span></p><p><span style="color: rgb(255, 255, 255); background-color: rgb(0, 153, 102);">&nbsp; - pageEncoding 속성 : JSP파일 작성시의 문자코드를 지정</span></p><p>&nbsp;</p><p>자바가상머신(JVM)의 내부에서는 모든 문자열이 Unicode로 표현된다.<br />
그러므로 서블릿 콘테너는 JSP파일을 JVM에 읽어들일 때 JSP파일의<br />
문자코드(예를들어 Windows-31J)에서 Unicode로 변환한다. <br />
그리고 웹브라우저에 HTML문서를 출력할 때는 Unicode로부터 출력파일의 <br />
문자코드로 변환한다.</p><p>&nbsp;</p><p>■contentType 속성의 역할<br />
</p><p>contentType 속성은 "JSP파일 출력시의 문자코드", "Content-Type 헤더에 <br />
지정할 문자코드"의 양쪽을 지정하는 기능을 갖는다. <br />
상기 코드와 같이 기술하면 서블릿 콘테너는 콘텐츠를 Windows-31J로 <br />
Encode하여 출력한다.<br />
또한 동시에 Content-Type 헤더를 통하여 문자코드 종류를 웹브라우저에 <br />
전달한다.</p><p>&nbsp;</p><p>■pageEncoding 속성의 역할<br />
</p><p>pageEncoding 속성은 "JSP파일 작성시의 문자코드"를 지정하기 위한 <br />
속성으로서 JSP 1.2사양(Tomcat 4.0) 이후부터 지원된다. <br />
예를들어, 윈도우즈에서 작성한 JSP파일이면 Windows-31J를 지정하면 된다.<br />
UNIX의 일본어 에디터로 작성한 것이라면 EUC-JP를 지정하면 바르게 처리될 <br />
것이다.</p><p>pageEncoding 속성을 생략한 경우, JSP 1.2 사양에서는 <br />
"contentType 속성에서 지정된 문자코드로 JSP파일을 읽어들임"<br />
이라고 규정되어 있다. <br />
그러므로 보통은 생략해도 문자깨짐이 발생할 염려는 없다.<br />
그렇지만 <u>Windows-31J -&gt; Unicode -&gt; Windows-31J</u> 의 문자코드 변환은 <br />
기억해 둬야 한다.<br />
또한 include 된 JSP파일에서는 contentType 속성을 기술할 수 없으므로 <br />
pageEncoding 속성을 이용할 필요가 있다.<br />
이 문제에 대해서는 다음회에 설명할 예정이다.<br />
덧붙여, contentType 속성과 pageEncoding 속성에는 각기 다른 문자코드를 <br />
지정할 수도 있다.<br />
예를들어 ShiftJIS로 작성한 JSP파일을 EUC-JP,UTF-8등으로 출력하는 것도 <br />
가능하다.</p><br />
			 ]]> 
		</description>
		<category>tomcat</category>

		<comments>http://spore.egloos.com/4198440#comments</comments>
		<pubDate>Mon, 27 Jul 2009 20:40:26 GMT</pubDate>
		<dc:creator>vimming</dc:creator>
	</item>
	<item>
		<title><![CDATA[ Tomcat/JSP와 한글 ]]> </title>
		<link>http://spore.egloos.com/4198438</link>
		<guid>http://spore.egloos.com/4198438</guid>
		<description>
			<![CDATA[ 
  총 정리 차원에서...<br />
Tomcat 한글 설정하기<br />
일반적으로 웹 어플리케이션이 GET과 POST 방식으로 파라미터를 넘겨 받을 때 request.setCharacterEncoding()을 통한 문자셋 인코딩이 필요하다.<br />
<br />
<b>◎ Tomcat 4.x</b><br />
단순히 JSP 혹은 서블릿의 최 상단에 <b>request.setCharacterEncoding("euc-kr");</b>을 하면 된다.<br />
GET과 POST 방식에 상관없이 인코딩을 해준다.<br />
<br />
<b>◎ Tomcat 5.x</b><br />
POST 방식은 request.setCharacterEncoding("euc-kr");로 계속 하면된다.<br />
하지만 GET 방식은 server.xml의 <connector> 설정 부분을 바꿔줘야만 한다.<br />
<br />
</connector><blockquote class="src">&lt;Connector port="8080"<br />
&nbsp;&nbsp;maxThreads="150" minSpareThreads="25" maxSpareThreads="75"<br />
&nbsp;&nbsp;enableLookups="false" redirectPort="8443" acceptCount="100"<br />
&nbsp;&nbsp;debug="0" connectionTimeout="20000"<br />
&nbsp;&nbsp;disableUploadTimeout="true" URIEncoding="euc-kr"/&gt;<br />
<br />
&lt;Connector port="8009"<br />
&nbsp;&nbsp;enableLookups="false" redirectPort="8443" debug="0"<br />
&nbsp;&nbsp;protocol="AJP/1.3" URIEncoding="euc-kr"/&gt;<br />
</blockquote><br />
위에서 <strong>URIEncoding="euc-kr"</strong> 부분이다.그리고 아래의 port="8009" 부분은 mod_jk를 이용해서 Apache와 Tomcat 5.x 를 연동할 때 URIEncoding="euc-kr"을 지정할 필요가 있다.<br />
<br />
URIEncoding으로 지정할 경우, 만약 웹 어플리케이션이 EUC-KR과 UTF-8을 각 요청 별로 따로 처리할 필요가 있을경우 그에 대응할 수 없다. 대신, <strong>useBodyEncodingForURI="true"</strong>을 사용하면 Tomcat 4.x와 동일한 방식으로 즉, request.setCharacterEncoding() 값에 따라 GET/POST 방식 모두를 처리할 수도 있다. (참조 : <a title="" href="http://tomcat.apache.org/tomcat-5.5-doc/config/http.html">http://tomcat.apache.org/tomcat-5.5-doc/config/http.html</a>)<br />
<br />
결론적으로 Tomcat 4.x와 Tomcat 5.x 는 모두 request.setCharacterEncoding()이 필요하다는 사실에는 변함이 없다.<br />
<br />
<b>◎ 한글 파라미터를 가진 링크를 만들 때</b><br />
JSP페이지에서 링크를 생성할 때, 한글이 됐든 공백이나 특수문자를 가진 영어가 됐든, 순수하게 영어와 숫자, 밑줄 등으로만 이뤄진게 아닌 모든 파라미터를 넘길 때는 무조건 URLEncoding을 해야한다고 봐도 된다.<br />
<br />
WebContainer에 따라 URLEncoding을 안하고 넘겨도 작동하는 경우가 있는데, 동일한 웹 컨테이너라도 버전에 따라한글을 제대로 인식하지 못하는 경우도 있고, 또 다른 컨테이너에서는 URLEncoding이 안된 한글을 전혀 인식하지 못할 수도있다.<br />
<br />
그러므로 <b>무조건 표준을 따라서 java.net.URLEncoder.encode()메 소드를 사용해 인코딩해서 넘기도록 한다</b>.디코드 작업은 request.setCharacterEncoding()에 의해서 자동으로 이뤄지므로 해줄것이 없다.(Tomcat3.x대- JSP Spec 1.1 -에서는 request.setCharacterEncoding()이 없으므로String.getBytes()를 이용해 직접 디코딩을 해줘야만 했다)<br />
<br />
<b>◎ &lt;%@ include file="test.jspf"%&gt; 에서의 한글</b><br />
위와 같이 test.jspf를 static include 할 경우에 test.jspf에 있는 한글이 모두 깨질 수 있다.test.jspf에도 한글 설정이 필요한데, 이 경우에는 test.jspf의 최 상단에 다음을 추가하면 된다.<br />
<br />
<blockquote class="src">&lt;%@page pageEncoding="euc-kr"%&gt;<br />
</blockquote><br />
<ul><li>staticinclude : JSP 페이지를 컴파일하는 시점에 해당 jspf 파일의 내용을 문자열 그대로 현재 jsp에 삽입하여 컴파일하는 것. static include 방식에서 include 되는 대상 jsp의 확장자는 .jspf로 하는 것이 표준이다..jspf 는 단독 실행을 위한 것이 아니라 항상 다른 JSP에 포함되어 쓰이는 목적으로 만들어졌기 때문에 완전한 JSP의형태를 갖추고 있지 않다.<br />
</li><li>&lt;jsp:include page=""/&gt; 이 방식은 동적include 방식으로, JSP 페이지가 실행되는 중간에 page에 지정된 jsp를 실행한 결과를 삽입하는 방식이다. 이방식에서는 include 되는 JSP 페이지가 원래부터 페이지 인코딩 정보 등을 포함한 완전한 JSP 형태를 갖추고 있어야만한다.</li></ul>출처 : http://kwon37xi.egloos.com/1462013<br />
			 ]]> 
		</description>
		<category>tomcat</category>

		<comments>http://spore.egloos.com/4198438#comments</comments>
		<pubDate>Mon, 27 Jul 2009 20:01:20 GMT</pubDate>
		<dc:creator>vimming</dc:creator>
	</item>
	<item>
		<title><![CDATA[ [NIO-02] NIO를 이용한 간단한 예제 공부/Java ]]> </title>
		<link>http://spore.egloos.com/4169925</link>
		<guid>http://spore.egloos.com/4169925</guid>
		<description>
			<![CDATA[ 
  <pre>오늘 알아 볼것은 NIO가 동작하는 방법입니다.<br />
<br />
이제까지 사용하던 IO의 사용법은 다음과 같습니다.<br />
<br />
1. Stream을 연다.<br />
<br />
2. Stream에 쓴다.<br />
<br />
오~ 놀랍도록 간단합니다. ;;;;<br />
<br />
<br />
그럼 NIO가 동작하는 방법을 보겠습니다.<br />
<br />
1. Stream을 연다<br />
<br />
2. Stream에서 Channel을 얻는다.<br />
<br />
3. Buffer를 만들어 Channel에 쓴다.<br />
<br />
<br />
<br />
NIO는 스트림을 열고. 그곳에서 다시 채널을 얻어 냅니다.<br />
<br />
그런뒤에 그냥 일반적인 DATA를 쓰는것이 아니라.<br />
<br />
Buffer를 통째로 넘겨서 Channel에 쓰게 합니다.<br />
<br />
<br />
<br />
<br />
<br />
그럼 NIO에 대한 소스를 하나 보면서 설명 드리겠습니다.<br />
<br />
소스는 매닝사에서 나오고 인포북에서 번역 출간한<br />
<br />
" JDK 1.4 튜토리얼 " 을 참고 했습니다.<br />
<br />
=================================================================================<br />
<br />
<pre><br />
<br />
<tt><br />
<br />
01: <font color="#9a1900">// NioTest1.java</font><br />
<br />
02: <font color="#9a1900">/*</font><br />
<br />
03: <font color="#9a1900"> * 작성된 날짜: 2003. 12. 5.</font><br />
<br />
04: <font color="#9a1900"> *</font><br />
<br />
05: <font color="#9a1900"> * 프로그램명 :</font><br />
<br />
06: <font color="#9a1900"> * 버젼           :</font><br />
<br />
07: <font color="#9a1900"> * 파일명        : NioTest1.java</font><br />
<br />
08: <font color="#9a1900"> * </font><br />
<br />
09: <font color="#9a1900"> * 프로그램 설명 :</font><br />
<br />
10: <font color="#9a1900"> * </font><br />
<br />
11: <font color="#9a1900"> */</font><br />
<br />
12:  <br />
<br />
13: <font color="#000080">import</font> java.io.*;<br />
<br />
14: <font color="#000080">import</font> java.nio.*;<br />
<br />
15: <font color="#000080">import</font> java.nio.channels.*;<br />
<br />
16: <br />
<br />
17: <font color="#9a1900">/**</font><br />
<br />
18: <font color="#9a1900"> * @author ggaman.com</font><br />
<br />
19: <font color="#9a1900"> * http://ggaman.com</font><br />
<br />
20: <font color="#9a1900"> *</font><br />
<br />
21: <font color="#9a1900"> * 클래스 명 : NioTest1.java</font><br />
<br />
22: <font color="#9a1900"> * 버젼        :</font><br />
<br />
23: <font color="#9a1900"> * </font><br />
<br />
24: <font color="#9a1900"> * 하는 일 :</font><br />
<br />
25: <font color="#9a1900"> * </font><br />
<br />
26: <font color="#9a1900"> */</font><br />
<br />
27: <font color="#0000ff">public</font> <font color="#0000ff">class</font> NioTest1 <font color="#000000">{</font><br />
<br />
28:         <br />
<br />
29:         <font color="#9a1900">// 자 프로그램을 시작해 보죠.</font><br />
<br />
30:         <font color="#0000ff">public</font> <font color="#0000ff">static</font> <font color="#33cc00">void</font> <font color="#000000">main</font>(String[] args) <font color="#0000ff">throws</font> Exception <font color="#000000">{</font><br />
<br />
31:                 <br />
<br />
32:                 <font color="#9a1900">// 우선 화일 객체를 두개 만들겠습니다. 각각 입력과 출력을 맡을껍니다.</font><br />
<br />
33:                 File fi = <font color="#0000ff">new</font> <font color="#000000">File</font>(<font color="#ff0000">"input.txt"</font>) ;<br />
<br />
34:                 File fo = <font color="#0000ff">new</font> <font color="#000000">File</font>(<font color="#ff0000">"output.txt"</font>) ;<br />
<br />
35:                 <br />
<br />
36:                 <font color="#9a1900">// 이제 화일의 입출력을 하기 위해서 스트림을 만들어서 열어야 합니다.</font><br />
<br />
37:                 FileInputStream fis = <font color="#0000ff">new</font> <font color="#000000">FileInputStream</font>(fi);<br />
<br />
38:                 FileOutputStream fos = <font color="#0000ff">new</font> <font color="#000000">FileOutputStream</font>(fo);<br />
<br />
39:                 <br />
<br />
40:                 <font color="#9a1900">// #### 1</font><br />
<br />
41:                 <font color="#9a1900">// 여기서 재미난 것이 있군요.</font><br />
<br />
42:                 <font color="#9a1900">// 화일의 입출력을 위해 연 fis 과 fos 에서 채널을 얻어 냅니다.</font><br />
<br />
43:                 FileChannel fic = fis.<font color="#000000">getChannel</font>();<br />
<br />
44:                 FileChannel foc = fos.<font color="#000000">getChannel</font>();<br />
<br />
45: <br />
<br />
46:                 <font color="#9a1900">// #### 2</font><br />
<br />
47:                 <font color="#9a1900">// 이것은 NIO를 쓰기 위해서 Buffer을 하나 만들죠.</font><br />
<br />
48:                 <font color="#9a1900">// 재미난것은 Buffer은.. 생성자를 쓰지 않는군요.</font><br />
<br />
49:                 <font color="#9a1900">// 나중에 한번 다시 확인해 보도록 하죠.</font><br />
<br />
50:                 ByteBuffer buf = ByteBuffer.<font color="#000000">allocate</font>( <font color="#cc33cc">1024</font> );<br />
<br />
51:                 <br />
<br />
52: <br />
<br />
53:                 <font color="#9a1900">// 무한 루프를 돕니다.</font><br />
<br />
54:                 <font color="#0000ff">while</font>(true) <font color="#000000">{</font><br />
<br />
55:                         <font color="#9a1900">// #### 3</font><br />
<br />
56:                         <font color="#9a1900">// 여기서는 fic 즉 입력 채널에서 데이터를 읽어 들입니다.</font><br />
<br />
57:                         <font color="#9a1900">// 역시 재미난것은 ByteBuffer만 써 주었다는 것이지요.</font><br />
<br />
58:                         <font color="#33cc00">int</font> ret = fic.<font color="#000000">read</font>(buf);<br />
<br />
59:                         <br />
<br />
60:                         <font color="#9a1900">// 여기서 ret가 -1이 반환되면 화일의 끝이 됩니다.</font><br />
<br />
61:                         <font color="#9a1900">// 즉 -1이 아니면 화일을 복사 해야 겠죠?</font><br />
<br />
62:                         <font color="#0000ff">if</font> ( ret != -<font color="#cc33cc">1</font> ) <font color="#000000">{</font><br />
<br />
63:                                 <font color="#9a1900">// #### 4</font><br />
<br />
64:                                 <font color="#9a1900">// 버퍼를 플립하고 ( 나중에 설명 들어 갑니다. )</font><br />
<br />
65:                                 <font color="#9a1900">// 출력채널에다가 Buffer를 써 줍니다.</font><br />
<br />
66:                                 <font color="#9a1900">// 그리고 버퍼를 클리어 시키죠.</font><br />
<br />
67:                                 buf.<font color="#000000">flip</font>() ;<br />
<br />
68:                                 foc.<font color="#000000">write</font>(buf);<br />
<br />
69:                                 buf.<font color="#000000">clear</font>() ;<br />
<br />
70:                         <font color="#000000">}</font><br />
<br />
71:                         <font color="#0000ff">else</font> <font color="#0000ff">break</font>;        <font color="#9a1900">// -1(화일끝)이 나오면 루프를 멈춥니다.</font><br />
<br />
72:                 <font color="#000000">}</font><br />
<br />
73:                 <br />
<br />
74:         <font color="#000000">}</font><br />
<br />
75:         <br />
<br />
76: <font color="#000000">}</font></tt><br />
<br />
</pre><br />
<br />
======================================================================<br />
<br />
<br />
<br />
<br />
<br />
자 그림 위에서 체크 ( #1, #2 ... ) 되어 있는 몇 부분을 확인해 보겠습니다.<br />
<br />
<br />
<br />
####### 1<br />
<br />
// #### 1<br />
<br />
// 여기서 재미난 것이 있군요.<br />
<br />
// 화일의 입출력을 위해 연 fis 과 fos 에서 채널을 얻어 냅니다.<br />
<br />
FileChannel fic = fis.getChannel();<br />
<br />
FileChannel foc = fos.getChannel();<br />
<br />
<br />
<br />
바로 스트림에서 채널을 얻어 내는 부분입니다.<br />
<br />
<br />
<br />
사용법은 다음과 같네요<br />
<br />
<br />
<br />
FileChannel fic = fis.getChannel();<br />
<br />
<br />
<br />
여기 같은 경우는 FileInputStream이니깐 당연히 FileChannel 로 받아야 합니다.<br />
<br />
<br />
<br />
채널은 다음과 같은 종류가 있습니다.<br />
<br />
DatagramChannel, FileChannel, Pipe.SinkChannel, Pipe.SourceChannel, SelectableChannel, <br />
<br />
<br />
<br />
SocketChannel 등<br />
<br />
Java 1.4.2 API 문서에서 참고한것입니다.<br />
<br />
<br />
<br />
각각 맞는 채널을 사용하면 될 것 같습니다.<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
####### 2<br />
<br />
// #### 2<br />
<br />
// 이것은 NIO를 쓰기 위해서 Buffer을 하나 만들죠.<br />
<br />
// 재미난것은 Buffer은.. 생성자를 쓰지 않는군요.<br />
<br />
// 나중에 한번 다시 확인해 보도록 하죠.<br />
<br />
ByteBuffer buf = ByteBuffer.allocate( 1024 );<br />
<br />
<br />
<br />
바로 Buffer 부분입니다. NIO에서는 입출력을 위해서 Buffer를 Channel에 쓰게 됩니다.<br />
<br />
<br />
<br />
제가 생각하기로 이 버퍼는 데이터를 저장하기 위한 공간입니다.<br />
<br />
일반적인 io에서는 데이터를 넘기면(읽거나 쓰거나) Block 되면서 처리하게 됩니다.<br />
<br />
하지만 NIO에서는 Block 되지 않으므로 호출한 즉시 처리가 되지 않는다면<br />
<br />
데이터를 어디엔가 저장했다가 써야 하기 때문에 Buffer이 필요한것으로 생각됩니다.<br />
<br />
<br />
<br />
재미난것은 보통과 다르게 Buffer은 생성자를 쓰지 않습니다.<br />
<br />
위의 소스를 보면 다음과 같이 사용했습니다.<br />
<br />
<br />
<br />
ByteBuffer buf = ByteBuffer.allocate( 1024 );<br />
<br />
<br />
<br />
바로 allocate를 사용하여 buf라는 이름으로 메모리를 할당하게 됩니다.<br />
<br />
( 마치 C에서 malloc(sizeof(byte) * 1024 ) 하는것과 같은것 같군요 ^^ )<br />
<br />
<br />
<br />
그럼 ByteBuffer의 원래 소스의 일부를 한번 확인해 보겠습니다.<br />
<br />
====================================================================================<br />
<br />
    ByteBuffer(int mark, int pos, int lim, int cap,	// package-private<br />
<br />
		 byte[] hb, int offset)<br />
<br />
    {<br />
<br />
	super(mark, pos, lim, cap);<br />
<br />
	this.hb = hb;<br />
<br />
	this.offset = offset;<br />
<br />
    }<br />
<br />
====================================================================================<br />
<br />
보다시피 생성자가 package-private 로 설정이 되어 있군요.<br />
<br />
그래서 new를 이용해서<br />
<br />
ByteBuffer buf = new ByteBuffer(1024);<br />
<br />
이런식으로 생성할수가 없게 되어 있습니다.<br />
<br />
( 이렇게 생성자를 private로 만든것은 Singleton 패턴에도 존재하죠 )<br />
<br />
( 궁금하신 분은 Performance 쪽을 확인해 주십시오. ^^ )<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
####### 3<br />
<br />
// #### 3<br />
<br />
// 여기서는 fic 즉 입력 채널에서 데이터를 읽어 들입니다.<br />
<br />
// 역시 재미난것은 ByteBuffer만 써 주었다는 것이지요.<br />
<br />
int ret = fic.read(buf);<br />
<br />
<br />
<br />
이 부분은 채널에서 데이터를 읽어 오는 부분입니다.<br />
<br />
<br />
<br />
보통의 IO에서는 다음과 같은 메소드로 데이터를 읽어 들입니다.<br />
<br />
1. read()<br />
<br />
2. read(byte[] b)<br />
<br />
3. read(byte[] b, int off, int len)<br />
<br />
<br />
<br />
하지만 NIO는 다음과 같은 메소드를 사용합니다.<br />
<br />
1. abstract  int read(ByteBuffer dst) <br />
<br />
2.          long read(ByteBuffer[] dsts)  <br />
<br />
3. abstract long read(ByteBuffer[] dsts, int offset, int length)<br />
<br />
4. abstract  int read(ByteBuffer dst, long position) <br />
<br />
<br />
<br />
역시나 몇개가 되죠.<br />
<br />
하지만 여기서 중요한것은 바로 모든것이 ByteBuffer을 사용한다는 것입니다.<br />
<br />
( 물론 다른 형태(Char, Float등)에 대하여는 거기에 맞는것을 사용해야 할것입니다. )<br />
<br />
<br />
<br />
<br />
<br />
채널에 대하여 하나 더 알아두고 가야 할것이 있습니다.<br />
<br />
FileChannel 클래스를 확인해 보면...<br />
<br />
read() 메소드 뿐만 아니라, write 메소드가 있습니다.<br />
<br />
즉, 채널로 입출력을 동시에 할 수 있게 됩니다.<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
####### 4<br />
<br />
// #### 4<br />
<br />
// 버퍼를 플립하고 ( 나중에 설명 들어 갑니다. )<br />
<br />
// 출력채널에다가 Buffer를 써 줍니다.<br />
<br />
// 그리고 버퍼를 클리어 시키죠.<br />
<br />
buf.flip() ;<br />
<br />
foc.write(buf);<br />
<br />
buf.clear() ;<br />
<br />
<br />
<br />
<br />
<br />
이부분은 데이터를 복사하는 부분입니다.<br />
<br />
화일의 끝 ( API에 따르면 End-of-Stream ) 이면 -1을 반환하게 됩니다.<br />
<br />
<br />
<br />
<br />
<br />
이 다음에 나오는 부분이 가장 설명하기가 까다로운 부분입니다.<br />
<br />
buf.flip() 과 buf.clear() 부분인데.<br />
<br />
<br />
<br />
<br />
<br />
buf는 데이터를 저장하고 있습니다.<br />
<br />
버퍼의 끝 ( 데이터 저장할 마지막 자리, 배열처럼 설명하면 buf[1023] )이 있고<br />
<br />
그리고 데이터가 들어 있는 장소의 끝이 있을것입니다.<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
배열은 아니지만 배열 처럼 설명을 드리겠습니다.<br />
<br />
buf는 10개의 방이 있습니다.<br />
<br />
그리고 0,1,2,3,4,5 에는 데이터가 들어 있습니다.<br />
<br />
<br />
<br />
그렇다면 buf의 끝은 9번 방이 될것이고<br />
<br />
buf 데이터의 끝은 5가 될것입니다.<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
buf.flip() 는 buf의 데이터끝을 조정합니다.<br />
<br />
처음 buf가 만들어지면 실제 데이터의 끝이 어딘지 모르니깐<br />
<br />
맨 마지막을 가리키고 있을것입니다.<br />
<br />
그리고 실제 데이터가 들어 오면, 입출력 할곳을 정한 포인터가<br />
<br />
한칸씩 이동하면서 데이터를 읽거나 쓰게 될겁니다.<br />
<br />
<br />
<br />
하지만 읽은 데이터를 사용하려고 한다면,<br />
<br />
입출력을 정하는 포인터는 제일 앞으로 이동해야 할것이고,<br />
<br />
데이터의 마지막에 어디인지를 가르키는 포인터가 데이터의 끝 지점에 위치 해야 할것입니다.<br />
<br />
<br />
<br />
<br />
<br />
그렇기 때문에 buf.flip()를 사용하여 buf에서 데이터의 끝을 가르키는 포인터를<br />
<br />
( 현재는 제일 버퍼의 마지막에 있을것입니다. ) buf 실제 데이터의 마지막으로 옮깁니다.<br />
<br />
그리고 파일을 입출력할 장소를 나타내는 포인터를 제일 앞으로 옮깁니다.<br />
<br />
<br />
<br />
그런뒤에 foc 채널에다가 데이터를 씁니다.<br />
<br />
<br />
<br />
그뒤에 buf.clear()을 사용하여 버퍼를 완전히 비워 버립니다.<br />
<br />
( buf의 초기화 )<br />
<br />
물론 데이터의 입출력 포인터 역시 제일 앞칸으로 이동하고,<br />
<br />
buf의 실제 데이터의 끝을 나타내는 포인터 역시 제일 마지막칸으로 이동합니다.<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
예제가 간단하기는 하지만 어떤 방식으로 NIO를 사용하는지 이해가 될것이라 믿습니다.<br />
<br />
<br />
<br />
마지막으로 중요한것만 정리 하면.<br />
<br />
<br />
<br />
1. Stream에서 Channel을 얻는다.<br />
<br />
2. Buffer을 만들어서 Channel로 입출력을 한다.<br />
<br />
3. ByteBuffer.flip() 또는 ByteBuffer.clear() 가 동작하는것을 알아야한다.<br />
<br />
<br />
출처 : http://ggaman.com/tt/456<br />
</pre>			 ]]> 
		</description>
		<category>java</category>

		<comments>http://spore.egloos.com/4169925#comments</comments>
		<pubDate>Fri, 19 Jun 2009 21:41:20 GMT</pubDate>
		<dc:creator>vimming</dc:creator>
	</item>
	<item>
		<title><![CDATA[ 자바 파일복사 코드와 성능 2 :: Java File Copy Code & Perfomance Issue. part 2 ]]> </title>
		<link>http://spore.egloos.com/4167316</link>
		<guid>http://spore.egloos.com/4167316</guid>
		<description>
			<![CDATA[ 
  <div class="titleWrap">            <h3><a href="http://www.yunsobi.com/blog/406" class="entry-title" rel="bookmark" title="자바 파일복사 코드와 성능 2 :: Java File Copy Code &amp; Perfomance Issue. part 2">자바 파일복사 코드와 성능 2 :: Java File Copy Code &amp; Perfomance Issue. part 2</a>            </h3>		  <div class="author">		 <a href="http://www.yunsobi.com/blog/category/JAVA" class="categoryBtn">JAVA</a>		 <span class="date">2008/07/13 21:21</span>		 <span class="ownerBtn">by 서비<br />
<br />
</span></div></div><!-- titleWrap close -->          															          <div class="article entry-content" id="article_1"> <p><a href="http://www.yunsobi.com/blog/399" target="_blank">지난 포스트</a>를 통해 자바로 파일을 복사하는 몇가지 방법을 알아보았다.<br />
이번시간에는 각 코드의 성능을 간단히 확인해 보고자 한다. <br />
<br />
</p><pre class="prettyprint"><code><span class="pln"><br />
</span><span class="com">/*<br />
&nbsp;* author 신윤섭<br />
&nbsp;*/</span><span class="pln"><br />
</span><span class="kwd">package</span><span class="pln"> filecopy</span><span class="pun">;</span><span class="pln"><br />
</span></code><p><span class="kwd">import</span><span class="pln"> java</span><span class="pun">.</span><span class="pln">io</span><span class="pun">.</span><span class="typ">File</span><span class="pun">;</span><span class="pln"><br />
</span><span class="kwd">import</span><span class="pln"> java</span><span class="pun">.</span><span class="pln">io</span><span class="pun">.</span><span class="typ">FileInputStream</span><span class="pun">;</span><span class="pln"><br />
</span><span class="kwd">import</span><span class="pln"> java</span><span class="pun">.</span><span class="pln">io</span><span class="pun">.</span><span class="typ">FileOutputStream</span><span class="pun">;</span><span class="pln"><br />
</span><span class="kwd">import</span><span class="pln"> java</span><span class="pun">.</span><span class="pln">io</span><span class="pun">.</span><span class="typ">IOException</span><span class="pun">;</span></p><span class="pln"><br />
</span><p><span class="com">/**<br />
&nbsp;* Stream을 이용한 파일복사 코드 스니핏<br />
&nbsp;* @author 신윤섭<br />
&nbsp;*/</span><span class="pln"><br />
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">StreamCopy</span><span class="pln"> </span><span class="pun">{</span></p><span class="pln"><br />
</span><p><span class="pln"> </span><span class="com">/**<br />
&nbsp; * source에서 target으로의 파일 복사<br />
&nbsp; * @param source<br />
&nbsp; * @param target<br />
&nbsp; */</span><span class="pln"><br />
&nbsp;</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> copy</span><span class="pun">(</span><span class="typ">String</span><span class="pln"> source</span><span class="pun">,</span><span class="pln"> </span><span class="typ">String</span><span class="pln"> target</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br />
&nbsp; </span><span class="com">//복사 대상이 되는 파일 생성 </span><span class="pln"><br />
&nbsp; </span><span class="typ">File</span><span class="pln"> sourceFile </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">File</span><span class="pun">(</span><span class="pln"> source </span><span class="pun">);</span><span class="pln"><br />
&nbsp; <br />
&nbsp; </span><span class="com">//스트림 선언 </span><span class="pln"><br />
&nbsp; </span><span class="typ">FileInputStream</span><span class="pln"> inputStream </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln"><br />
&nbsp; </span><span class="typ">FileOutputStream</span><span class="pln"> outputStream </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln"><br />
&nbsp; <br />
&nbsp; </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="com">//스트림 생성</span><span class="pln"><br />
&nbsp; &nbsp;inputStream </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">FileInputStream</span><span class="pun">(</span><span class="pln">sourceFile</span><span class="pun">);</span><span class="pln"><br />
&nbsp; &nbsp;outputStream </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">FileOutputStream</span><span class="pun">(</span><span class="pln">target</span><span class="pun">);</span><span class="pln"><br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;</span><span class="kwd">int</span><span class="pln"> bytesRead </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="com">//인풋스트림을 아웃픗스트림에 쓰기</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="kwd">byte</span><span class="pun">[]</span><span class="pln"> buffer </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="kwd">byte</span><span class="pun">[</span><span class="lit">1024</span><span class="pun">];</span><span class="pln"> &nbsp; <br />
&nbsp; &nbsp;</span><span class="kwd">while</span><span class="pln"> </span><span class="pun">((</span><span class="pln">bytesRead </span><span class="pun">=</span><span class="pln"> inputStream</span><span class="pun">.</span><span class="pln">read</span><span class="pun">(</span><span class="pln">buffer</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1024</span><span class="pun">))</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br />
&nbsp; &nbsp; outputStream</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">buffer</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> bytesRead</span><span class="pun">);</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="pun">}</span><span class="pln"><br />
&nbsp; &nbsp;<br />
&nbsp; </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Exception</span><span class="pln"> e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br />
&nbsp; &nbsp;e</span><span class="pun">.</span><span class="pln">printStackTrace</span><span class="pun">();</span><span class="pln"><br />
&nbsp; </span><span class="pun">}</span><span class="kwd">finally</span><span class="pun">{</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="com">//자원 해제</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="kwd">try</span><span class="pun">{</span><span class="pln"><br />
&nbsp; &nbsp; outputStream</span><span class="pun">.</span><span class="pln">close</span><span class="pun">();</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="pun">}</span><span class="kwd">catch</span><span class="pun">(</span><span class="typ">IOException</span><span class="pln"> ioe</span><span class="pun">){}</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="kwd">try</span><span class="pun">{</span><span class="pln"><br />
&nbsp; &nbsp; inputStream</span><span class="pun">.</span><span class="pln">close</span><span class="pun">();</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="pun">}</span><span class="kwd">catch</span><span class="pun">(</span><span class="typ">IOException</span><span class="pln"> ioe</span><span class="pun">){}</span><span class="pln"><br />
&nbsp; </span><span class="pun">}</span></p><span class="pln"><br />
</span><p><span class="pln"> </span><span class="pun">}</span><span class="pln"><br />
</span><span class="pun">}</span><span class="pln"><br />
</span></p></pre><br />
<pre class="prettyprint"><code><span class="pln"><br />
</span><span class="com">/*<br />
&nbsp;* author 신윤섭<br />
&nbsp;*/</span><span class="pln"><br />
</span><span class="kwd">package</span><span class="pln"> filecopy</span><span class="pun">;</span><span class="pln"><br />
</span></code><p><span class="kwd">import</span><span class="pln"> java</span><span class="pun">.</span><span class="pln">io</span><span class="pun">.</span><span class="typ">File</span><span class="pun">;</span><span class="pln"><br />
</span><span class="kwd">import</span><span class="pln"> java</span><span class="pun">.</span><span class="pln">io</span><span class="pun">.</span><span class="typ">BufferedInputStream</span><span class="pun">;</span><span class="pln"><br />
</span><span class="kwd">import</span><span class="pln"> java</span><span class="pun">.</span><span class="pln">io</span><span class="pun">.</span><span class="typ">BufferedOutputStream</span><span class="pun">;</span><span class="pln"><br />
</span><span class="kwd">import</span><span class="pln"> java</span><span class="pun">.</span><span class="pln">io</span><span class="pun">.</span><span class="typ">FileInputStream</span><span class="pun">;</span><span class="pln"><br />
</span><span class="kwd">import</span><span class="pln"> java</span><span class="pun">.</span><span class="pln">io</span><span class="pun">.</span><span class="typ">FileOutputStream</span><span class="pun">;</span><span class="pln"><br />
</span><span class="kwd">import</span><span class="pln"> java</span><span class="pun">.</span><span class="pln">io</span><span class="pun">.</span><span class="typ">IOException</span><span class="pun">;</span></p><span class="pln"><br />
</span><p><span class="com">/**<br />
&nbsp;* Buffer를 이용한 파일복사 코드 스니핏<br />
&nbsp;* @author 신윤섭<br />
&nbsp;*/</span><span class="pln"><br />
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">BufferCopy</span><span class="pln"> </span><span class="pun">{</span></p><span class="pln"><br />
</span><p><span class="pln"> </span><span class="com">/**<br />
&nbsp; * source에서 target으로의 파일 복사<br />
&nbsp; * @param source<br />
&nbsp; * @param target<br />
&nbsp; */</span><span class="pln"><br />
&nbsp;</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> copy</span><span class="pun">(</span><span class="typ">String</span><span class="pln"> source</span><span class="pun">,</span><span class="pln"> </span><span class="typ">String</span><span class="pln"> target</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br />
&nbsp; </span><span class="com">//복사 대상이 되는 파일 생성 </span><span class="pln"><br />
&nbsp; </span><span class="typ">File</span><span class="pln"> sourceFile </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">File</span><span class="pun">(</span><span class="pln"> source </span><span class="pun">);</span><span class="pln"><br />
&nbsp; <br />
&nbsp; </span><span class="com">//스트림, 버퍼 선언</span><span class="pln"><br />
&nbsp; </span><span class="typ">FileInputStream</span><span class="pln"> inputStream </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln"><br />
&nbsp; </span><span class="typ">FileOutputStream</span><span class="pln"> outputStream </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln"><br />
&nbsp; </span><span class="typ">BufferedInputStream</span><span class="pln"> bin </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln"><br />
&nbsp; </span><span class="typ">BufferedOutputStream</span><span class="pln"> bout </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln"><br />
&nbsp; <br />
&nbsp; </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="com">//스트림 생성</span><span class="pln"><br />
&nbsp; &nbsp;inputStream </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">FileInputStream</span><span class="pun">(</span><span class="pln">sourceFile</span><span class="pun">);</span><span class="pln"><br />
&nbsp; &nbsp;outputStream </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">FileOutputStream</span><span class="pun">(</span><span class="pln">target</span><span class="pun">);</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="com">//버퍼 생성</span><span class="pln"><br />
&nbsp; &nbsp;bin </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">BufferedInputStream</span><span class="pun">(</span><span class="pln">inputStream</span><span class="pun">);</span><span class="pln"><br />
&nbsp; &nbsp;bout </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">BufferedOutputStream</span><span class="pun">(</span><span class="pln">outputStream</span><span class="pun">);</span><span class="pln"><br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;</span><span class="com">//버퍼를 통한 스트림 쓰기</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="kwd">int</span><span class="pln"> bytesRead </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="kwd">byte</span><span class="pun">[]</span><span class="pln"> buffer </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="kwd">byte</span><span class="pun">[</span><span class="lit">1024</span><span class="pun">];</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="kwd">while</span><span class="pln"> </span><span class="pun">((</span><span class="pln">bytesRead </span><span class="pun">=</span><span class="pln"> bin</span><span class="pun">.</span><span class="pln">read</span><span class="pun">(</span><span class="pln">buffer</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1024</span><span class="pun">))</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br />
&nbsp; &nbsp; bout</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">buffer</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> bytesRead</span><span class="pun">);</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="pun">}</span></p><span class="pln"><br />
</span><p><span class="pln"> &nbsp;</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Exception</span><span class="pln"> e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br />
&nbsp; &nbsp;e</span><span class="pun">.</span><span class="pln">printStackTrace</span><span class="pun">();</span><span class="pln"><br />
&nbsp; </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">finally</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="com">//자원 해제</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="kwd">try</span><span class="pun">{</span><span class="pln"><br />
&nbsp; &nbsp; outputStream</span><span class="pun">.</span><span class="pln">close</span><span class="pun">();</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="pun">}</span><span class="kwd">catch</span><span class="pun">(</span><span class="typ">IOException</span><span class="pln"> ioe</span><span class="pun">){}</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="kwd">try</span><span class="pun">{</span><span class="pln"><br />
&nbsp; &nbsp; inputStream</span><span class="pun">.</span><span class="pln">close</span><span class="pun">();</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="pun">}</span><span class="kwd">catch</span><span class="pun">(</span><span class="typ">IOException</span><span class="pln"> ioe</span><span class="pun">){}</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="kwd">try</span><span class="pun">{</span><span class="pln"><br />
&nbsp; &nbsp; bin</span><span class="pun">.</span><span class="pln">close</span><span class="pun">();</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="pun">}</span><span class="kwd">catch</span><span class="pun">(</span><span class="typ">IOException</span><span class="pln"> ioe</span><span class="pun">){}</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="kwd">try</span><span class="pun">{</span><span class="pln"><br />
&nbsp; &nbsp; bout</span><span class="pun">.</span><span class="pln">close</span><span class="pun">();</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="pun">}</span><span class="kwd">catch</span><span class="pun">(</span><span class="typ">IOException</span><span class="pln"> ioe</span><span class="pun">){}</span><span class="pln"><br />
&nbsp; </span><span class="pun">}</span><span class="pln"><br />
&nbsp;</span><span class="pun">}</span><span class="pln"><br />
</span><span class="pun">}</span><span class="pln"><br />
</span></p></pre><br />
<pre class="prettyprint"><code><span class="pln"><br />
</span><span class="com">/*<br />
&nbsp;* author 신윤섭<br />
&nbsp;*/</span><span class="pln"><br />
</span><span class="kwd">package</span><span class="pln"> filecopy</span><span class="pun">;</span><span class="pln"><br />
</span></code><p><span class="kwd">import</span><span class="pln"> java</span><span class="pun">.</span><span class="pln">io</span><span class="pun">.</span><span class="typ">File</span><span class="pun">;</span><span class="pln"><br />
</span><span class="kwd">import</span><span class="pln"> java</span><span class="pun">.</span><span class="pln">io</span><span class="pun">.</span><span class="typ">FileInputStream</span><span class="pun">;</span><span class="pln"><br />
</span><span class="kwd">import</span><span class="pln"> java</span><span class="pun">.</span><span class="pln">io</span><span class="pun">.</span><span class="typ">FileOutputStream</span><span class="pun">;</span><span class="pln"><br />
</span><span class="kwd">import</span><span class="pln"> java</span><span class="pun">.</span><span class="pln">nio</span><span class="pun">.</span><span class="pln">channels</span><span class="pun">.</span><span class="typ">FileChannel</span><span class="pun">;</span><span class="pln"><br />
</span><span class="kwd">import</span><span class="pln"> java</span><span class="pun">.</span><span class="pln">io</span><span class="pun">.</span><span class="typ">IOException</span><span class="pun">;</span></p><span class="pln"><br />
</span><p><span class="com">/**<br />
&nbsp;* NIO Channel을 이용한 파일복사 코드 스니핏<br />
&nbsp;* @author 신윤섭<br />
&nbsp;*/</span><span class="pln"><br />
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">ChannelCopy</span><span class="pln"> </span><span class="pun">{</span></p><span class="pln"><br />
</span><p><span class="pln"> </span><span class="com">/**<br />
&nbsp; * source에서 target으로의 파일 복사<br />
&nbsp; * @param source 복사할 파일명을 포함한 절대 경로 <br />
&nbsp; * @param target 복사될 파일명을 포함한 절대경로<br />
&nbsp; */</span><span class="pln"><br />
&nbsp;</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> copy</span><span class="pun">(</span><span class="typ">String</span><span class="pln"> source</span><span class="pun">,</span><span class="pln"> </span><span class="typ">String</span><span class="pln"> target</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br />
&nbsp; </span><span class="com">//복사 대상이 되는 파일 생성 </span><span class="pln"><br />
&nbsp; </span><span class="typ">File</span><span class="pln"> sourceFile </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">File</span><span class="pun">(</span><span class="pln"> source </span><span class="pun">);</span></p><span class="pln"><br />
</span><p><span class="pln"> &nbsp;</span><span class="com">//스트림, 채널 선언</span><span class="pln"><br />
&nbsp; </span><span class="typ">FileInputStream</span><span class="pln"> inputStream </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln"><br />
&nbsp; </span><span class="typ">FileOutputStream</span><span class="pln"> outputStream </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln"><br />
&nbsp; </span><span class="typ">FileChannel</span><span class="pln"> fcin </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln"><br />
&nbsp; </span><span class="typ">FileChannel</span><span class="pln"> fcout </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span></p><span class="pln"><br />
</span><p><span class="pln"> &nbsp;</span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="com">//스트림 생성</span><span class="pln"><br />
&nbsp; &nbsp;inputStream </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">FileInputStream</span><span class="pun">(</span><span class="pln">sourceFile</span><span class="pun">);</span><span class="pln"><br />
&nbsp; &nbsp;outputStream </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">FileOutputStream</span><span class="pun">(</span><span class="pln">target</span><span class="pun">);</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="com">//채널 생성</span><span class="pln"><br />
&nbsp; &nbsp;fcin </span><span class="pun">=</span><span class="pln"> inputStream</span><span class="pun">.</span><span class="pln">getChannel</span><span class="pun">();</span><span class="pln"><br />
&nbsp; &nbsp;fcout </span><span class="pun">=</span><span class="pln"> outputStream</span><span class="pun">.</span><span class="pln">getChannel</span><span class="pun">();</span><span class="pln"><br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;</span><span class="com">//채널을 통한 스트림 전송</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="kwd">long</span><span class="pln"> size </span><span class="pun">=</span><span class="pln"> fcin</span><span class="pun">.</span><span class="pln">size</span><span class="pun">();</span><span class="pln"><br />
&nbsp; &nbsp;fcin</span><span class="pun">.</span><span class="pln">transferTo</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">,</span><span class="pln"> fcout</span><span class="pun">);</span></p><span class="pln"><br />
</span><p><span class="pln"> &nbsp;</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Exception</span><span class="pln"> e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br />
&nbsp; &nbsp;e</span><span class="pun">.</span><span class="pln">printStackTrace</span><span class="pun">();</span><span class="pln"><br />
&nbsp; </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">finally</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="com">//자원 해제</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="kwd">try</span><span class="pun">{</span><span class="pln"><br />
&nbsp; &nbsp; fcout</span><span class="pun">.</span><span class="pln">close</span><span class="pun">();</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="pun">}</span><span class="kwd">catch</span><span class="pun">(</span><span class="typ">IOException</span><span class="pln"> ioe</span><span class="pun">){}</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="kwd">try</span><span class="pun">{</span><span class="pln"><br />
&nbsp; &nbsp; fcin</span><span class="pun">.</span><span class="pln">close</span><span class="pun">();</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="pun">}</span><span class="kwd">catch</span><span class="pun">(</span><span class="typ">IOException</span><span class="pln"> ioe</span><span class="pun">){}</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="kwd">try</span><span class="pun">{</span><span class="pln"><br />
&nbsp; &nbsp; outputStream</span><span class="pun">.</span><span class="pln">close</span><span class="pun">();</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="pun">}</span><span class="kwd">catch</span><span class="pun">(</span><span class="typ">IOException</span><span class="pln"> ioe</span><span class="pun">){}</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="kwd">try</span><span class="pun">{</span><span class="pln"><br />
&nbsp; &nbsp; inputStream</span><span class="pun">.</span><span class="pln">close</span><span class="pun">();</span><span class="pln"><br />
&nbsp; &nbsp;</span><span class="pun">}</span><span class="kwd">catch</span><span class="pun">(</span><span class="typ">IOException</span><span class="pln"> ioe</span><span class="pun">){}</span><span class="pln"><br />
&nbsp; </span><span class="pun">}</span><span class="pln"><br />
&nbsp;</span><span class="pun">}</span><span class="pln"><br />
</span><span class="pun">}</span><span class="pln"><br />
</span></p></pre><br />
<br />
이상의 샘플코드를 이용하여 700Mbytes 짜리 파일을 5번 복사하여 그 시간을 측정해 본 결과는 아래와 같다.<br />
테스트는 Win XP Pro sp3, Intel Core2 Duo 2GHz, 2Gbytes, 5400rpm의 노트북용 HDD 에서 JDK 1.6.0_06<br />
을 이용하여 이루어졌다.<br />
<br />
결과는 아래와 같다.<br />
<br />
<div class="imageblock center" style="text-align: center; clear: both;"><img src="http://www.yunsobi.com/blog/attach/1/1123986205.png" alt="스트림을 이용한 파일 카피" width="616" height="134"><p class="cap1">Stream을 이용한 파일 복사</p></div><br />
<div class="imageblock center" style="text-align: center; clear: both;"><img src="http://www.yunsobi.com/blog/attach/1/1311194150.png" alt="버퍼를 이용한 파일 카피" width="616" height="134"><p class="cap1">Buffer를 이용한 파일 복사</p></div><br />
<div class="imageblock center" style="text-align: center; clear: both;"><img src="http://www.yunsobi.com/blog/attach/1/1394099584.png" alt="채널을 이용한 파일 카피" width="616" height="134"><p class="cap1">Channel을 이용한 파일 복사</p></div><br />
<br />
프로파일러를 이용하여 측정한 값이기 때문에 프로파일러의 처리량 만큼의 차이는 있겠지만 상대적 성능 비교<br />
에는 문제가 없으리라 생각 된다. <br />
실측에서도 예상대로 Stream , Buffer, Channel 순으로 파일 복사 시간이 줄어들고 있음을 볼 수있다.<br />
<br />
이번에는 조금 더 들여다 보기로 하자. 700m짜리 파일을 한번 복사하는데 어떤 클래스와 메소들이 참여하고 <br />
있는지, 그리고 메소드가 몇번이나 호출되고 있는지 확인 해 보는것도 재미있을 것이다.<br />
<br />
<div class="imageblock center" style="text-align: center; clear: both;"><img src="http://www.yunsobi.com/blog/attach/1/1090601110.png" alt="스트림이용" width="636" height="649"><p class="cap1">FileInputStream.read()실행에 대부분의 시간을 소비하고 있다.</p></div><br />
스트림을 이용한 파일복사이다. FileInputStream.read()메소드가 71만여번 호출되고있으며 실행시간의 대부분을 <br />
이 메소드를 실행 하는데 소비하고 있음을 알 수 있다.<br />
<br />
<div class="imageblock center" style="text-align: center; clear: both;"><img src="http://www.yunsobi.com/blog/attach/1/1041926112.png" alt="버퍼이용" width="636" height="649"><p class="cap1">Stream보다는 나아졌다고는 하나 역시 read()메소드가 대부분의 실행시간을 소비하고 있다.</p></div><br />
Buffer를 이용한 방법. 위의 Stream을 이용한 방법에 비해 수행시간이 약간은 줄어들었지만 이는 Buffer를 활용<br />
함으로써 FileOutputStream.write() 수행시간을 줄인데 따른 성능 향상이며, FileInputStream.read()메소드는<br />
약 9만번 호출되고 있다.<br />
<br />
<div class="imageblock center" style="text-align: center; clear: both;"><img src="http://www.yunsobi.com/blog/attach/1/1327109749.png" alt="채널이용" width="636" height="649"><p class="cap1">위 두 방식과는 확연히 다른 동작 성향을 보여주고 있다.</p></div><br />
마지막으로 채널을 이용한 파일복사의 경우 위 두 경우와 비교하여 호출되는 메소드나 호출횟수등 전혀 다른 <br />
동작 성향을 보이고 있다. read 도 하지 않은채 FileDispatcher.write() 메소드를 단 한번 호출 하는것으로 파일<br />
복사를 끝내고 있다. 이 FileDispatcher.write() 하부구조에서는 OS의 네이티브IO를 호출하고 있으리라 미루어<br />
짐작할 수 있다.<br />
<br />
이상으로 파일복사(스트림전송)의 세가지 방식과 그 성능에 대해 간략하게 알아보았다.<br />
위 실험 결과는 크기가 비교적 큰 파일의 복사에서 나타나는 성향며, 다수의 작은 크기의 파일을 복사한다면<br />
그 결과가 달라질 수도 있음을 밝혀둔다.<br />
<br />
io작업이 필요한데 JDK 1.4 이상의 버전을 이용할 수 있다면 나은 성능을 보장하는 nio를 사용하지<br />
않을 이유가 없어보인다.            <div class="autosourcing-stub"><div style="padding-top: 5px;" align="center">&lt;출처 : <a href="http://www.yunsobi.com/" target="_blank">서비의 다락방</a>&nbsp;( http://www.yunsobi.com )&gt;<br />
<font color="#999999">-출처를 밝혀주신 당신은 아름다운 사람입니다.-</font></div></div></div>			 ]]> 
		</description>
		<category>java</category>

		<comments>http://spore.egloos.com/4167316#comments</comments>
		<pubDate>Tue, 16 Jun 2009 16:24:44 GMT</pubDate>
		<dc:creator>vimming</dc:creator>
	</item>
	<item>
		<title><![CDATA[ 자바 파일복사 코드와 성능 1. :: Java File Copy Code & Perfomance Issue. part 1 ]]> </title>
		<link>http://spore.egloos.com/4167313</link>
		<guid>http://spore.egloos.com/4167313</guid>
		<description>
			<![CDATA[ 
  <div class="titleWrap">            <h3><a href="http://www.yunsobi.com/blog/399" class="entry-title" rel="bookmark" title="자바 파일복사 코드와 성능 1. :: Java File Copy Code &amp; Perfomance Issue. part 1">자바 파일복사 코드와 성능 1. :: Java File Copy Code &amp; Perfomance Issue. part 1</a>            </h3>		  <div class="author">		 <a href="http://www.yunsobi.com/blog/category/JAVA" class="categoryBtn">JAVA</a>		 <span class="date">2008/07/13 00:05</span>		 <span class="ownerBtn">by 서비<br />
<br />
</span></div></div><!-- titleWrap close -->          															          <div class="article entry-content" id="article_1"> <p>자바로 파일을 복사할 수 있는 방법은 크게 3가지 정도가 있다.<br />
InputStream, OutputStream을 이용한 방법, Buffer를 이용한 방법, Channel을 이용한 방법이 그것이다.<br />
물론 Buffer를 이용하면서도 단순히 Stream에 Buffer 필터를 적용할 수도, MappedByteBuffer를 쓸 수도 있고<br />
Channel을 이용하면서도 inputChannel과 outputChannel을 이용하거나 transterTo()를 이용하는 등<br />
다양한 방법을 구사할 수 있다.<br />
여기서는 자바로 구현 할 수 있는 대표적인 파일 복사 코드를 살펴보고 각 코드간의 성능에 대한 이야기도 나눠<br />
보도록 하겠다.<br />
<br />
Java입문서등을 통하여 io (Input/Output)부분을 언급하며 나오는 개념이 Stream일 것이다. 스트림의 개념을<br />
설명하고 처음 접하는 코드는 아래와 유사할 것이다. 파일을 인풋스트림으로 읽어들인 후 그 길이만큼 아웃풋<br />
스트림에다 흘려보내는 방식으로 파일을 복사할 수 있다.<br />
<br />
</p><pre class="prettyprint"><code><span class="pln"><br />
</span><span class="typ">FileInputStream</span><span class="pln"> inputStream </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">FileInputStream</span><span class="pun">(</span><span class="pln">file</span><span class="pun">);</span><span class="pln"><br />
</span><span class="typ">FileOutputStream</span><span class="pln"> outputStream </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">FileOutputStream</span><span class="pun">(</span><span class="pln">saveFullPath</span><span class="pun">);</span><span class="pln"><br />
</span></code><p><span class="kwd">int</span><span class="pln"> bytesRead </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"><br />
</span><span class="kwd">byte</span><span class="pun">[]</span><span class="pln"> buffer </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="kwd">byte</span><span class="pun">[</span><span class="lit">1024</span><span class="pun">];</span><span class="pln"><br />
</span><span class="kwd">while</span><span class="pln"> </span><span class="pun">((</span><span class="pln">bytesRead </span><span class="pun">=</span><span class="pln"> inputStream</span><span class="pun">.</span><span class="pln">read</span><span class="pun">(</span><span class="pln">buffer</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1024</span><span class="pun">))</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br />
&nbsp; &nbsp; outputStream</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">buffer</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> bytesRead</span><span class="pun">);</span><span class="pln"><br />
</span><span class="pun">}</span></p><span class="pln"><br />
</span><p><span class="pln">outputStream</span><span class="pun">.</span><span class="pln">close</span><span class="pun">();</span><span class="pln"><br />
inputStream</span><span class="pun">.</span><span class="pln">close</span><span class="pun">();</span></p></pre><br />
* InputStream과 OutputStream을 이용한 기본적인 파일 복사 코드.<br />
위 코드는 기본적인 Stream의 사용법을 잘 보여주고 있지만 성능상에 심각한 문제를 안고 있다.<br />
파일크기(정확하게는 스트림의 길이)만큼 while문을 돌면서 끊임없이 읽고쓰기를 반복하고 있는데<br />
이는 CPU, DISK모두에게 부담을 주는 결과를 초래한다.<br />
<br />
이어지는 코드가 아마 가장 널리쓰이고 흔하게 볼수 있는 코드 일 것이다. 위에서 살펴본 Stream간의 데이터<br />
전송이 썩 좋은 성능을 내지 못하기 때문에, 스트림을 버퍼를 장착(wrapping, chainning)하여 입출력 횟수를 줄여<br />
성능 향상을 꾀하고 있다.<br />
<br />
<pre class="prettyprint"><code><span class="pln"><br />
</span><span class="typ">FileInputStream</span><span class="pln"> inputStream </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">FileInputStream</span><span class="pun">(</span><span class="pln">file</span><span class="pun">);</span><span class="pln"><br />
</span><span class="typ">FileOutputStream</span><span class="pln"> outputStream </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">FileOutputStream</span><span class="pun">(</span><span class="pln">saveFullPath</span><span class="pun">);</span><span class="pln"> <br />
</span></code><p><span class="typ">BufferedInputStream</span><span class="pln"> bin </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">BufferedInputStream</span><span class="pun">(</span><span class="pln">inputStream</span><span class="pun">);</span><span class="pln"><br />
</span><span class="typ">BufferedOutputStream</span><span class="pln"> bout </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">BufferedOutputStream</span><span class="pun">(</span><span class="pln">outputStream</span><span class="pun">);</span></p><span class="pln"><br />
</span><p><span class="kwd">int</span><span class="pln"> bytesRead </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"><br />
</span><span class="kwd">byte</span><span class="pun">[]</span><span class="pln"> buffer </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="kwd">byte</span><span class="pun">[</span><span class="lit">1024</span><span class="pun">];</span></p><span class="pln"><br />
</span><p><span class="kwd">while</span><span class="pln"> </span><span class="pun">((</span><span class="pln">bytesRead </span><span class="pun">=</span><span class="pln"> bin</span><span class="pun">.</span><span class="pln">read</span><span class="pun">(</span><span class="pln">buffer</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1024</span><span class="pun">))</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br />
&nbsp; &nbsp; bout</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">buffer</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> bytesRead</span><span class="pun">);</span><span class="pln"><br />
</span><span class="pun">}</span></p><span class="pln"><br />
</span><p><span class="pln">bout</span><span class="pun">.</span><span class="pln">close</span><span class="pun">();</span><span class="pln"><br />
bin</span><span class="pun">.</span><span class="pln">close</span><span class="pun">();</span><span class="pln"><br />
outputStream</span><span class="pun">.</span><span class="pln">close</span><span class="pun">();</span><span class="pln"><br />
inputStream</span><span class="pun">.</span><span class="pln">close</span><span class="pun">();</span><span class="pln"><br />
<br />
</span></p></pre><br />
* Stream에 Buffer Filter를 연결하여 성능을 향상.<br />
위와같은 방법으로 충분히 만족할만 한가? 그렇다고 할수도있고 아니라고 할수도 있다. 위 두 방식은 스트림으로<br />
데이터를 전송하는데 항상 cpu의 연산을 필요로 한다. 즉 스트림을 처리하는동안 cpu가 계속해서 명령을 처리<br />
해줘야 한다는것이다.(비록 cpu사용율은 얼마 안될지 모르지만.. )<br />
<br />
컴퓨터의 입장에서 본다면 IO는 상당히 느린 작업중의 하나이다. 이런 작업을 조금이라도 빨리 처리하기위해<br />
하드웨어 혹은 운영체제 수준에서 많은 기법들을 제공하고 있다.<br />
자바는 버전 1.4에 이르러서 기존 io와는 차별화된 nio(new io) 패키지가 추가되었는데 이 nio를 통하여 <br />
운영체제가 제공해 주는 향상된 io기능을 활용할 수 있게 되었다. 그 대표적인 것이 Channel과 Selector일 것이다.<br />
아래와 같은 코드는 JDK 1.4이상부터 사용 가능하며 transferTo() 메소드를 호출하면 내부적으로 OS의 네이티브IO<br />
기능을 활용하여 더욱 효율적인 스트림 전송이 가능하다.<br />
&nbsp;<br />
<pre class="prettyprint"><code><span class="pln"><br />
</span><span class="typ">FileInputStream</span><span class="pln"> inputStream </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">FileInputStream</span><span class="pun">(</span><span class="pln">file</span><span class="pun">);</span><span class="pln"> &nbsp; &nbsp; &nbsp; &nbsp; <br />
</span><span class="typ">FileOutputStream</span><span class="pln"> outputStream </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">FileOutputStream</span><span class="pun">(</span><span class="pln">saveFullPath</span><span class="pun">);</span><span class="pln"><br />
</span></code><p><span class="typ">FileChannel</span><span class="pln"> fcin </span><span class="pun">=</span><span class="pln"> &nbsp;inputStream</span><span class="pun">.</span><span class="pln">getChannel</span><span class="pun">();</span><span class="pln"><br />
</span><span class="typ">FileChannel</span><span class="pln"> fcout </span><span class="pun">=</span><span class="pln"> outputStream</span><span class="pun">.</span><span class="pln">getChannel</span><span class="pun">();</span></p><span class="pln"><br />
</span><p><span class="kwd">long</span><span class="pln"> size </span><span class="pun">=</span><span class="pln"> fcin</span><span class="pun">.</span><span class="pln">size</span><span class="pun">();</span><span class="pln"><br />
&nbsp; &nbsp; <br />
fcin</span><span class="pun">.</span><span class="pln">transferTo</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">,</span><span class="pln"> fcout</span><span class="pun">);</span></p><span class="pln"><br />
</span><p><span class="pln">fcout</span><span class="pun">.</span><span class="pln">close</span><span class="pun">();</span><span class="pln"><br />
fcin</span><span class="pun">.</span><span class="pln">close</span><span class="pun">();</span><span class="pln"><br />
outputStream</span><span class="pun">.</span><span class="pln">close</span><span class="pun">();</span><span class="pln"><br />
inputStream</span><span class="pun">.</span><span class="pln">close</span><span class="pun">();</span><span class="pln"><br />
<br />
</span></p></pre><br />
* Channel을 이용한 네이티브OS 기능 사용하기.<br />
<br />
이상으로 3가지 대표적인 자바 파일복사 코드를 살펴보았다. 다음 포스트에서는 각 방식의 성능 차이에 대해 <br />
알아보도록 하겠다.<br />
<br />
<a href="http://www.yunsobi.com/blog/406">자바 파일복사 코드와 성능 2</a><a href="http://www.yunsobi.com/blog/406" onclick="window.open('http://www.yunsobi.com/blog/406');return false;" style="border: medium none ; background: transparent url(/blog/plugins/NewWindowLink/newwindow.gif) no-repeat scroll 0px 50%; text-decoration: none; padding-left: 15px; margin-right: -0.5em; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;" title="다음 링크를 새 창으로 엽니다. : '자바 파일복사 코드와 성능 2'">&nbsp;</a><div class="autosourcing-stub"><div style="padding-top: 5px;" align="center"><a href="http://www.yunsobi.com/blog/406" onclick="window.open('http://www.yunsobi.com/blog/406');return false;" style="border: medium none ; background: transparent url(/blog/plugins/NewWindowLink/newwindow.gif) no-repeat scroll 0px 50%; text-decoration: none; padding-left: 15px; margin-right: -0.5em; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;" title="다음 링크를 새 창으로 엽니다. : '자바 파일복사 코드와 성능 2'">&lt;출처 : </a><a href="http://www.yunsobi.com/" target="_blank">서비의 다락방</a>&nbsp;( http://www.yunsobi.com )&gt;<br />
<font color="#999999">-출처를 밝혀주신 당신은 아름다운 사람입니다.-</font></div></div>           </div>			 ]]> 
		</description>

		<comments>http://spore.egloos.com/4167313#comments</comments>
		<pubDate>Tue, 16 Jun 2009 16:24:07 GMT</pubDate>
		<dc:creator>vimming</dc:creator>
	</item>
	<item>
		<title><![CDATA[ JAVA IO ]]> </title>
		<link>http://spore.egloos.com/4167265</link>
		<guid>http://spore.egloos.com/4167265</guid>
		<description>
			<![CDATA[ 
  <h1 id="title-heading" class="pagetitle">                            		<span id="title-text">					            <a href="http://wiki.oracleclub.com/display/SWDEV/JAVA+IO">JAVA IO</a>    				</span>    </h1>    <!--    Root decorator: this is a layer of abstraction that Confluence doesn't need. It will be removed eventually.-->                                                                                                                                                                    <div class="page-metadata">                Added by <a href="http://wiki.oracleclub.com/display/%7Eo2ptpu">안병훈</a>, last edited by <a href="http://wiki.oracleclub.com/display/%7Eo2ptpu">안병훈</a> on 6월 09, 2009                            <span class="noprint">&nbsp;(<a href="http://wiki.oracleclub.com/pages/diffpages.action?pageId=2457819&amp;originalId=2457947">view change</a>)</span>                </div>                <div class="wiki-content"># 이 문서는 <a href="http://www.oracleclub.com/" target="_blank">오라클클럽</a>에서 작성하였습니다. <br />
# 이 문서를 다른 블로그나 홈페이지에 게재하실 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^ <br />
# 출처 : <a href="http://wiki.oracleclub.com/display/SWDEV/JAVA+IO?" target="_blank">http://wiki.oracleclub.com/display/SWDEV/JAVA+IO?</a><br />
<br />
<!--google_ad_client = "pub-7746436232991148";/* 728x90, 작성됨 08. 3. 21 */google_ad_slot = "2833670423";google_ad_width = 728;google_ad_height = 90;//-->window.google_render_ad<!-- wiki content -->            <h1><a name="JAVAIO-자바I/O"></a>자바 I/O</h1><h2><a name="JAVAIO-자바I/O"></a>자바 I/O</h2><ul><li><a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457822" title="자바 IO 란">자바 I/O 란</a></li></ul><ul><li>바이트 스트림	<ul><li><a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457949" title="File 클래스">File 클래스</a></li><li><a href="http://wiki.oracleclub.com/display/SWDEV/InputStream%2C+OutputStream" title="InputStream, OutputStream">InputStream, OutputStream</a></li><li><a href="http://wiki.oracleclub.com/display/SWDEV/FileInputStream%2C+FileOutputStream" title="FileInputStream, FileOutputStream">FileInputStream, FileOutputStream</a></li><li><a href="http://wiki.oracleclub.com/display/SWDEV/DataInputStream%2C+DataOutputStream" title="DataInputStream, DataOutputStream">DataInputStream, DataOutputStream</a></li><li><a href="http://wiki.oracleclub.com/display/SWDEV/ByteArrayInputStream%2C+ByteArrayOutputStream" title="ByteArrayInputStream, ByteArrayOutputStream">ByteArrayInputStream, ByteArrayOutputStream</a></li><li><a href="http://wiki.oracleclub.com/display/SWDEV/PipedInputStream%2C+PipedOutputStream" title="PipedInputStream, PipedOutputStream">PipedInputStream, PipedOutputStream</a></li></ul>	</li></ul><ul><li>문자 스트림	<ul><li><a href="http://wiki.oracleclub.com/display/SWDEV/Reader%2C+Writer" title="Reader, Writer">Reader, Writer</a></li><li><a href="http://wiki.oracleclub.com/display/SWDEV/InputStreamReader%2C+OutputStreamWriter" title="InputStreamReader, OutputStreamWriter">InputStreamReader, OutputStreamWriter</a></li><li><a href="http://wiki.oracleclub.com/display/SWDEV/FileReader%2C+FileWriter" title="FileReader, FileWriter">FileReader, FileWriter</a></li><li><a href="http://wiki.oracleclub.com/display/SWDEV/BufferedReader%2C+BufferedWriter" title="BufferedReader, BufferedWriter">BufferedReader, BufferedWriter</a></li><li><a href="http://wiki.oracleclub.com/display/SWDEV/PrintWriter" title="PrintWriter">PrintWriter</a></li><li><a href="http://wiki.oracleclub.com/display/SWDEV/CharArrayReader%2C+CharArrayWriter" title="CharArrayReader, CharArrayWriter">CharArrayReader, CharArrayWriter</a></li></ul>	</li></ul><ul><li>객체 스트림	<ul><li><a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457981" title="맛보기">맛보기</a></li><li><a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457983" title="소개">소개</a></li><li><a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457986" title="책목록 예제">책목록 예제</a></li><li><span class="error">[윈도우 저장과 읽기 예제]</span></li><li><span class="error">[정리]</span></li></ul>	</li></ul><ul><li><a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457829" title="ByteStream, CharacterStream 비교">ByteStream, CharacterStream 비교</a></li></ul><ul><li><a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457831" title="기본 입출력 스트림">기본 입출력 스트림</a> : InputStream, OutputStream, Reader, Writer</li></ul><ul><li><a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457851" title="파일 입출력 스트림">파일 입출력 스트림</a> : FileInputStream, FileOutputStream, FileReader, FileWriter</li></ul><ul><li><a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457856" title="연결 입출력 스트림">연결 입출력 스트림</a> : SequenceInputStream, PipedInputStream, PipedOutputStream, PipedReader, PipedWriter</li></ul><ul><li><a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457861" title="배열 입출력 스트림">배열 입출력 스트림</a> : ByteArrayInputStream, ByteArrayOutputStream, CharArrayReader, CharArrayWriter</li></ul><ul><li><a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457865" title="문자열 입출력 스트림">문자열 입출력 스트림</a> : StringBufferInputStream, StringReader, StringWriter</li></ul><ul><li><a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457867" title="필터 입출력 스트림">필터 입출력 스트림</a>	<ul><li><a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457869" title="필터 입출력 스트림-필터 입출력 스트림">필터 입출력 스트림</a> : FilterInputStream, FilterOutputStream, FilterReader, FilterWriter</li><li><a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457871" title="필터 입출력 스트림-버퍼 입출력 스트림">버퍼 입출력 스트림</a> : BufferedInputStream, BufferedOutputStream, BufferedReader, BufferedWriter</li><li><a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457873" title="필터 입출력 스트림-데이터 입출력 스트림">데이터 입출력 스트림</a> : DataInputStream, DataOutputStream</li><li><a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457875" title="필터 입출력 스트림-라인 번호 입력 스트림">라인 번호 입력 스트림</a> : LineNumberInputStream, LineNumberReader</li><li><a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457879" title="필터 입출력 스트림-되돌림 입력 스트림">되돌림 입력 스트림</a> : PushbackInputStream, PushbackReader,</li><li><a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457881" title="필터 입출력 스트림-프린트 출력 스트림">프린트 출력 스트림</a> : PrintStream, PrintWriter</li><li><a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457883" title="필터 입출력 스트림-스트림 토크나이저">스트림 토크나이저</a> : StreamTokenizer</li></ul>	</li></ul><ul><li><a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457895" title="객체직렬화">객체직렬화</a> : ObjectInput, ObjectOutput, ObjectInputStream, ObjectOutputStream	<ul><li><a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457921" title="직렬화 인터페이스">직렬화 인터페이스</a> : Serializable, Externalizable,</li><li><a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457929" title="자료 압축, 손상 검사 및 파일 묶기">자료 압축, 손상 검사 및 파일 묶기</a> : ZipInputStream, ZipOutputStream, CheckedOutputStream, CheckedInputStream, DeflaterOutputStream, InflaterInputStream</li><li><a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457936" title="Random Access File 클래스">Random Access File 클래스</a> : RandomAccessFile</li></ul>	</li></ul><ul><li><a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457941" title="특수한 IO 객체">특수한 IO 객체</a> : System.in, System.out, System.err</li></ul><br />
# 이 문서는 <a href="http://www.oracleclub.com/" target="_blank">오라클클럽</a>에서 작성하였습니다. <br />
# 이 문서를 다른 블로그나 홈페이지에 게재하실 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^ <br />
# 출처 : <a href="http://wiki.oracleclub.com/display/SWDEV/JAVA+IO?" target="_blank">http://wiki.oracleclub.com/display/SWDEV/JAVA+IO?</a>        </div>        <!--<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"         xmlns:dc="http://purl.org/dc/elements/1.1/"         xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">         <rdf:Description    rdf:about="http://beta.oracleclub.com/display/SWDEV/JAVA+IO"    dc:identifier="http://beta.oracleclub.com/display/SWDEV/JAVA+IO"    dc:title="JAVA IO"    trackback:ping="http://beta.oracleclub.com/rpc/trackback/2457819"/></rdf:RDF>-->                                <fieldset class="hidden parameters">    <legend>Labels parameters</legend>    <input id="editLabel" value="Edit" type="hidden">    <input id="addLabel" value="Add Labels" type="hidden">    <input id="domainName" value="http://beta.oracleclub.com" type="hidden">    <input id="pageId" value="2457819" type="hidden">    <input id="spaceKey" value="SWDEV" type="hidden"></fieldset><div id="labels-section" class="pageSection">    <div id="default-labels-header" class="section-header">        <h2 id="labels-section-title" class="section-title hidden">Labels</h2>            </div>    <div class="labels-editor">        <div id="labelsList">                    </div>        <span class="errorMessage error" id="errorSpan"></span>                    <div id="labelInputSpan" class="labels-input">                <div id="labelOperationErrorContainer" class="hidden">                    <span class="error"><span class="errorMessage" id="labelOperationErrorMessage"></span></span>                </div>                <div class="caption">Enter labels to add to this page:</div>                <input autocomplete="off" id="labelsString" name="labelsString" value="" size="40">                <input class="add-labels" value="Add" type="submit">                <input class="hide-labels-editor" value="Done" type="submit">                <div id="waitImageAndStatus">                    <img class="waiting" alt="Please wait" src="http://wiki.oracleclub.com/images/icons/wait.gif">&nbsp;                    <span id="labelOperationStatus" class="smalltext"></span>                </div>                                <div class="labels-tip">                                        Looking for a label? Just start typing.                </div>            </div>            </div></div>                                    <div class="section-header">            <h2 id="children-section-title" class="section-title">                <a name="children">Children (35)</a>            </h2>            <span class="noprint">                &nbsp;                                    <a id="hide-children-link" class="grey" href="http://wiki.oracleclub.com/display/SWDEV/JAVA+IO?showChildren=false#children">Hide Children</a>                                &nbsp;|&nbsp; <a class="grey" href="http://wiki.oracleclub.com/pages/listpages-dirview.action?key=SWDEV&amp;openId=2457819#selectedPageInHierarchy">View in Hierarchy</a>                            </span>        </div>                                                                         <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="BufferedReader, BufferedWriter" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/display/SWDEV/BufferedReader%2C+BufferedWriter">BufferedReader, BufferedWriter</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="ByteArrayInputStream, ByteArrayOutputStream" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/display/SWDEV/ByteArrayInputStream%2C+ByteArrayOutputStream">ByteArrayInputStream, ByteArrayOutputStream</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="ByteStream, CharacterStream 비교" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457829">ByteStream, CharacterStream 비교</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="CharArrayReader, CharArrayWriter" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/display/SWDEV/CharArrayReader%2C+CharArrayWriter">CharArrayReader, CharArrayWriter</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="DataInputStream, DataOutputStream" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/display/SWDEV/DataInputStream%2C+DataOutputStream">DataInputStream, DataOutputStream</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="FileInputStream, FileOutputStream" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/display/SWDEV/FileInputStream%2C+FileOutputStream">FileInputStream, FileOutputStream</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="FileReader, FileWriter" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/display/SWDEV/FileReader%2C+FileWriter">FileReader, FileWriter</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="File 클래스" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457949">File 클래스</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="InputStream, OutputStream" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/display/SWDEV/InputStream%2C+OutputStream">InputStream, OutputStream</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="InputStreamReader, OutputStreamWriter" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/display/SWDEV/InputStreamReader%2C+OutputStreamWriter">InputStreamReader, OutputStreamWriter</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="PipedInputStream, PipedOutputStream" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/display/SWDEV/PipedInputStream%2C+PipedOutputStream">PipedInputStream, PipedOutputStream</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="PrintWriter" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/display/SWDEV/PrintWriter">PrintWriter</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="Random Access File 클래스" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457936">Random Access File 클래스</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="Reader, Writer" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/display/SWDEV/Reader%2C+Writer">Reader, Writer</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="객체직렬화" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457895">객체직렬화</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="기본 입출력 스트림" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457831">기본 입출력 스트림</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="맛보기" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457981">맛보기</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="문자열 입출력 스트림" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457865">문자열 입출력 스트림</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="배열 입출력 스트림" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457861">배열 입출력 스트림</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="소개" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457983">소개</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="연결 입출력 스트림" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457856">연결 입출력 스트림</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="자료 압축, 손상 검사 및 파일 묶기" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457929">자료 압축, 손상 검사 및 파일 묶기</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="자바 IO 란" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457822">자바 IO 란</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="직렬화 인터페이스" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457921">직렬화 인터페이스</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="책목록 예제" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457986">책목록 예제</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="특수한 IO 객체" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457941">특수한 IO 객체</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="파일 입출력 스트림" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457851">파일 입출력 스트림</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="필터 입출력 스트림" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457867">필터 입출력 스트림</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="필터 입출력 스트림-데이터 입출력 스트림" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457873">필터 입출력 스트림-데이터 입출력 스트림</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="필터 입출력 스트림-되돌림 입력 스트림" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457879">필터 입출력 스트림-되돌림 입력 스트림</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="필터 입출력 스트림-라인 번호 입력 스트림" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457875">필터 입출력 스트림-라인 번호 입력 스트림</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="필터 입출력 스트림-버퍼 입출력 스트림" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457871">필터 입출력 스트림-버퍼 입출력 스트림</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="필터 입출력 스트림-스트림 토크나이저" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457883">필터 입출력 스트림-스트림 토크나이저</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="필터 입출력 스트림-프린트 출력 스트림" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457881">필터 입출력 스트림-프린트 출력 스트림</a>                             <br />
                                                     <img src="http://wiki.oracleclub.com/images/icons/docs_16.gif" title="필터 입출력 스트림-필터 입출력 스트림" width="16" align="absmiddle" border="0" height="16">                         <a href="http://wiki.oracleclub.com/pages/viewpage.action?pageId=2457869">필터 입출력 스트림-필터 입출력 스트림</a>                             			 ]]> 
		</description>
		<category>java</category>

		<comments>http://spore.egloos.com/4167265#comments</comments>
		<pubDate>Tue, 16 Jun 2009 15:30:46 GMT</pubDate>
		<dc:creator>vimming</dc:creator>
	</item>
	<item>
		<title><![CDATA[ 예제를 통해본 자바 입출력 ]]> </title>
		<link>http://spore.egloos.com/4167260</link>
		<guid>http://spore.egloos.com/4167260</guid>
		<description>
			<![CDATA[ 
  <pre><font><font size="2" face="굴림"><h2>예제를 통해본 자바 입출력</h2><br />
이글은 숭실대학교 최종명님의 강좌에서 발최한 내용입니다.<br />
<br />
 <a href="mailto:jmchoi@it.soongsil.ac.kr">최종명</a><br />
<br />
바이트의 연속을 스트림(stream)이라고 한다. 자바에서는 스트림을 이용해서 입출력을 한다.<br />
입력을 하는 스트림을 입력스트림(input stream)이라고 하고, 출력하는 스트림을 출력 스트림(output stream)이라고 한다. <br />
입출력 스트림은 java.io 패키지에 만들어져 있다.<br />
화면에 출력하고, 키보드로 부터 입력을 받아들이기 위해서는 System 클래스의 <br />
out 과 in 을 사용했다. System 클래스의 out은 PrintStream 타입의 멤버 필드이고,<br />
in은 InputStream 타입의 멤버 필드이다. 자바에서 입력 스트림 클래스들은 <br />
InputStream 클래스로부터 상속된 클래스이다. 출력 스트림 클래스들은 OutputStream <br />
클래스로부터 상속된 클래스이다.<br />
<br />
<h3>9.2.1 InputStream 클래스</h3><br />
System 클래스의 in 멤버필드는 대표적인 InputStream 타입이다. InputStream은 입력을<br />
위해 다음과 같은 메소드들을 이용할 수 있다.<br />
       int read()<br />
       int read(byte[])<br />
       int read(byte[], int, int)<br />
read() 메소드를 이용하는 경우에 바이트 값을 읽어오거나 파일의 끝인 경우에는<br />
-1을 리턴한다. read(byte[]) 메소드는 읽은 내용을 바이트 배열에 채우고, 읽은 바이트의<br />
수를 리턴한다. read(byte[], int, int) 메소드는 바이트 배열에서 시작 위치와 끝 위치를<br />
지정한 뒤에 내용을 읽어오고, 읽은 바이트의 수를 리턴한다.<br />
<br />
<br />
inOut.java 파일<br />
     1  import java.io.*;<br />
     2<br />
     3  class inOut {<br />
     4      public static void main (String args[]) throws IOException {<br />
     5          int b, count = 0;<br />
     6          while ((b = System.in.read()) != -1) {<br />
     7              count++;<br />
     8              System.out.print((char)b);<br />
     9          }<br />
    10          System.out.println();<br />
    11          System.err.println("total bytes = " + count);<br />
    12      }<br />
    13  }<br />
<br />
결과 <br />
% java inOut<br />
Hello<br />
Hello<br />
한글<br />
??±?<br />
^D<br />
total bytes = 11<br />
<br />
설명<br />
     6          while ((b = System.in.read()) != -1) {<br />
System.in.read() 메소드를 이용해서 키보드로부터 입력을 받는다. read() 메소드는<br />
바이트 입력을 리턴하고, 입력이 종료되면(Cntl-D) -1을 리턴한다.<br />
<br />
     8              System.out.print((char)b);<br />
System.out.print() 메소드를 이용해서 읽어온 바이트를 문자 타입으로 변환해서<br />
출력한다.<br />
<br />
    11          System.err.println("total bytes = " + count);<br />
System 클래스의 err 멤버 필드를 이용해서 출력하였다. err 멤버필드는 표준 에러<br />
출력을 위해 사용된다.<br />
<br />
total bytes = 11<br />
유닉스 시스템에서 테스트 하였기 때문에 영어 문자당 1개의 바이트와 한글에 2바이트<br />
가 사용되었다. 따라서, 영어 5개 문자(5 바이트), 한글 2개 문자(4 바이트), 리턴값<br />
(1 바이트 x 2), 총 11 바이트가 된다.<br />
<br />
<br />
<br />
<h3>9.2.2 InputStreamReader 클래스</h3><br />
JDK 1.0의 입출력 스트림은 JDK 1.1에서 Reader 와 Writer 클래스로 대체되었다.<br />
입력을 위해서는 Reader 클래스를 이용하고, 출력을 위해서는 Writer 클래스를 <br />
이용할 수 있다. Reader 클래스는 입력을 위해 다음과 같은 메소드들을 이용할 수 있다.<br />
         int read()<br />
         int read(char[])<br />
         int read(char[], int, int)<br />
<br />
InputStreamReader 클래스는 InputStream 을 아규먼트로 만들어진다. <br />
InputStreamReader 클래스의 getEncoding() 메소드는 스트림에서 사용된 인코딩 이름을 리턴한다.<br />
<br />
BufferedReader 클래스는 Reader 클래스를 아규먼트로 만들 수 있다. BufferedReader 클래스<br />
 는 다음과 같은 메소드를 이용해서 입력을 받을 수 있다.<br />
          int read()<br />
          String readLine()<br />
read() 메소드는 한문자를 읽어서 리턴하는 메소드이고, readLine() 메소드는 한 줄을<br />
읽어서 문자열을 리턴하는 메소드이다.<br />
<br />
<br />
CharInput.java 파일<br />
     1  import  java.io.*;<br />
     2<br />
     3  public class CharInput {<br />
     4<br />
     5      public static void main(String args[]) {<br />
     6          String  s;<br />
     7          BufferedReader     in;<br />
     8          in = new BufferedReader(new InputStreamReader(System.in));<br />
     9<br />
    10          try {<br />
    11              System.out.print("Put characters:");<br />
    12              while((s = in.readLine()) != null) {<br />
    13                  System.out.println("\tCharacters from console :" + s);<br />
    14                  System.out.print("Put characters:");<br />
    15              }<br />
    16          } catch (IOException ex) { }<br />
    17      }<br />
    18  }<br />
<br />
결과<br />
% java CharInput<br />
Put characters:Hello ?<br />
        Characters from console :Hello ?<br />
Put characters:안녕하세요 ?<br />
        Characters from console :안녕하세요 ?<br />
Put characters:^D<br />
<br />
설명<br />
     8          in = new BufferedReader(new InputStreamReader(System.in));<br />
키보드로 부터 입력을 받는 BufferedReader 클래스를 만들기 위해, InputStreamReader<br />
클래스와 System.in 을 이용했다.<br />
<br />
    12              while((s = in.readLine()) != null) {<br />
BufferedReader 클래스의 readLine() 메소드를 이용해서 한줄을 읽어들였다.<br />
<br />
<br />
<br />
<h3>9.2.3 FileOutputStream 클래스</h3><br />
FileOut.java 파일<br />
     1  import java.io.*;<br />
     2<br />
     3  public class FileOut {<br />
     4      private FileOutputStream fout;<br />
     5      private byte msg[];<br />
     6      private int  len;<br />
     7<br />
     8      FileOut(String fname) throws IOException {<br />
     9          msg = new byte[1024];<br />
    10          len = 0;<br />
    11          fout = new FileOutputStream(fname);<br />
    12          int b =0;<br />
    13<br />
    14          System.out.print("Put characters:");<br />
    15          b = System.in.read();<br />
    16          while(b != 10) {<br />
    17              msg[len++] = (byte)b;<br />
    18              b = System.in.read();<br />
    19          }<br />
    20          write(msg);<br />
    21          System.out.println("Total "+ len + " bytes.");<br />
    22      }<br />
    23<br />
    24      public void write(byte[] m) throws IOException{<br />
    25          for(int i=0; i &lt; len; i++)  {<br />
    26              fout.write(m[i]);<br />
    27          }<br />
    28      }<br />
    29<br />
    30      public void close() {<br />
    31          try {<br />
    32              fout.close();<br />
    33          } catch(IOException ex) { }<br />
    34      }<br />
    35<br />
    36<br />
    37      public static void main(String[] args) throws IOException{<br />
    38          FileOut o = new FileOut("temp");<br />
    39          o.close();<br />
    40      }<br />
    41<br />
    42  }<br />
<br />
결과<br />
% java FileOut<br />
Put characters:Hello ? 안녕하세요 ?<br />
Total 20 bytes.<br />
<br />
% more temp<br />
Hello ? 안녕하세요 ?<br />
<br />
설명<br />
    11          fout = new FileOutputStream(fname);<br />
파일 이름을 아규먼트로 갖고 FileOutputStream 클래스를 만든다.<br />
<br />
    15          b = System.in.read();<br />
키보드로부터 입력을 받아들인다.<br />
<br />
    26              fout.write(m[i]);<br />
FileOutputStream 클래스를 이용해서 파일에 기록한다.<br />
<br />
    32              fout.close();<br />
close() 메소드를 이용해서 파일을 닫는다.<br />
<br />
<br />
<br />
<h3>9.2.4 RandomAccessFile 클래스</h3><br />
RandomAccessFile 클래스는 seek() 메소드를 이용해서 입출력 포인터의 위치를<br />
이동할 수 있다. 포인터를 이동시킨뒤에 파일에 기록하거나 내용을 읽을 수 있다.<br />
RandomAccessFile 클래스는 다음과 같은 생성자를 이용해서 만들 수 있다.<br />
      RandomAccessFile(String filename, String openmode)<br />
첫번째 아규먼트는 파일의 이름을 의미하고, 두번째 아규먼트는 파일을 오픈할 때<br />
읽기 전용인가 아니면 읽기/쓰기 가능한지를 나타낸다. 두번째 아규먼트는 읽기 <br />
전용인 경우에는 "r", 읽기/쓰기 인 경우에는 "rw" 이다.<br />
RandomAccessFile 클래스는 파일의 길이를 알아볼 수 있는 length() 메소드, 각 자료<br />
타입을 읽을 수 있는 readBoolean(), readByte(), readChar(), readDouble(), readFloat(),<br />
readInt(), readLong(), readShort() 등의 메소드들이 있다. 마찬가지로 각 자료 타입을<br />
기록할 수 있는 writeBoolean(boolean), writeByte(int), writeBytes(String), writeChar(int),<br />
writeChars(String), writeDouble(double), writeFloat(float), writeInt(int), writeLong(long),<br />
writeShort(int) 등의 메소드들이 있다.<br />
<br />
EmployeeDB.java 파일 예제는 자바에서 C 언어에서 레코드를 어떻게 사용하는가를 보여준다.<br />
자바는 레코드가 없기 때문에 클래스를 레코드로 사용한다. Record 클래스는 레코드를 표현하기<br />
위해 사용된 클래스이다. Table 클래스는 레코드를 처리하기 위해 사용된 클래스이다. <br />
Table 클래스에서 레코드를 읽거나 기록하기 위한 루틴들을 포함하고 있다. EmployeeDB 클래스는<br />
주로 GUI를 위한 코드가 들어 있다.<br />
<br />
EmployeeDB.java 파일<br />
     1  import java.awt.*;<br />
     2  import java.awt.event.*;<br />
     3  import java.io.*;<br />
     4<br />
     5<br />
     6  public class EmployeeDB extends Frame implements ActionListener {<br />
     7      static final int NONE   = 0;<br />
     8      static final int ADD    = 1;<br />
     9      static final int TOTAL  = 2;<br />
    10      static final int SEARCH = 3;<br />
    11      static final int REMOVE = 4;<br />
    12      static final int ESC    = 5;<br />
    13      Panel             left, bottom;<br />
    14      LabeledTextField  name, number, dept, phone;<br />
    15      TextArea          display;<br />
    16      Button            addB, totalB, searchB, removeB, escB, exitB;<br />
    17      Table             table;<br />
    18      int               action;<br />
    19<br />
    20<br />
    21      public EmployeeDB() {<br />
    22          setLayout(new BorderLayout());<br />
    23          action = NONE;<br />
    24          left = new Panel();<br />
    25          bottom = new Panel();<br />
    26          display = new TextArea();<br />
    27          display.setEditable(false);<br />
    28          name = new LabeledTextField("이 름");<br />
    29          name.setEditable(false);<br />
    30          number = new LabeledTextField("사 번");<br />
    31          number.setEditable(false);<br />
    32          dept = new LabeledTextField("부 서");<br />
    33          dept.setEditable(false);<br />
    34          phone = new LabeledTextField("전 화");<br />
    35          phone.setEditable(false);<br />
    36          left.setLayout(new GridLayout(4,1));<br />
    37          left.setSize(400, 300);<br />
    38          left.add(name);<br />
    39          left.add(number);<br />
    40          left.add(dept);<br />
    41          left.add(phone);<br />
    42<br />
    43          addB = new Button("추 가");<br />
    44          addB.addActionListener(this);<br />
    45          addB.setActionCommand("add");<br />
    46          totalB = new Button("전체 보기");<br />
    47          totalB.addActionListener(this);<br />
    48          totalB.setActionCommand("total");<br />
    49          searchB = new Button("검 색");<br />
    50          searchB.addActionListener(this);<br />
    51          searchB.setActionCommand("search");<br />
    52          removeB = new Button("삭 제");<br />
    53          removeB.addActionListener(this);<br />
    54          removeB.setActionCommand("remove");<br />
    55          escB = new Button("취 소");<br />
    56          escB.addActionListener(this);<br />
    57          escB.setActionCommand("esc");<br />
    58          exitB = new Button("종 료");<br />
    59          exitB.addActionListener(this);<br />
    60          exitB.setActionCommand("exit");<br />
    61          exitB.setBackground(Color.red);<br />
    62          bottom.setLayout(new GridLayout(1,6));<br />
    63          bottom.add(addB);<br />
    64          bottom.add(totalB);<br />
    65          bottom.add(searchB);<br />
    66          bottom.add(removeB);<br />
    67          bottom.add(escB);<br />
    68          bottom.add(exitB);<br />
    69<br />
    70          add("Center", display);<br />
    71          add("West", left);<br />
    72          add("South", bottom);<br />
    73<br />
    74          table = new Table();<br />
    75      }<br />
    76<br />
    77      public void initialize() {<br />
    78          action = NONE;<br />
    79          addB.enable();<br />
    80          totalB.enable();<br />
    81          searchB.enable();<br />
    82          removeB.enable();<br />
    83          name.setText("");<br />
    84          number.setText("");<br />
    85          dept.setText("");<br />
    86          phone.setText("");<br />
    87          name.setEditable(false);<br />
    88          number.setEditable(false);<br />
    89          dept.setEditable(false);<br />
    90          phone.setEditable(false);<br />
    91      }<br />
    92<br />
    93      public void actionPerformed(ActionEvent e) {<br />
    94          int    index = 0;<br />
    95          String cmd = e.getActionCommand();<br />
    96          String nameString, num, part, tel;<br />
    97          boolean found = false;<br />
    98          String  msg = "";<br />
    99<br />
   100          if(cmd.equals("add")) {<br />
   101              if(action != ADD) {<br />
   102                  action = ADD;<br />
   103                  name.setEditable(true);<br />
   104                  number.setEditable(true);<br />
   105                  dept.setEditable(true);<br />
   106                  phone.setEditable(true);<br />
   107                  totalB.disable();<br />
   108                  searchB.disable();<br />
   109                  removeB.disable();<br />
   110                  return;<br />
   111              }<br />
   112              nameString = name.getText().trim();<br />
   113              if(nameString == null || nameString.length() == 0)<br />
   114                  return;<br />
   115              num  = number.getText().trim();<br />
   116              if(num == null || num.length() == 0)<br />
   117                  return;<br />
   118              part = dept.getText().trim();<br />
   119              if(part == null || part.length() == 0)<br />
   120                  return;<br />
   121              tel = phone.getText().trim();<br />
   122<br />
   123              display.setText(nameString + num + part + tel);<br />
   124              table.add(nameString, num, part, tel);<br />
   125              display.appendText("\n 등록을 성공적으로 마쳤습니다.");<br />
   126              initialize();<br />
   127          } else if(cmd.equals("total")) {<br />
   128              action = TOTAL;<br />
   129              initialize();<br />
   130              index = table.getIndex();<br />
   131              display.setText("\n 검색 건수 : 총 " + Integer.toString(index+1)+ " 건\n");<br />
   132              display.appendText("\n============================================");<br />
   133              display.appendText("\n 순번  \t성명   \t사번   \t부서명    \t전화번호 ");<br />
   134              display.appendText("\n--------------------------------------------\n\n");<br />
   135              if(index &lt; 0) {<br />
   136                  display.appendText(" 등록된 자료가 없습니다. \n");<br />
   137                  return;<br />
   138              }<br />
   139              for(int i = 0; i &lt;= index; i++) {<br />
   140                  Record rec = table.readRec(i);<br />
   141                  msg = " " + Integer.toString(i+1) + "  \t ";<br />
   142                  msg +=  rec.getName() + " \t";<br />
   143                  msg +=  Integer.toString(rec.getNum()) + " \t";<br />
   144                  msg +=  rec.getPart() + " \t";<br />
   145                  msg +=  rec.getTel() + "\n";<br />
   146                  display.appendText(msg);<br />
   147              }<br />
   148          } else if(cmd.equals("search")) {<br />
   149              if(action != SEARCH) {<br />
   150                  action = SEARCH;<br />
   151                  name.setEditable(true);<br />
   152                  addB.disable();<br />
   153                  totalB.disable();<br />
   154                  removeB.disable();<br />
   155                  return;<br />
   156              }<br />
   157              Record  rec;<br />
   158              index = table.getIndex();<br />
   159              nameString = name.getText().trim();<br />
   160              if(nameString == null || nameString.length() == 0)<br />
   161                  return;<br />
   162              display.setText("\n ## 개인 조회 ###########\n");<br />
   163              display.appendText("\n============================================");<br />
   164              display.appendText("\n 순번  \t성명   \t사번   \t부서명  \t전화번호 ");<br />
   165              display.appendText("\n--------------------------------------------\n\n");<br />
   166              for(int i = 0; i &lt;= index; i++) {<br />
   167                  rec = table.readRec(i);<br />
   168                  if(nameString.equals(table.readName(i, nameString.length()))) {<br />
   169                      found = true;<br />
   170                  }<br />
   171                  if(found) {<br />
   172                      msg = " " + Integer.toString(i+1) + "  \t ";<br />
   173                      msg +=  rec.getName() + " \t";<br />
   174                      msg +=  Integer.toString(rec.getNum()) + " \t";<br />
   175                      msg +=  rec.getPart() + " \t";<br />
   176                      msg +=  rec.getTel() + "\n";<br />
   177                      display.appendText(msg);<br />
   178                      msg = "";<br />
   179                      break;<br />
   180                  }<br />
   181              }<br />
   182              if (!found) {<br />
   183                  display.setText(" 조회하신 성명이나 사번의  직원이 없습니다...");<br />
   184              }<br />
   185              initialize();<br />
   186          } else if(cmd.equals("remove")) {<br />
   187              if(action != REMOVE) {<br />
   188                  action = REMOVE;<br />
   189                  name.setEditable(true);<br />
   190                  addB.disable();<br />
   191                  totalB.disable();<br />
   192                  searchB.disable();<br />
   193                  return;<br />
   194              }<br />
   195              index = table.getIndex();<br />
   196              nameString = name.getText().trim();<br />
   197              if(nameString == null || nameString.length() == 0)<br />
   198                  return;<br />
   199              display.setText("\n ## 삭제 ###########\n");<br />
   200              display.appendText("\n============================================");<br />
   201              display.appendText("\n 순번  \t성명   \t사번   \t부서명  \t전화번호 ");<br />
   202              display.appendText("\n--------------------------------------------\n\n");<br />
   203              for(int i = 0; i &lt;= index; i++) {<br />
   204                  Record rec = table.readRec(i);<br />
   205                  if(nameString.equals(table.readName(i, nameString.length()))) {<br />
   206                      found = true;<br />
   207                  }<br />
   208                  if(found) {<br />
   209                      msg  = rec.getName();<br />
   210                      msg += Integer.toString(rec.getNum());<br />
   211                      msg += rec.getPart();<br />
   212                      msg += rec.getTel();<br />
   213                      display.appendText(msg);<br />
   214                      msg = "";<br />
   215                      found = true;<br />
   216                      display.appendText("\n 위의 자료를 삭제하였습니다....");<br />
   217                      for(int j=i+1; j &lt;= index; j++) {<br />
   218                          rec = table.readRec(j);<br />
   219                          table.writeRec(rec.getName(),rec.getNum(),rec.getPart(),rec.getTel(),j-1);<br />
   220                      }<br />
   221                      table.remove(--index);<br />
   222                      break;<br />
   223                  }<br />
   224              }<br />
   225              if(!found) {<br />
   226                  display.appendText("조회하신 성명의  직원이 없습니다...");<br />
   227              }<br />
   228              initialize();<br />
   229          } else if(cmd.equals("esc")) {<br />
   230              action = NONE;<br />
   231              initialize();<br />
   232          } else if(cmd.equals("exit")) {<br />
   233              table.close();<br />
   234              setVisible(false);<br />
   235              dispose();<br />
   236              System.exit(0);<br />
   237          }<br />
   238      }<br />
   239<br />
   240<br />
   241<br />
   242      class Table {<br />
   243          private RandomAccessFile myRAFile;<br />
   244          private int recordCount;<br />
   245          private int recordLength = 50;<br />
   246          private int recordOffset = 4;<br />
   247<br />
   248          public Table() {<br />
   249              try {<br />
   250                  myRAFile = new RandomAccessFile("employee.db", "rw");<br />
   251                  if(myRAFile.length() ==0) {<br />
   252                      recordCount = -1;<br />
   253                  } else {<br />
   254                      recordCount = myRAFile.readInt();<br />
   255                  }<br />
   256              } catch(IOException e) {<br />
   257                  System.out.println("Can't access employee.dat");<br />
   258              }<br />
   259          }<br />
   260<br />
   261<br />
   262          public int getIndex() {<br />
   263              return recordCount;<br />
   264          }<br />
   265<br />
   266          public void add(String name, String num, String part, String tel) {<br />
   267              writeRec(name, Integer.parseInt(num), part, tel, ++recordCount);<br />
   268          }<br />
   269<br />
   270          public void close() {<br />
   271              try {<br />
   272                  myRAFile.close();<br />
   273              } catch(IOException ioe) {<br />
   274                  System.out.println("IOException during close file");<br />
   275              }<br />
   276          }<br />
   277<br />
   278          public Record readRec(int index) {<br />
   279              String name="", part="", tel="" ;<br />
   280              int    num = -1 ;<br />
   281<br />
   282              try {<br />
   283                  myRAFile.seek(index * recordLength + recordOffset);<br />
   284                  for(int i = 0; i &lt; 5;i++)  {<br />
   285                      name += myRAFile.readChar();<br />
   286                  }<br />
   287                  num = myRAFile.readInt();<br />
   288                  for(int i = 0; i &lt; 6;i++) {<br />
   289                      part += myRAFile.readChar();<br />
   290                  }<br />
   291                  for(int i = 0; i &lt; 8;i++)  {<br />
   292                      tel  += myRAFile.readChar();<br />
   293                  }<br />
   294<br />
   295              } catch(IOException ioe) {<br />
   296                  System.out.println("IOException during read file..");<br />
   297              }<br />
   298              return (new Record(name, num, part, tel));<br />
   299          }<br />
   300<br />
   301          public String readName(int index, int len) {<br />
   302              String name="";<br />
   303              try {<br />
   304                  myRAFile.seek(index * recordLength + recordOffset);<br />
   305                  for(int i = 0; i &lt; len;i++)  {<br />
   306                      name += myRAFile.readChar();<br />
   307                  }<br />
   308              } catch (IOException ioe) {<br />
   309                  System.out.println("IOException :"+ioe.toString());<br />
   310              }<br />
   311              return (name);<br />
   312          }<br />
   313<br />
   314<br />
   315          public void remove(int i) {<br />
   316              recordCount = i;<br />
   317          }<br />
   318<br />
   319<br />
   320          public void writeRec(String name, int num, String part, String tel, int index) {<br />
<br />
   321              int len = 0;<br />
   322<br />
   323              try {<br />
   324                  myRAFile.seek(index * recordLength + recordOffset);<br />
   325                  len = name.length();<br />
   326                  for(int i =0;i &lt; 5;i++) {<br />
   327                      myRAFile.writeChar((i &lt; len ? name.charAt(i) : ' '));<br />
   328                  }<br />
   329                  myRAFile.writeInt(num);<br />
   330<br />
   331                  len = part.length();<br />
   332                  for(int i =0;i &lt; 6;i++) {<br />
   333                      myRAFile.writeChar((i &lt; len ? part.charAt(i) : ' '));<br />
   334                  }<br />
   335<br />
   336                  len = tel.length();<br />
   337                  for(int i =0;i &lt; 8;i++) {<br />
   338                      myRAFile.writeChar((i &lt; len ? tel.charAt(i) : ' '));<br />
   339                  }<br />
   340                  myRAFile.seek(0);<br />
   341                  myRAFile.writeInt(recordCount);<br />
   342              } catch(IOException ioe) {<br />
   343                  System.out.println("IOException while writing..");<br />
   344              }<br />
   345          }<br />
   346<br />
   347      }<br />
   348<br />
   349<br />
   350      class Record {<br />
   351          private  String  name;<br />
   352          private  int     num;<br />
   353          private  String  part;<br />
   354          private  String  tel;<br />
   355<br />
   356          public Record(String na, int n, String p, String t) {<br />
   357              name  = na;<br />
   358              num   = n;<br />
   359              part  = p;<br />
   360              tel   = t;<br />
   361          }<br />
   362<br />
   363          public String getName() {<br />
   364              return(name);<br />
   365          }<br />
   366<br />
   367          public int getNum() {<br />
   368              return(num);<br />
   369          }<br />
   370<br />
   371          public String getPart() {<br />
   372              return(part);<br />
   373          }<br />
   374<br />
   375          public String getTel() {<br />
   376              return(tel);<br />
   377          }<br />
   378      }<br />
   379<br />
   380      public static void main(String agrs[]) {<br />
   381          EmployeeDB  db = new EmployeeDB();<br />
   382          db.setSize(550, 300);<br />
   383          db.setVisible(true);<br />
   384      }<br />
   385  }<br />
<br />
<br />
LabeledTextField.java 파일<br />
     1  import  java.awt.*;<br />
     2<br />
     3  public class LabeledTextField extends Panel{<br />
     4      private  Label     label;<br />
     5      private  TextField field;<br />
     6      private  String    labelPosition;<br />
     7      private  String    fieldPosition;<br />
     8<br />
     9      public LabeledTextField(String labelString) {<br />
    10          this(labelString, "1%, 5%, 25%, 95%", "27%, 5%, 98%, 95%");<br />
    11      }<br />
    12<br />
    13<br />
    14      public LabeledTextField(String labelString, String labelPosition, String fieldPosition) {<br />
    15          super();<br />
    16          setLayout(new PositionLayout());<br />
    17          this.labelPosition = labelPosition;<br />
    18          this.fieldPosition = fieldPosition;<br />
    19          label = new Label(labelString);<br />
    20          field = new TextField(20);<br />
    21          add(labelPosition, label);<br />
    22          add(fieldPosition, field);<br />
    23      }<br />
    24<br />
    25      public String getText() {<br />
    26          return field.getText();<br />
    27      }<br />
    28<br />
    29      public void setText(String m) {<br />
    30          field.setText(m);<br />
    31      }<br />
    32<br />
    33      public void setEditable(boolean t) {<br />
    34          boolean able = field.isEditable();<br />
    35          if(t != able)<br />
    36              field.setEditable(t);<br />
    37      }<br />
    38<br />
    39      public static void main(String args[]) {<br />
    40          Frame f = new Frame();<br />
    41          LabeledTextField lt = new LabeledTextField("Name:");<br />
    42          f.add("South", lt);<br />
    43          f.setSize(400, 200);<br />
    44          f.setVisible(true);<br />
    45      }<br />
    46  }<br />
<br />
결과<br />
% java EmployeeDB<br />
<img src="http://www.javastudy.co.kr/docs/jm/img/jm17_1.gif"><br />
<br />
<br />
설명<br />
   250                  myRAFile = new RandomAccessFile("employee.db", "rw");<br />
employee.db 파일을 읽기/쓰기로 오픈한다.<br />
<br />
   251                  if(myRAFile.length() ==0) {<br />
파일의 길이가 0 이면, 즉 파일에 내용이 없으면..<br />
<br />
   254                      recordCount = myRAFile.readInt();<br />
파일로부터 정수를 하나 읽어온다.<br />
<br />
   283                  myRAFile.seek(index * recordLength + recordOffset);<br />
입출력 포인터를 특정 위치로 이동 시킨다.<br />
<br />
   327                      myRAFile.writeChar((i &lt; len ? name.charAt(i) : ' '));<br />
문자를 파일에 기록한다.<br />
</font></font></pre>			 ]]> 
		</description>
		<category>java</category>

		<comments>http://spore.egloos.com/4167260#comments</comments>
		<pubDate>Tue, 16 Jun 2009 15:26:41 GMT</pubDate>
		<dc:creator>vimming</dc:creator>
	</item>
	<item>
		<title><![CDATA[ excel 2007 파일 열기에서 경고 메세지 ]]> </title>
		<link>http://spore.egloos.com/4166446</link>
		<guid>http://spore.egloos.com/4166446</guid>
		<description>
			<![CDATA[ 
  <h1 class="title"><font size="4">Excel 2007에서 파일을 열면 파일 형식이 파일 이름 확장명에서 지정한 형식과 다르다는 경고가 나타난다</font></h1><div class="appliesToLink"><a href="http://support.microsoft.com/kb/948615/ko#appliesto">이 문서가 적용되는 제품 보기.</a></div>function loadTOCNode(){}<div class="articleProperty"><table><tbody><tr><td>기술 자료 ID</td><td>:</td><td>948615</td></tr><tr><td>마지막 검토</td><td>:</td><td>2008년 5월 23일 금요일</td></tr><tr><td>수정</td><td>:</td><td>1.1</td></tr></tbody></table></div><div class="notice"><b>중요</b> 이 문서에서는 레지스트리 수정 방법을 설명합니다. 레지스트리를 수정하기전에 해당 레지스트리를 백업하는 것이 좋습니다. 또한 문제가 발생할 경우 레지스트리를 복원하는 방법을 알고 있어야 합니다.레지스트리 백업, 복원 및 수정 방법에 대한 자세한 내용은 Microsoft 기술 자료의 다음 문서를 참조하십시오. <div class="indent"><a class="KBlink" href="http://support.microsoft.com/kb/322756/">322756</a><span class="pLink"> (<a href="http://support.microsoft.com/kb/322756/%29" onclick="window.open(this.href); return false;">http://support.microsoft.com/kb/322756/)</a></span> Windows XP 및 Windows Server 2003에서 레지스트리를 백업, 편집 및 복원하는 방법</div></div><h2 class="subTitle" id="tocHeadRef">현상</h2>loadTOCNode(1, 'symptoms');<div class="sbody">Microsoft Office Excel 2007에서 파일 확장명과 일치하지 않는 내용이 포함된 파일을 열면 다음과 같은 경고 메시지가 나타납니다. <div class="message">열려는 파일 '<var>name</var>.<var>ext</var>'의 형식이 파일 확장명에서 지정한 형식과 다릅니다. 파일을 열기 전에 파일이 손상되지 않았는지, 원본을 신뢰할 수 있는지 확인하십시오. 지금 파일을 여시겠습니까?</div><b>참고</b>&nbsp;<var>name</var> 자리 표시자는 파일 이름이고 <var>ext</var> 자리 표시자는 Excel 2007에서 여는 파일의 파일 이름 확장명입니다. <p class="topOfPage"><a href="http://support.microsoft.com/kb/948615/ko#top"><img rel="xe_gallery" style="" alt="" src="http://support.microsoft.com/library/images/support/kbgraphics/public/en-us/uparrow.gif" width="0">위로 가기</a></p></div><h2 class="subTitle" id="tocHeadRef">원인</h2>loadTOCNode(1, 'cause');<div class="sbody">이 경고 메시지는 Excel 2007에 추가된 사용자 알림 기능으로, 파일의 실제 내용과 파일 이름 확장명 간의 비호환성 때문에 발생할 수 있는 예기치 않은 문제를 방지하는 데 도움이 됩니다. <p class="topOfPage"><a href="http://support.microsoft.com/kb/948615/ko#top"><img rel="xe_gallery" style="" alt="" src="http://support.microsoft.com/library/images/support/kbgraphics/public/en-us/uparrow.gif" width="0">위로 가기</a></p></div><h2 class="subTitle" id="tocHeadRef">해결 방법</h2>loadTOCNode(1, 'resolution');<div class="sbody">파일의 원본을 신뢰할 수 있는 경우 경고 메시지에서 <strong class="uiterm">예</strong>를 누르십시오.<br />
<br />
사용자 알림 기능을 제어하려면 다음 방법 중 하나를 사용하십시오.<br />
<br />
<b>중요</b>이 단계를 수행하면 보안 위험이 커질 수 있습니다. 또한 컴퓨터나 네트워크가 악의적인 사용자나 바이러스와 같은 악성 소프트웨어의공격에 더 취약해질 수 있습니다. 프로그램이 원래 설계된 대로 작동하도록 설정하거나 특정 프로그램 기능을 구현하는 데 이문서에서 설명하는 단계를 사용하십시오. 이 단계를 수행하기 전에 먼저 특정 환경에서 이 단계를 구현하는 것과 관련된 위험을평가하는 것이 좋습니다. 이 단계를 구현하기로 한 경우 적절한 시스템 보호 조치를 추가로 취하십시오. 이 단계는 정말 필요한경우에만 사용하는 것이 좋습니다.<br />
<br />
기본적으로 사용자는 경고 메시지가 나타나면 파일을 열지 여부를 결정할 수 있습니다. 그러나 그룹 정책 설정 또는 레지스트리 편집기를 사용하여 사용자 알림 기능을 다음 수준 중 하나로 설정할 수도 있습니다. <table class="list ul"><tbody><tr><td class="bullet">•</td><td class="text">경고 메시지를 표시하고 파일을 열지 않습니다.</td></tr><tr><td class="bullet">•</td><td class="text">경고 메시지를 표시하고 사용자가 파일을 열지 여부를 결정할 수 있습니다(기본 설정).</td></tr><tr><td class="bullet">•</td><td class="text">파일을 열고 경고 메시지를 표시하지 않습니다.</td></tr></tbody></table><b>그룹 정책 설정 사용</b> <table class="list ol"><tbody><tr><td class="number">1.</td><td class="text">다음 Microsoft 다운로드 센터 웹 사이트에서 2007 Office system 관리 템플릿 파일(ADM, ADMX, ADML) 및 Office 사용자 지정 도구를 다운로드합니다. <div class="indent"><span class="ll"><a href="http://www.microsoft.com/downloads/thankyou.aspx?familyId=92d8519a-e143-4aee-8f7a-e4bbaeba13e7&amp;displaylang=ko">http://www.microsoft.com/downloads/thankyou.aspx?familyId=92d8519a-e143-4aee-8f7a-e4bbaeba13e7&amp;displaylang=ko</a></span><span class="pLink"> (<a href="http://www.microsoft.com/downloads/thankyou.aspx?familyId=92d8519a-e143-4aee-8f7a-e4bbaeba13e7&amp;displaylang=ko%29" onclick="window.open(this.href); return false;">http://www.microsoft.com/downloads/thankyou.aspx?familyId=92d8519a-e143-4aee-8f7a-e4bbaeba13e7&amp;displaylang=ko)</a></span></div></td></tr><tr><td class="number">2.</td><td class="text">관리 템플릿 파일을 폴더로 추출합니다. 이렇게 하려면 다음과 같이 하십시오. <table class="list al"><tbody><tr><td class="number">a. </td><td class="text"><strong class="uiterm">AdminTemplates.exe</strong> 파일을 두 번 누릅니다.</td></tr><tr><td class="number">b. </td><td class="text">Microsoft 소프트웨어 사용 조건에 동의한 다음 <strong class="uiterm">Continue</strong>를 누릅니다.</td></tr><tr><td class="number">c. </td><td class="text">추출한 파일을 저장할 폴더를 선택한 다음 <strong class="uiterm">확인</strong>을 누릅니다.</td></tr><tr><td class="number">d. </td><td class="text">파일이 성공적으로 추출되면 <strong class="uiterm">확인</strong>을 누릅니다.</td></tr></tbody></table></td></tr><tr><td class="number">3.</td><td class="text">그룹 정책 개체 편집기를 엽니다.<br />
<br />
그룹 정책 개체 편집기를 여는 방법에 대한 자세한 내용은 다음 Microsoft TechNet 웹 사이트를 참조하십시오. <div class="indent"><span class="ll"><a href="http://technet2.microsoft.com/windowsserver/ko/library/03ec122f-fc65-496e-ad0d-4fd22a96a4bb1042.mspx?mfr=true">http://technet2.microsoft.com/windowsserver/ko/library/03ec122f-fc65-496e-ad0d-4fd22a96a4bb1042.mspx?mfr=true</a></span><span class="pLink"> (<a href="http://technet2.microsoft.com/windowsserver/ko/library/03ec122f-fc65-496e-ad0d-4fd22a96a4bb1042.mspx?mfr=true%29" onclick="window.open(this.href); return false;">http://technet2.microsoft.com/windowsserver/ko/library/03ec122f-fc65-496e-ad0d-4fd22a96a4bb1042.mspx?mfr=true)</a></span></div></td></tr><tr><td class="number">4.</td><td class="text"><strong class="uiterm">사용자 구성</strong>을 확장합니다.</td></tr><tr><td class="number">5.</td><td class="text"><strong class="uiterm">관리 템플릿</strong>을 마우스 오른쪽 단추로 누른 다음 <strong class="uiterm">템플릿 추가/제거</strong>를 누릅니다.</td></tr><tr><td class="number">6.</td><td class="text"><strong class="uiterm">템플릿 추가/제거</strong> 대화 상자에서 <strong class="uiterm">추가</strong>를 누릅니다.</td></tr><tr><td class="number">7.</td><td class="text">2c단계에서 추출한 관리 템플릿이 있는 폴더로 이동합니다.</td></tr><tr><td class="number">8.</td><td class="text"><strong class="uiterm">Excel12.adm</strong> 파일을 누른 다음 <strong class="uiterm">열기</strong>를 누릅니다. Excel12.adm 파일은 2c단계에서 관리 템플릿을 추출한 다음 폴더에 있습니다. <div class="indent">\ADM\<var>languageID</var></div><b>참고</b> 한국어 관리 템플릿 파일은 <strong class="uiterm">ko-kr</strong> languageID 폴더에 있습니다.</td></tr><tr><td class="number">9.</td><td class="text"><strong class="uiterm">닫기</strong>를 눌러 <strong class="uiterm">템플릿 추가/제거</strong> 대화 상자를 닫습니다.</td></tr><tr><td class="number">10.</td><td class="text"><strong class="uiterm">관리 템플릿</strong>, <strong class="uiterm">Microsoft Office Excel 2007</strong>, <strong class="uiterm">Excel 옵션</strong>을 차례로 확장한 다음 <strong class="uiterm">보안</strong>을 누릅니다.</td></tr><tr><td class="number">11.</td><td class="text"><strong class="uiterm">확장</strong> 탭의 <strong class="uiterm">설정</strong>에서 <strong class="uiterm">파일 확장명을 파일 형식에 맞춤</strong>을 두 번 누릅니다.</td></tr><tr><td class="number">12.</td><td class="text"><strong class="uiterm">설정</strong> 탭에서 <strong class="uiterm">사용</strong>을 누르고 <strong class="uiterm">파일 확장명을 파일 형식에 맞춤</strong> 드롭다운 목록에서 다음 중 하나를 누른 다음 <strong class="uiterm">확인</strong>을 누릅니다. <table class="list ul"><tbody><tr><td class="bullet">•</td><td class="text"><strong class="uiterm">다른 형식 허용</strong></td></tr><tr><td class="bullet">•</td><td class="text"><strong class="uiterm">다른 형식을 허용하고 경고 표시</strong></td></tr><tr><td class="bullet">•</td><td class="text"><strong class="uiterm">항상 파일 형식 일치</strong></td></tr></tbody></table></td></tr><tr><td class="number">13.</td><td class="text">그룹 정책 개체 편집기를 닫습니다.</td></tr></tbody></table><b>레지스트리 편집기 사용</b><br />
<br />
<b>경고</b>레지스트리 편집기나 다른 방법을 사용하여 레지스트리를 잘못 수정하면 심각한 문제가 발생할 수 있습니다. 이러한 문제를 해결하기위해 운영 체제를 다시 설치해야 할 수도 있습니다. Microsoft는 이러한 문제의 해결을 보증하지 않습니다. 레지스트리수정에 따른 모든 책임은 사용자에게 있습니다. <table class="list ol"><tbody><tr><td class="number">1.</td><td class="text">Excel 2007을 종료합니다.</td></tr><tr><td class="number">2.</td><td class="text">레지스트리 편집기를 시작합니다. <table class="list ul"><tbody><tr><td class="bullet">•</td><td class="text">Windows Vista에서는 <strong class="uiterm">시작</strong><img style="cursor: pointer;" rel="xe_gallery" class="graphic" title="시작 단추" alt="시작 단추" src="http://support.microsoft.com/library/images/support/kbgraphics/Public/EN-US/VistaStartButton.jpg" width="52">을 누르고 <strong class="uiterm">검색 시작</strong> 상자에 <span class="userInput">regedit</span>를 입력한 다음 Enter 키를 누릅니다. <br />
<br />
<img style="cursor: pointer;" rel="xe_gallery" class="graphic" title="사용자 계정 컨트롤 권한" alt="사용자 계정 컨트롤 권한" src="http://support.microsoft.com/library/images/support/kbgraphics/Public/EN-US/SecurityShield.jpg" width="132"> 관리자 암호나 확인을 요청하는 메시지가 나타나면 암호를 입력하거나 <strong class="uiterm">계속</strong>을 누릅니다.</td></tr><tr><td class="bullet">•</td><td class="text">Windows XP의 경우 <strong class="uiterm">시작</strong>, <strong class="uiterm">실행</strong>을 차례로 누르고 <span class="userInput">regedit</span>를 입력한 다음 <strong class="uiterm">확인</strong>을 누릅니다.</td></tr></tbody></table></td></tr><tr><td class="number">3.</td><td class="text">다음 레지스트리 하위 키를 찾아서 누릅니다. <div class="indent"><strong class="uiterm">HKEY_CURRENT_USER\Software\Microsoft\Office\12.0\Excel\Security</strong></div></td></tr><tr><td class="number">4.</td><td class="text"><strong class="uiterm">편집</strong> 메뉴에서 <strong class="uiterm">새로 만들기</strong>를 가리킨 다음 <strong class="uiterm">DWORD 값</strong>을 누릅니다.</td></tr><tr><td class="number">5.</td><td class="text"><span class="userInput">ExtensionHardening</span>을 입력한 다음 Enter 키를 누릅니다.</td></tr><tr><td class="number">6.</td><td class="text"><strong class="uiterm">ExtensionHardening</strong>을 마우스 오른쪽 단추로 누른 다음 <strong class="uiterm">수정</strong>을 누릅니다.</td></tr><tr><td class="number">7.</td><td class="text"><strong class="uiterm">값 데이터</strong> 상자에 값 데이터를 입력한 다음 <strong class="uiterm">확인</strong>을 누릅니다.<br />
<br />
다음 목록에서는 ExtensionHardening 설정에 적합한 값 데이터 설정을 보여 줍니다. <table class="list ul"><tbody><tr><td class="bullet">•</td><td class="text">0: 파일 이름 확장명과 파일 형식을 검사하지 않고 경고 메시지 기능을 무시합니다.</td></tr><tr><td class="bullet">•</td><td class="text">1: 파일 이름 확장명과 파일 형식을 검사합니다. 파일 이름 확장명과 파일 형식이 일치하지 않으면 경고 메시지를 표시합니다.</td></tr><tr><td class="bullet">•</td><td class="text">2: 파일 이름 확장명과 파일 형식을 검사합니다. 파일 이름 확장명과 파일 형식이 일치하지 않으면 파일을 열지 않습니다.</td></tr></tbody></table><b>참고</b>이러한 값 데이터의 기본값은 1입니다. 값 데이터를 1로 설정하면 레지스트리 값을 설정하지 않은 것과 같은 결과가 나타납니다.값 데이터를 0으로 설정하면 파일 이름 확장명과 파일 내용이 항상 검사되지 않습니다. 이 기능은 무시하지 않는 것이 좋습니다.</td></tr><tr><td class="number">8.</td><td class="text"><strong class="uiterm">파일</strong> 메뉴에서 <strong class="uiterm">끝내기</strong>를 눌러 레지스트리 편집기를 종료합니다.</td></tr></tbody></table><p class="topOfPage"><a href="http://support.microsoft.com/kb/948615/ko#top"><img rel="xe_gallery" style="" alt="" src="http://support.microsoft.com/library/images/support/kbgraphics/public/en-us/uparrow.gif" width="0">위로 가기</a></p></div><h2 class="subTitle" id="tocHeadRef">현재 상태</h2>loadTOCNode(1, 'status');<div class="sbody">이것은 의도적으로 설계된 동작입니다. <p class="topOfPage"><a href="http://support.microsoft.com/kb/948615/ko#top"><img rel="xe_gallery" style="" alt="" src="http://support.microsoft.com/library/images/support/kbgraphics/public/en-us/uparrow.gif" width="0">위로 가기</a></p></div><h2 class="subTitle" id="tocHeadRef">추가 정보</h2>loadTOCNode(1, 'moreinformation');사용 방법에 따라 파일 이름 확장명이 올바르게 인식되지 않을 수 있는 문제에 대한 자세한 내용은 Microsoft 기술 자료의 다음 문서를 참조하십시오. <div class="indent"><a class="KBlink" href="http://support.microsoft.com/kb/939597/">939597</a><span class="pLink"> (<a href="http://support.microsoft.com/kb/939597/%29" onclick="window.open(this.href); return false;">http://support.microsoft.com/kb/939597/)</a></span> 2007년 6월 29일자 Excel 2007 핫픽스 패키지에 대한 설명 </div>			 ]]> 
		</description>

		<comments>http://spore.egloos.com/4166446#comments</comments>
		<pubDate>Mon, 15 Jun 2009 15:18:17 GMT</pubDate>
		<dc:creator>vimming</dc:creator>
	</item>
	<item>
		<title><![CDATA[ SICP와 HTDP ]]> </title>
		<link>http://spore.egloos.com/4163401</link>
		<guid>http://spore.egloos.com/4163401</guid>
		<description>
			<![CDATA[ 
  <table width="100%" align="center" border="0" cellpadding="0" cellspacing="0"><tbody><tr bgcolor="#f5f3ee" height="30"><td><span class="tt"><b>고전을 찾아서 3 | 바른 가르침과 배움에 대한 해답, <span style="background-color: yellow; color: red;">SICP</span>와 HTDP</b></span></td>    <td align="right"><span class="tt">2003-10-07 09:10:44</span>&nbsp;&nbsp;</td></tr> <tr>    <td colspan="2">        <table width="100%" cellpadding="5">        <tbody><tr>            <td style="" class="lh" height="100">                                <!-- 내용 출력 -->                <span class="content">어떻게 해야 프로그래밍을 제대로 배울 수 있을까? 그리고 어떤 식으로 해야 프로그래밍을 제대로 가르칠 수 있을까? 프로그래밍 기술서적이 무더기로 쏟아져 나오지만 정작 이와 같은 질문에 바른 답을 주는 책은 드물다. 무엇이 ‘제대로’인지 깨닫지 못하는 바에야무작정 프로그래밍 기술을 집어 삼키는 것이 무슨 의미가 있을까? 이 문제를 진지하게 고민하지 않는 이에게는 세상에 둘도 없이못써먹을 책이겠지만 그렇지 않다면―어떻게 프로그래밍을 배우고 가르쳐야 할지 그 바른 출발점을 찾지 못해 헤매는 누군가가 있다면,『Structure and Interpretation of Computer Programs』는 유일무이한 해답이라고 할만 하다.<br />
<br />
김재우 | kizoo@bluette.com<br />
블루엣 인터내셔널의 기술 이사로 재직중이며 개발 환경과 온라인 교육 시스템을 결합한 소프트웨어를 설계하고 있다. 소프트웨어 공학 기술이나 관련 이론을 실천하도록 만드는 것이 개발자로서의 목표다.<br />
<br />
<br />
지난 1985년 MIT Press에서 출판한 『Structure and Interpretation of ComputerPrograms』(이하 SICP)는 MIT의 기초 프로그래밍 교육 과정을 담고 있다. 이 책의 신선한 교육 철학과 완성도 높은내용은 기존의 프로그래밍 입문 교재들과 차원을 달리했다. 그리하여 ‘강호(?)를 평정’했다고 표현해도 될 만큼 수많은 대학에서이 과정을 채택했고, 이른바 프로그래밍 입문 교육의 표준이 됐다(한때 SICP는 세계 300여개 대학의 프로그래밍 교육 과정에사용됐다).<br />
<br />
SICP의 신선한 교육 철학<br />
SICP의 무엇이 그렇게 상큼했을까? 이 책은 프로그래밍 언어의 선택부터가 남달랐다. 당시 산업에서 인기를 끌고 있는 언어나교육용 언어로 널리 인정받았던 파스칼을 쓰지 않고 MIT에서 개발한 새로운 언어, Scheme을 실습 언어로 선택하는 과감성을보였다. 프로그래밍 언어 Scheme은 LISP의 전통을 이어받아 설계된 언어이나 Static Scoping(미안하지만, 아직이 용어를 쉽게 대체할 적당한 우리말을 찾지 못했다)을 채택하고, 함수 계산 결과가 함수가 될 수 있도록 기능을 확장한 면이다르다. 그렇다면 하고 많은 언어 중에 왜 하필이면 Scheme이었을까? 그것도 처음 프로그래밍을 훈련하는 과정에서 왜 그런파격이 필요했을까?<br />
<br />
독특한 실습 언어, Scheme<br />
첫 번째 프로그래밍 언어의 선택은 아주 중요하고도 민감한 문제다. 처음 배우는 언어는 프로그래머에게 모국어와 같아서, 프로그래머가 생각하는 사고의 바탕이 된다(본지 다른 기사를 통해 여러 번 같은 주장을 한 적이 있다). <br />
선택한 언어가 표현 수준이 낮아 어려운 문제를 푸는 데 많은 사전 작업을 거쳐야 한다면 학생들은 문제를 푸는 사고를배운다기보다, 언어의 낮은 표현 수준을 문제를 표현할 수 있는 수준으로 끌어올리는 데 더 심혈을 기울여야 한다(대부분의 시스템프로그래밍 언어가 그렇다). 물론 그 또한 프로그래밍 교육이라고 할 수야 있겠지만 프로그래밍 사고를 형성하고자 하는 교육목표와는 거리가 멀다. 다시 말해 프로그래밍 입문 과정에서 다룰 주제는 아니다. <br />
또한 실습 언어가 편협한 해법을 강요하면 문제를 유연하게 해결하는 사고력을 가르치기 어렵다. 나중에 완전히 다른 방식의 해법을공부하게 되더라도 처음 익힌 사고의 편향성 때문에 새로운 방식에 적응하기 매우 힘들다(필자 자신이 그 좋은 예다. SICP를처음 배울 때의 충격은 프로그래밍을 처음 배웠을 때에 비할 바가 아니었다). <br />
그러므로 가능하면 아예 처음부터 복합 사고를 익히게 하는 것이 옳다. 즉, 하나의 문제 풀이에 가능한 해법을 총동원해 보고, 그 중 가장 유리한 해법 몇 개를 섞어 쓰도록 유도하는 것이 바람직하다(이른바 멀티패러다임 프로그래밍).<br />
Scheme은 앞의 두 가지 문제를 균형 있게 해결할 수 있는 답이다. 문법이 간결하고 구문의 의미가 명확하다 보니 다른언어에서처럼 ‘문법의 횡포’에 시달릴 요인이 없다. 즉, 언어를 익히느라 시간을 허비하지 않아도 되므로 교육의 취지에 맞게프로그래밍을 익히는 데 더 많은 노력과 시간을 할애할 수 있다(만일 이 글이 언어 선택에 대한 확신을 심어주기에 모자라다고생각하면, Alan J. Perlis가 쓴 SICP의 머리말과 참고자료 ?의 논문을 읽어봐 주었으면 한다).<br />
<br />
풍부하고 정선된 예제<br />
SICP의 두 번째 자랑거리는 주옥같은 예제에 있다. 이 책은 예제로 시작해 예제로 끝난다고 해도 과언이 아닐 정도로 풍부한예제를 제공하는데, 그 완성도가 뛰어남은 물론이고 하나하나 확실한 교육 목표를 염두에 두고 설계되어 있다. 즉, 프로그래밍기법이나 새로운 응용 분야를 말로 드러내어 설명한다기보다(그렇다고 아예 설명을 생략한다는 것은 아니지만), 주어진 문제의자연스런 해결책으로 동원될 수 있게 애써 꾸며 놓았다. <br />
이는 시중에서 흔히 볼 수 있는 프로그래밍 책들과 크게 다른 접근 방식이다. 보통 프로그래밍 패러다임이나 설계 원리를 설명하는책들은 이해시키고자 하는 대상에 지나치게 집중한 나머지 예제 선택의 중요성을 간과한다. 고의로 간단한 예제를 사용하고 예제자체를 이해하는 데 부담을 줄여 원리를 이해시키는 목적에 충실하자는 의도다. 그러나 이런 방식은 원리 해설에는 유리할지 몰라도그 원리를 실제 어떻게 응용해야 좋은지, 그리고 어떤 유형의 문제에 더 적합한지를 가르쳐 주지는 못한다.<br />
SICP의 2.4~2.5절은 SICP의 그런 장점을 보여주는 좋은 예다. 이 두 절은 복소수를 예로 들어 다형성 문제를 취급하고있는데, 무작정 다형성을 소개하는 것이 아니라 ‘한 종류(형, type)의 데이터라도 왜 여러 개의 표현이 필요한지’를자연스럽게―프로그램 개발 과정에서 요구 변화에 따라오는 필연적 개선 작업으로 설명한다. <br />
복소수는 직각 좌표계에서 표현할 수 있지만 극 좌표계에서도 표현 가능하다. 그런데 이 두 표현 방식은 쓰임새에 따라 어느 한쪽이 더 유리해질 가능성이 있다. 예를 들어, 복소수를 덧셈/뺄셈할 때는 직각 좌표로 표현하는 것이 좋고, 곱셈/나눗셈에는 극좌표가 자연스럽다.<br />
<br />
◆ 직각 좌표 표현으로 덧셈<br />
c1 + c2 = 실수부(c1 + c2) + 허수부(c1 + c2)i <br />
	= (실수부(c1) + 실수부(c2)) + (허수부(c1) + 허수부(c2))i<br />
◆ 극 좌표로 곱셈<br />
c1.c2 = r.e^iA<br />
	where r = 크기(c1.c2) = 크기(c1).크기(c2)<br />
		   A = 각(c1) + 각(c2)<br />
<br />
그러므로 단 한 가지 표현만 쓰게 된다면 어느 한 쪽 연산에만 유리하다. 결국 여러 연산에 고루 유리한 복소수 데이터를 만들고자한다면 여러 표현을 하나의 그릇에 섞을 수 있어야 하며, 이를 사용하는 쪽에서는 그 속사정을 알지 못하도록 가려야 한다. 이문제를 가장 간단하게 해결하는 방법은 내부에서는 한쪽 표현에 따라 구현하고, 다른 표현은 인터페이스로만 제공하는 것이다. 즉,다음과 같다.<br />
<br />
Let c = x + yi (복소수를 직각 좌표로 표현했을 경우)<br />
<br />
	실수부(c) = x<br />
	허수부(c) = y<br />
	크기(c) = sqrt( 실수부(c)^2 + 허수부(c)^2<br />
	각(c) = atan(허수부(c), 실수부(c))<br />
<br />
이 방법은 극 좌표 표현을 직각 좌표 표현으로부터 계산해 내기 때문에 곱셈 연산을 자주 하는 경우 계산 효율이 크게 떨어진다.본래 연산에 따라 더 적합한 표현을 선택할 수 있는 ‘표현 선택의 자유’를 제공하려는 목적을 만족시키지 못하지만 우선 사용자인터페이스를 설계하고 돌려 보는 용도에 적합하다. 그리고 곱셈을 별로 사용하지 않는다고 확신할 수 있다면 이 기법으로도충분하다. 일단, ‘프로그램은 돌아가고 봐야 된다’는 목표를 달성했으니, 좀더 유리한 표현 기법을 탐구하고 실험해 볼 수 있는적당한 시간을 번 셈이다.<br />
자, 이제 인터페이스에는 아무런 변화를 주지 않고(복소수를 사용하는 코드에는 아무런 영향을 주지 않아야 된다는 말이다), 서로다른 연산에 유리한 서로 다른 표현을 한 바구니에 담으려면(하나의 형처럼 취급하려면) 어떤 주문을 외어야 할까? 조사 결과사용자는 덧셈과 곱셈을 고루 사용하는 것으로 나타났고, 곱셈에 유리한 극 좌표 구현을 제공하지 않으면 계산 효율성을 개선할 수없다. <br />
SICP는 이런 문제의 해법으로 정책이 전혀 다른 세 가지 프로그래밍 기술인 Tagged Data, Data-DirectedProgramming, Message-Passing을 소개한다. 그러나 어느 것이 절대 유리하다고 편협한 판단을 강요하지않는다. 단지, 다음과 같은 질문을 던져 학생 스스로 상황에 따라 유리한 기법을 고를 수 있는 안목을 기르라고 소리 없이가르친다.<br />
<br />
◆ 추가 변동 사항이 없다면 가장 효율 있는 방법은 무엇인가?<br />
◆ 만일 직각 좌표, 극 좌표 외에도 새로운 복소수 표현을 추가할 필요가 있다면 어떤 기법이 가장 유리한가?(즉, 또 다른 표현이 필요하다고 해도 이미 만들어 놓은 코드를 전혀 손댈 필요가 없는 기법은 무엇인가?)<br />
◆ 만일 표현의 종류에는 변화가 없으나 연산을 새로 추가해야 한다면 어떤 기법을 쓰는 것이 가장 유리한가?(즉, 복소수 연산이 더 필요할 때 나머지 코드에 전혀 손상을 가하지 않는 기법은 무엇인가?)<br />
<br />
이 문제에 대한 해답은 독자들의 몫으로 남겨둔다. <br />
이제 책 내용에 대한 설명은 접고 SICP의 교육 철학에 대한 얘기를 마무리 짓도록 하자. <br />
SICP가 보기 드물게 훌륭한 예제를 풍부하게 제공한다는 점은 앞에서 이미 얘기했다. 그런데 이 책에서 좋은 예제가 차지하는역할이 하나 더 있다. 읽기 능력 훈련이 바로 그것이다. SICP는 다른 많은 프로그래밍 연습용 서적처럼 작은 문제를 바닥부터홀로 만들어 올라가는 방식을 취하지 않는다. 그보다는 어느 정도 규모를 갖춘 예제와 그 예제에 걸맞은 프로그램을 그 구조를보여주고 이를 완성하거나 개선하는 방식의 문제를 제시한다. <br />
배우는 이가 책이 제시하는 예제를 충분히 이해해 온전히 자기 것으로 소화하지 못하면 문제의 의도는 물론이고 적절한 답을 찾기어렵다. 이는 좋은 프로그래머라면 주어진 코드를 읽고, 그 동작 방식을 제대로 그려낼 줄 알아야 한다―즉, 프로세스 시각화능력을 갖추어야 한다―는 교육 의도를 충실히 반영하려는 노력이다. <br />
 <br />
SICP 현황과 문제점<br />
SICP의 철학과 우수성은 앞에서 충분히(물론 완벽할 수야 없지만) 설명했다고 본다. 이제 그 문제점과 대안을 알아볼 차례가됐다. 세상에 완벽한 해결책이란 없는 법이다. 우선 이 멋진 책(또는 과정)을 얼마나 많은 대학에서 쓰고 있는지 살펴보자.<br />
현재 SICP를 가르치는 대학은 약 100여개 정도 된다. 나라 별로 그 수가 많은 것부터 늘어놓아 보면 단연코 미국이 가장많다. 미국은 모두 93개 대학으로 컬럼비아, 코넬, 프린스턴, MIT(당연히) 등이 여기에 포함된다. 그리고 영국에서는옥스포드를 포함해 총 7개 대학, 독일은 9개 정도다. 이어서 이탈리아와 덴마크가 각 2개, 네덜란드·핀란드·벨기에·스페인이 각한 개씩인 것으로 되어 있다. <br />
아시아권은 그 수가 적다. 여기에는 우리나라도 물론 포함되어 있다. 일단 일본은 동경대, 싱가포르는 싱가포르 국립대에서 이과정을 채택하고 있고, 우리나라에서는 KAIST(이광근 교수), 고려대에서 채택하고 있다(그리고 등록되어 있지 않지만창원대(이수현 교수)에서 SICP를 가르치고 있다는 사실을 들어서 알고 있다). 또한 현재는 다른 과정으로 대체됐으나 한때 부산동아대학교에서 1995년부터 신입생 프로그래밍 강좌로 이 강좌를 개설해 한 해 5개 강좌 약 300명이 수강하기도 했다.<br />
총 100여개에 이르는 대학이 한 대학에서 개발한 과정을 채택하고 있다고 보면 여전히 많은 축에 속하기는 하지만 예전만큼‘강호를 평정’하고 있다고 하기는 어렵다. 지난 10여 년간 SICP를 채택하거나 적어도 Scheme을 실습 언어로 선택하는대학이 많이 줄어든 것이 사실이다. 이는 많은 대학에서 이 분야의 급격한 기술 변화를 무시하지 못하고 예전처럼 유행하는프로그래밍 언어를 가르치는 방식으로 돌아섰기 때문에 생긴 결과라 하겠다. 그러나 이런 슬픈 현상을 추세 탓으로만 돌릴 수는 없는법이다. SICP를 채택한 이후에 겪게 된 여러 가지 문제점이 그런 변절(?)의 빌미를 제공했다고도 볼 수 있기 때문이다. <br />
SICP의 문제점은 2002년에 발표된 참고자료 ?에 비교적 잘 설명되어 있다(SICP 방식의 교육에 깊은 관심이 있는사람이라면 그전에 참고자료 ?의 논문을 읽어 보는 것이 좋다). 이 논문에서 몇 가지 눈에 띌 만한 것을 나름대로 정리해 보면이렇다(아마도 SICP를 약 4장 정도까지라도 따라가 본 사람은 이 논문이 주장하는 바를 공감할 수 있을 것이다).<br />
SICP의 가장 큰 문제는 과정 자체가 너무 어렵다는 데 있다. 프로그래밍 자체가 어려운 것이야 당연한 것이지만 프로그래밍 기법을 설명하기 위해 드는 예제들이 문제다. <br />
SICP는 컴퓨터를 전공하는 학생들만을 위한 기초 서적이 아니다. 프로그래밍이 꼭 필요한 분야라면 전공에 관계없이 채택할 수있는 기초 기술 서적(또는 과정)이다. 특정 분야에 치우침 없이 고루 응용할 수 있는, 다양한 문제와 해법을 다루고 있기 때문에전산 전반에 걸친 기초 기술 모두를 한 번씩은 짚고 넘어간다고 봐도 틀린 얘기가 아니다. <br />
게다가 완성도가 높아서 분야별 사전 지식(domain knowledge)을 먼저 학습하지 않고서는 문제 자체를 이해할 수 없는경우가 대부분이다. 균형 잡힌 지도를 받지 못한다면 초심자들은 이 책이 전문 분야 지식과 프로그래밍 기법 중 어느 쪽에 중점을두고 있는지 알아차리지 못할 가능성이 높다. <br />
처음 배우는 이를 더욱 당혹스럽게 만드는 점은 이 책의 ‘보물찾기’ 식 내용 구성이다. 프로그램 설계를 그 어느 서적보다중요하게 다루지만 드러내어 떠들지 않는다. 너무 고상한 방법으로 목표를 달성하려고 하다가 선문답식 가르침이 되어버린 셈이다.가르치고자 하는 모든 것을 예제 속에서 엮어 놓았기 때문에 배우는 사람 스스로 그 참뜻을 찾아내려 애써야 한다. <br />
사실, 학생 대부분은 숨겨놓은 교육 의지(제대로 프로그래밍하기)를 찾아내지 못하고, 표면 지식(이를테면, 언어 그 자체나 특정응용 분야)에 더 중점을 두기 쉽다. 만일 가르치는 사람조차 그 의도를 충분히 알아차리지 못하면 당연히 이 문제는 더심각해진다. 내용상의 연계성을 고려하지 않고 교육 의도―‘왜 그렇게 프로그래밍하는 것이 옳은가’를 충분히 전달할 수 없다면,SICP는 주어진 예제를 단순히 풀어내려가는 평범한(그러나 아마도 아주 혹독한) 훈련으로 전락할 수 있기 때문이다(이런 문제때문에 이 과정을 제대로 이끌어갈 수 있는 교수진을 구성하기도 어렵다). <br />
<br />
HTDP와 Dr. Sheme<br />
『How To Design Programs』(이하 HTDP)는 앞에서 설명한 SICP의 여러 가지 문제점, 특히 다음과 같은 문제점을 개선하는 데 중점을 두고 만들어 낸 책(또는 교육 과정)이다. <br />
<br />
◆ 특정 분야 지식을 과하게 요구할 뿐만 아니라 그 지식을 설명하는 데 너무 많은 지면을 할애한다.<br />
◆ 프로그램 설계를 드러내 가르치지 않으므로 학생들에게 교육 목표를 제대로 전달하는 데 어려움이 많다.<br />
<br />
더 자세한 개발 동기 및 설계 원칙, 교수법 등에 대한 설명은 참고자료 ?에 잘 정리되어 있으므로 참고하기 바란다.<br />
HTDP를 쓴 저자들은 모두 PLT(Programming Language Technology,http://www.plt-scheme.org/who)라는 단체의 구성원들이다. PLT는 다양한 Scheme 구현을 제공할목적으로 만든 자원 단체로 현재 EdScheme 또 MzScheme 등을 개발해 배포하고 있다. 특히 이 그룹에서 개발한 Dr.Scheme은 재미있는 소프트웨어다. Dr. Scheme은 여러 Scheme 구현 위에 돌아가는 일종의 Scheme IDE라 할수 있는데, 애초부터 교육 용도로 개발된 것이다. 그래서 프로그래밍 훈련의 재미와 효과를 높일 수 있는 여러 가지 기능을 갖추고있다. SICP 같은 과정과 Dr. Scheme 같은 실습 소프트웨어는 정말 찰떡궁합이라 할 수 있다. <br />
<br />
HTDP와 우리 프로그래밍 교육<br />
필자는 우리나라의 많은 교육 기관이 이론 교육과 실무 기술 교육 사이의 균형점을 찾지 못하고 우왕좌왕하고 있다고 생각한다.컴퓨터 공학(과학)과 정보 처리학은 엄연히 다른 것인데도, 하나의 과정 속에 분별없이 섞어놓고, 학생들이 어디로 가야 할지해답의 실마리를 쥐어 주지 않는다. 취업 문제로 고민하는 학생들에게 나름대로 해결책을 제시하기 위해 실무 기술을 가르치겠다는의지 자체는 충분히 공감하는 바다. 그러나 기존 교육 체계는 그대로 두고서 실무 기술 교육을 강화하겠다는 것(교육 내용만 살짝바꿔치기하겠다는 것)은 헛된 바람이다. <br />
『The Pragmatic Programmer』(참고자료 ?)의 서문에 쓰인 말대로, 개발자 능력은 기초 컴퓨팅 이론 바탕 위에다양한 실무 프로젝트를 개발하는 경험이 쌓여서 배양된다. 설령 철저한 실무 교육을 목표로 하는 교육 기관이라 할지라도 기초 이론교육을 무시한다면 좋은 인력을 길러낼 수 없고, 이론 교육이라고 해도 실무 기술과 연계성을 주의 깊게 고려해 가르치지 않으면쓸모 있는 바탕 교육이라 할 수 없다.<br />
이런 점에서 HTDP가 추구하는 프로그래밍 교육의 원칙은 주목할 만하다. 프로그래밍의 원리 교육과 실무 기술 훈련이 하나의 과정속에 어떻게 배치되어야 하는지 한 가지 해법을 제안하고 있기 때문이다. 참고자료 ?은 HTDP가 추구하는 프로그래밍 교육 목표를다음과 같이 기술하고 있다. <br />
<br />
변하는 기술 환경에 빠르게 적응할 수 있고, 수십 년 동안 소프트웨어 관련 직종에서 살아남을 수 있는, 유능한 소프트웨어 개발 인력을 양성하는 것이 프로그래밍 교육의 목표다.<br />
<br />
너무 뻔한 얘기라서 식상하기까지 하지만, 우리네 교육기관 중 저 목표를 향해 땀 흘려 달리는 곳이 과연 몇 군데나 될까?참고자료 ?에서는 이와 같은 교육 목표를 달성하기 위해 다음과 같은 구조로 교육 과정을 구성하는 것이 바람직하다고 주장한다. 이제안에 따라 교육 과정을 그려보면 &lt;그림 1&gt;이 나온다.<br />
<br />
프로그래밍 커리큘럼은 근본 원리를 가르치는 데 중점을 두어야 한다. 그리고 첫 해 두 번째 학기와 마지막 학년에서 산업이 요구하는 기술에 적응할 수 있도록 실용 기술을 훈련한다.<br />
<br />
이와 같은 제안이 우리네 교육 기관이 처해있는 여러 가지 문제를 정말 해결해 줄 수 있는지를 함부로 판단할 수는 없는 법이다.그러나 SICP나 HTDP와 같은 해법이 프로그래밍 기술의 본질을 바로 알고 더 나은 프로그래밍 교육을 시도하는 가치 있는실천임에는 의문의 여지가 없다고 믿는다. <br />
<br />
독자에게 드리는 선물<br />
여기까지 글을 읽어준 독자에게 몇 가지 선물을 드릴까 한다. 이 글에서 소개한 두 권의 책은 모두 웹에 전문이 올라와 있다.<br />
<br />
◆ http://mitpress.mit.edu/sicp/<br />
◆ http://www.htdp.org<br />
<br />
앞에서도 말한 바 있지만 SICP를 제대로 익히려면 좋은 선생이 필요하다. 한데 다행스럽게도(그리고 매우 고맙게도) 저자(Harold Abelson) 및 다른 MIT 교수진의 SICP 강의를 동영상으로 보고 들을 수도 있다.<br />
<br />
◆ http://www.swiss.ai.mit.edu/classes/6.001/abelson-sussman-lectures/<br />
<br />
강의도 들을 수 있고 책도 마련했으니 이제 실습용 프로그래밍 환경만 있으면 완벽하다. 이왕 책이 권하는 대로 Scheme을써보기로 했다면, 다음 주소에서 Dr. Scheme을 내려받을 수 있다(실습 언어로 꼭 Sheme을 써야 하는 것은 아니지만,다른 언어를 쓴다고 해도 책을 읽고 예제를 풀기 위해 Scheme 코드는 정확히 읽고 이해할 수 있어야 한다).<br />
<br />
◆ http://www.drscheme.org<br />
<br />
이제 이 공개된 보물지도로 보물을 찾아 나설지 말지는 온전히 독자의 몫이다.    <br />
<br />
정리 | 송우일 | wooil@korea.cnet.com</span></td></tr></tbody></table></td></tr></tbody></table>			 ]]> 
		</description>
		<category>SICP</category>

		<comments>http://spore.egloos.com/4163401#comments</comments>
		<pubDate>Thu, 11 Jun 2009 17:08:49 GMT</pubDate>
		<dc:creator>vimming</dc:creator>
	</item>
</channel>
</rss>
