안녕하세요 워누입니다.

 

오늘은 그동안 포스팅했던 mkdir, fopen, fclose, fwrite 등을 활용해서 프로그램을 실행한 내용과 전달받은 데이터 등을 기록하는 로그파일을 만들어보는 방법을 포스팅 해보겠습니다. 

 

직전 포스팅에서 언급했던 것처럼 로그파일을 만드는 것은 개발자에게 꽤 중요한 작업이에요. 

귀찮더라도 초급 개발자분들은 이 과정을 꼭 한번씩 거쳐보시는 것을 권장합니다!

 

그럼 바로 시작해보겠습니다!

로그파일은 보통 프로그램 실행 중 정상 혹은 오류에 대한 기록을 잡기 위해 많이 사용합니다. 

그래서 보통 어떤 프로그램을 써먹어볼까 하다가 PHP로 간단한 계산기를 만들고, 계산기록을 메모장에 남겨보는 형태로 진행해보면 되겠다 싶어 바로 html로 요청 페이지를 만들고, php로 응답하도록 로직을 구성해 보았습니다! 

 


Code :: request.html 

<html>
<head>
 <title> PHP 계산기 TEST </title>
</head>
<body>
 <form method="post" action="response.php">
  사칙 연산 : 
  <select name="Calculator">
    <option value="Addition" selected>더하기</option>
    <option value="Subtraction">빼기</option>
    <option value="Multiplication">곱하기</option>
    <option value="Division">나누기</option>
  </select>
  <br>
  첫번째 숫자 : 
  <input type="text" name="FirstNum" value="" /><br>
  두번째 숫자 : 
  <input type="text" name="SecondNum" value="" /><br>
  <input type="submit" value="Submit" />
 </form>
</body>
</html>

UI :: request.html

request.html


일단은 간단하게 두개의 수만 받아서 더할 것인지, 뺄 것인지, 곱할 것인지, 나눌 것인지를 구성해보았습니다. 

요청은 이렇게 구성하고, 다음은 결과를 구성한 코드와 화면을 볼까요?

 


Code :: Response.php

<?php 

//전달받은 데이터를 변수로 저장 
$Calc = $_POST['Calculator'];
$num1 = $_POST['FirstNum'];
$num2 = $_POST['SecondNum'];

//계산한 두 수의 결과값을 저장할 변수 선언
$result = "";

//오늘의 날짜를 변수로 저장 
$logDate = date("Ymd");

//log 폴더 생성 
$dirName = "log";
$isDir = is_dir($dirName);

if($isDir){					//log 폴더가 존재하는 경우
	opendir($dirName);		//log 폴더 열기
} else {					//그렇지 않으면
	mkdir($dirName);		//"log" 폴더 새로 만들기
}

//로그파일 생성. 파일명은 오늘날짜. 
$fileName = $logDate.".log";

//로그파일 열기 
$fp = fopen("./log/".$fileName, 'a+');

//로그파일 기록 시작.
fwrite( $fp,"************************************************\r\n");
fwrite( $fp,"계산시작일시	: ".date("YmdHis")."\r\n");
fwrite( $fp,"num1		: ".$num1."\r\n");
fwrite( $fp,"num2		: ".$num2."\r\n");
fwrite( $fp,"연산기호		: ".$Calc."\r\n");

//사칙연산(+,-,*,/) 요청 값에 따라 구분하여 처리.
switch($Calc){
	case("Addition"):
		$result = $num1+$num2;
		break;
	case("Subtraction"):
		$result = $num1-$num2;
		break;
	case("Multiplication"):
		$result = $num1*$num2;
		break;
	case("Division"):
		$result = $num1/$num2;
		break;
}

//계산결과를 화면에 전달.		
echo "계산결과 :".$result."<br>";

fwrite( $fp,"결과		: ".$result."\r\n");
fwrite( $fp,"************************************************\r\n");

//로그파일 종료
fclose($fp);
?>

UI :: response.php

response.php


요청한 계산에 대한 결과를 이렇게 확인할 수 있었습니다!

계산은 제대로 되었는데 과연 로그 파일은 잘 작성되었는지 한번 보겠습니다. 

 

1. 계산 요청 전 php_prac 폴더의 상태.

기존의 폴더 상태

2. 계산 요청 후 php_prac 폴더의 상태.

더하기 계산 후 폴더 상태

3. log 폴더 상태.

log 폴더 상태 -> log파일이 정상적으로 생성됨.

일단 결과적으로도 잘 생성이 되었네요! 

그럼 로그폴더 안의 txt도 잘 기록되었는지 봅시다. 

 

더보기

************************************************
계산시작일시 : 20210125004605
num1 : 2
num2 : 5
연산기호 : Addition
결과 : 7
************************************************

20200125.log 안의 내용물을 그대로 복사해서 가져왔습니다. 

해당 로그 기록의 요청은 response.php 파일 내 fwrite()부분을 그대로 기재한 것을 볼수가 있네요! 

결과적으로 요청 값을 잘 기록했고, log파일이 생성된 시간과 log폴더 안에

계산 시작일시 시간도 일치하는 것을 볼수 있습니다!

 

혹시나 몰라 1분 내로 곱셈도 한번 더 진행했습니다. 

request.html
response.php

역시나 웹 페이지에 결과가 잘 기재되었네요!

그럼 아까 폴더 경로로 가서 파일이 잘 생성되었는지 봅시다. 

log 폴더 -> 수정한 날짜에 찍힌 시간이 46분에서 47분으로 바뀜

일단, 시간이 업데이트 된걸로 봐서 기록이 잘된것 같네요!

그럼 안의 내용물은 어떤지 한번 볼까요?

더보기

************************************************
계산시작일시 : 20210125004605
num1 : 2
num2 : 5
연산기호 : Addition
결과 : 7
************************************************
************************************************
계산시작일시 : 20210125004750
num1 : 9
num2 : 10
연산기호 : Multiplication
결과 : 90
************************************************

안의 내용물도 잘 업데이트 되었네요! 

계산시작일시가 47분 50초로 적혀 있습니다! 

 

이렇게 로그 파일을 잘 남겨두면, 내가 프로그램을 실행한 시간과 요청했던 데이터,

프로그램 실행 시 이슈 등을 파악하는데 매우 용이하게 사용할 수 있습니다. 

 

로그파일 형식은 굳이 저렇게 안하고 개발자 본인이 작성하고 싶은대로,

그러나 필요한 내용은 반드시 기재하는 용도로 체크해두시면 나중에 조금 더 깊게 개발하실 때 큰 도움이 되리라 생각해봅니다. 

 

오늘 포스팅한 내용도 읽어주신 여러분께 도움이 되길 바라며, 여기서 마치겠습니다! 

감사합니다 ㅎㅎ

안녕하세요 워누입니다! 

오랜만에 tistory 블로그를 작성하네요 ㅎㅎ

회사일과 네이버 블로그를 동시에 병행하다 보니 정신이 없지만, 힘내서 포스팅을 진행해보겠습니다!

이번 포스팅에서는 PHP에서 시간을 표시하는 date() 함수에 대해서 알아보겠습니다. 

 

우선 PHP에서 시간을 표시할 때 아래와 같이 작성합니다. 

 

date(시간 포맷)

시간 포맷이라는 알고 싶은 시간의 단위값(연도 또는 월일, 요일)을 입력합니다. 

어떤 형식인지 아래 표를 같이 보시죠!

(예시 데이터는 2021년 1월 18일을 기준입니다.)

문자 의미 예시
Y 연도를 4자리로 표시 2021
y 연도를 2자리로 표시 21
m 0이 붙은 상태로 월을 표시 01
n 0 없이 월을 표시 1
d 0이 붙은 상태로 일을 표시 18
j 0 없이 일을 표시 18
H 0이 붙은 상태로 시를 표시(24시 표현) 01
G 0 없이 시를 표시(24시 표현) 01
i 0이 붙은 상태로 분을 표시 56
s 0이 붙은 상태로 초를 표시 55
A 오전, 오후를 대문자로 표시 AM
a 오전, 오후를 소문자로 표시 am
D 요일을 세글자로 표시 Mon
l(소문자 엘) 요일을 전체 글자로 표시 Monday
w 요일을 숫자로 표시(0~6, 0:일요일, 6:토요일) 1
M 월을 세글자로 표시 Jan
F 월을 전체 글자로 표시 January
z 올해 1월 1일부터 며칠 지났는지 표시 17

 

각각 대소문자를 구별하고 기능이 다르므로 사용 시 주의하셔야 합니다. 

설명도 다 했으니 이제 예시 데이터를 만들어봅시다!

(date.php라는 파일명으로 아래와 같이 샘플을 작성해봅시다.)

<?php 

//시간 표시 (연도, 월, 일, 시, 분, 초) : 0이 붙어 있는 예시
echo date("Y년 m월 d일 H시 i분 s초")."<br>";

//시간 표시 (연도, 월, 일, 시, 분, 초) : 0이 붙어 있지 않은 예시
echo date("y년 n월 j일 G시 i분 s초")."<br>";

//오전 오후 여부
echo date("A")."<br>";
 
//요일 표기
echo date("D")."<br>";

//올해가 며칠 째인지 표기
echo date("z")."<br>";
?>

결과는 아래와 같이 조회됩니다. 

date.php 실행 결과

생각보다 간단하죠?

date() 함수 안에 괄호에서 큰따옴표(")를 사용하고 그 안에서 문자열로 표기되고, 

표에서 설명한 문자열이 아닌 다른 문자열은 그대로 표기가 되는 것으로 보여집니다. 

.

php를 배우시는 분들이라면, date() 함수를 자유자재로 계속 테스트 해보시길 권장 드립니다. 

 

이번 포스팅에서는 여기서 짧게 마치고, 다음 포스팅에서는 로그(log)라는 파일을 만들어볼건데요,

개발자라면 자신이 만든 프로그램에서 어떠한 이벤트가 발생했을 때 그에 대한 기록들을 남겨두기 때문에 

오늘 포스팅에서 배운 date() 함수를 포함하여 그동안 포스팅을 통해 알려드린 mkdir, fopen, fclose, fwrite 기능을

이용해서 실제 현업에서 써먹는 방법을 간략하게 전달드리도록 하겠습니다!

 

그럼 오늘은 여기서 20000!!

 

 

안녕하세요 워누입니다. 

 

그동안 네이버 블로그에 글을 쓰느라 tistory는 방치를 시켜놨네요 ㅜㅜ 

다행히(?) tistory에도 글을 써야지하고 다짐은 하고 있었는데, 드디어 오늘 포스팅하게 되었습니다 ㅎㅎ 

 

오늘은 지난번에 txt 파일을 생성해보고 읽어오는 것도 해봤으니,

이번에는 파일이 아닌 폴더를 생성하고, 삭제하는 것 기능을 포스팅해볼게요. 바로 시작해봅시다!

.

php에서 폴더를 생성하는 함수는 mkdir입니다!

우선 예제 소스를 보면서 어떻게 사용하는지 감을 잡아봅시다!!

.

<생성할 폴더명을 받을 html 페이지 : mkdir_req.html>

<html>
<head>
 <title> PHP 폴더 만들기 테스트 </title>
</head>
<body>
 <form method="post" action="mkdir_res.php">
  생성할 폴더명 : 
  <input type="text" name="ReqData" value="" /><br>
  <input type="submit" value="Submit" />
 </form>
</body>
</html>

<폴더를 생성하는 php 페이지 : mkdir_res.php>

<?php 

//req html 페이지로부터 전달받은 데이터 저장
$dirName = $_POST["ReqData"];

//폴더 생성
$makeDir = mkdir($dirName, '777');

//폴더 생성 여부 확인
if($makeDir){
	echo $dirName." 폴더 생성 완료!";
}
else {
	echo $dirName." 폴더 생성 실패!";
}

?>

<실행 결과>

mkdir_req.html 페이지

 

mkdir_res.php 페이지
test 폴더 생성

.

html 페이지에서 입력한 'test'라는 이름으로 폴더가 정상적으로 생성된 것을 확인할 수 있네요! 

 

html 페이지는 단순히 생성할 폴더명을 받는 페이지고,

지난번 txt 파일 생성하는 포스팅에서도 한번 언급했으니 넘어가겠습니다.

 

mkdir_res.php 페이지를 보시면 mkdir 함수가 보이실텐데요! 두가지 매개변수($dirName, '777')를 가지고 있습니다! 

mkdir 함수에 들어가는 매개변수는 아래와 같이 설정해주어야 합니다.

 

mkdir(경로 및 생성할 폴더 이름, 퍼미션 설정값)

 

위에서 언급한 매개변수 중 퍼미션(permission)이라 함은 권한을 말하는데요, 3자리의 숫자로 구성됩니다. 

첫번째 자리 두번째 자리 세번째 자리
소유자 권한 그룹 권한 사용자 권한

여기서 소유자는 파일 혹은 폴더 생성하는 사람, 그룹은 소유자가 속한 그룹(혹은 같은 그룹원), 사용자는 폴더를 사용하는 사람(보통 유저)을 의미합니다. 각 권한은 읽기(read), 쓰기(write), 실행(execute)으로 구성됩니다. 

읽기(read) 쓰기(write) 실행(execute)
4 2 1

표를 보면서 정리하면, 읽기 권한을 적용하려면 4, 쓰기 권한을 적용하려면 2, 실행 권한을 적용하려면 1을 입력합니다. 

 

읽기+쓰기 권한을 같이 주고 싶다면 6, 읽기+실행 권한을 같이 주고 싶다면 5,

읽기+쓰기+실행 권한을 모두 주고 싶다면 7을 입력해주시면 됩니다. 

 

윈도우에서는 파일을 오른쪽 버튼 클릭해서 나오는 속성 창에서 보안 항목을 통해 직접 권한을 줄 수도 있습니다. 

.

윈도우 속성 창에서 사용권한 부여

일단 저는 테스트이기도 하고, 보안적으로 문제될 것도 없어서 777로 설정을 하였으나

회사에서는 보안적인 이슈를 위해 755나 744 등으로도 쓰이니 용도에 맞게 권한 설정을 해주시면 될 것 같습니다. 

 

mkdir 함수에 대한 설명은 이정도로 하면 될 것 같습니다ㅎㅎ

이번엔 mkdir 함수로 만든 폴더를 rmdir()이라는 함수로 삭제해보도록 하겠습니다!

 

rmdir 함수는 아래와 같이 사용하면 됩니다! 

rmdir(삭제할 폴더 이름)

정말 단순하죠? 예제 소스도 그냥 단순하게 작성해서 테스트 해보았습니다. 

.

<test 폴더를 삭제하는 php 페이지 :  rmdir.php>

<?php

//폴더 삭제
$removeDir = rmdir('test');

//폴더 삭제 여부 확인
if($removeDir){
	echo "폴더 삭제 완료!";
}
else {
	echo "폴더 삭제 실패!";
}

?>

<실행 결과>

 

rmdir.php 페이지
test 폴더 삭제 확인

.

생성했던 test 폴더가 삭제되고 그동안 블로그에 기재하기 위해 작성하였던 파일들만 남아있네요! 

 

오늘은 이렇게 php로 폴더를 생성하고 삭제하는 방법을 작성해보았는데요! 

다음 포스팅에서는 이전에 포스팅했었던 php로 txt 파일을 생성하는 방법과, 오늘 포스팅한 폴더 생성하는 방법으로 

간단하게 날짜에 맞게 로그파일을 생성하는 방법을 포스팅해보겠습니다!

 

그럼 오늘은 여기서 마무리해볼게요~ 긴 글 읽어주셔서 감사합니다!

안녕하세요 워누입니다! 

오늘은 제가 회사에서 개발하다가 궁금한 점이 부딪혀서 직접 알아본 내용을 포스팅하고자 합니다. 

.

상황은 API 호출 시 특정 URL로 form-data를 post로 던지고 그 결과를 받아오는 로직입니다!

 

1. file_get_contents

//Post api call
function reqPost($data, $url){
	$requestData = stream_context_create(array(
		'http' => array(
			'method' => 'POST',
			'header' => 'Content-type:application/x-www-form-urlencoded;charset=euc-kr',
			'content' => $data,
			'timeout' => 15
		)
	));
	
	$response = file_get_contents($url, FALSE, $requestData);
	return $response;
}

 

2. curl

//Post api call
function reqPost(Array $data, $url){
	$ch = curl_init();
	curl_setopt($ch, CURLOPT_URL, $url);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15);	//connection timeout 15 
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
	curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));	//POST data
	curl_setopt($ch, CURLOPT_POST, true);
	$response = curl_exec($ch);
	curl_close($ch);	 
	return $response;
}

API를 호출하는 방식의 차이이고, 제가 적용한 소스에서 두 방식 모두 결과는 같습니다!

 

그렇다면 대체 뭐가 다른지 알아야 다른 모듈을 개발하면서 API를 호출할 때,

file_get_contents()를 쓸지, curl을 쓸지 쉽게 결정하겠죠? 

 

일단 file_get_contents()과 curl은 함수/라이브러리라는 개념적인 차이점이 있습니다. 

표로 아래와 같이 정리해볼 수 있겠습니다. 

명칭 구분 설명
file_get_contents() 함수 전체 파일을 문자열로 읽어오는 함수. php 4.3부터 7.x버전까지 사용 가능

*매개변수 ($filename, [$use_include_path, $context, $offset, $maxlen])
[] : 옵션 매개변수
$filename : 읽어올 파일명 or URL
$use_include_path : 파일 내 참조된 내용까지 읽어올지 여부 결정. 
$context : stream_context_create()로 작성된 유효한 컨텍스트 리소스. 
$offset : 몇 번째 데이터부터 읽을건지 설정.
$maxlen : 얼만큼 데이터를 읽을건지 length(길이)를 설정.
curl 라이브러리 다양한 프로토콜을 이용하여 데이터를 주고받는 기능 제공.
http, https, ftp, gopher, telnet, dict, file, ldap 등의 프로토콜 지원.

*함수
curl_init : curl 초기화 
curl_setopt : curl 데이터 옵션 설정 
 <예시>
 CURLOPT_URL : 통신할 URL 설정
 CURLOPT_RETURNTRANSFER : 요청 결과를 문자열로 반환 
 CURLOPT_CONNECTTIMEOUT : 요청 시 최대 Connection timeout 설정
 CURLOPT_SSL_VERIFYPEER : 원격 서버의 인증서가 유효한지 체크
 ...
curl_exec($ch) : curl_setopt를 통해 설정된 $ch에 대하여 통신을 실행하는 함수.
curl_close($ch) : curl $ch 종료함수.

이렇게 보니까 차이가 좀 크네요! 확실히 curl이 좀더 복잡해보입니다.

만약 두개가 서로 차이점이 없다면, 굳이 복잡한 curl을 쓸 필요가 없겠지만

php 개발자들이 가급적 curl을 선호하는 이유가 있습니다! 검색해서 찾아보고 정리해보았습니다.

 

1. file_get_contents()를 사용할 경우, 로그인이 필요하지 않은 페이지의 URL만 확인 가능하며, 읽어올 대상 페이지의 서버 혹은 소스에 allow_url_fopen 옵션이 활성화되어 있어야 합니다. 

그러나 이마저도, 최근에 allow_url_fopen 옵션에 대하여 보안문제가 이슈가 되어 php 개발자들이 해당 기능을 잘 사용하지 않는다고 하니 file_get_contents()를 사용하기가 점점 어려워 지고 있습니다.

 

2. curl_setopt를 통해 사용할 수 있는 설정들이 다양합니다. 범위가 함수냐, 라이브러리냐의 차이이기 때문에 간단한 기능이라면, file_get_contents()를 쓰겠지만 다양한 기능을 쓴다면 당연히 curl로 처리하는게 더 좋겠죠?

 

3. 같은 옵션, 같은 함수를 반복적으로 호출할 시 속도면에서 약 15~30%정도 차이가 나는 것을 확인하였습니다.

이거는 제가 체험해봐서 아는 거라 자세히 설명하기가 어렵네요..ㅜ 직접 소스를 돌려보고 차이를 느껴보셔야 합니다...!!

 

위와 같은 이슈로 요즈음의 php 개발자들은 데이터를 읽어오고 통신하는 부분에서는 curl을 더 선호한다고 합니다! 

그래도 단순 파일 읽어오기 혹은 보안 이슈가 필요없는 URL 호출을 사용한다면 file_get_contents()를 이용해서 데이터를 읽어와도 될 것 같습니다. 

 

PHP를 사용하시는 개발자라면 두 가지 방식 다 알아둔다면 적재적소에 써먹을 수 있을 것 같네요 ㅎㅎ

도움이 필요하신 분들이 이 글을 읽어서 도움이 되기를 바라며 오늘 포스팅은 여기서 마치겠습니다! 

 

긴 글 읽어주셔서 감사합니다!

 

 

 

안녕하세요 워누입니다!

최근에 회사에서 후임들과 소스리뷰를 진행하는데 확실히 Java를 야매(?)로 공부하다보니, 대략적으로 이 함수가 어떤 용도인지만 알고 있었을 뿐, 저 역시도 원론적인 개념이나 어떻게 사용하는지 방법 등을 정확하게 알지 못함을 다시 한번 깨닫게 되더군요.. 항상 검색하면서 공부하고 개발하다 보니 정리가 안된 것들이 많은 것 같습니다. 그래서 이번 포스팅과 다음 포스팅은 제가 개발하면서, 그리고 남이 개발한 걸 보면서 헷갈렸던 개념인 컬렉션 프레임워크(collection framework)에 대하여 작성해보도록 하겠습니다! 

.

일단 컬렉션 프레임워크(collection framework)를 정의하려면, 컬렉션(collection)과 프레임워크(framework)를 나누어서 살펴보아야 합니다. 

 

컬렉션(Collection) : 요소를 수집해서 저장하는 것을 말하며, 자바 컬렉션은 객체를 수집해서 저장하는 역할.

프레임워크(Framework) : 사용 방법을 미리 정해 놓은 라이브러리를 말함 (자주 쓰이는 말이니 꼭 알아두시길!)

 

컬렉션과 프레임워크를 정의하고 보니 컬렉션 프레임워크는 아래와 같이 정의할 수 있겠군요!

 

컬렉션 프레임워크(collection framework) : 객체를 수집해서 저장하는 역할에 대한 사용 방법이 미리 정의된 라이브러리

 

보통 저를 포함해서 초급 개발자들이 주로 하는 실수들은 객체를 저장해두고, 필요할 때 꺼내쓸 때 주로 배열을 쓰는 경우가 많습니다! 배열이 아무래도 쉽게 생성하고 사용할 수 있지만, 아무래도 저장할 수 있는 객체 수가 지정되어 있다 보니, 불특정 다수의 객체를 저장하기에는 문제가 있죠. 

(배열의 길이를 무작정 크게 생성하는 방법도 있지만 이 역시 불필요한 공간을 만들어버리는 거니까 좋은 방법이 될 수 없습니다.)

또 배열을 사용하다가 중간에 객체를 삭제하게 되면 해당 index가 비워지는데 이후에 새 객체를 만들어 저장하려면, 어디가 비어있는지 확인하는 코드를 또 만들어야 해요. 

-> 쉽게 말하면 공간 문제와 삭제 후 생성 같은 문제가 너무 커서 "배열은 비효율적이다." 라고 보시면 됩니다. 

 

이걸 해결하려고 자바는 자료구조를 바탕으로 객체들을 효율적으로 추가, 삭제, 검색(객체 수집, 저장을 포함한 역할)할 수 있도록 java.util 패키지에 인터페이스와 클래스들을 포함(라이브러리를 미리 정의해 놓음)시켜 놓았는데 이것들이 바로 컬렉션 프레임워크들입니다! 

 

글이 너무 길지만 한번 읽고 사용하면 이해가 훨씬 빠를거에요! (저도 찾아보면서 개념을 이해했습니다..3년간 뭐했니..)

 

컬렉션 프레임워크에서 사용하는 주요 인터페이스(interface)는 List, Set, Map 세가지가 있습니다.

 

이 중에서 List와 Set 인터페이스는 모두 컬렉션(Collection) 인터페이스를 상속받기 때문에 List와 Set의 공통된 부분은 컬렉션 인터페이스에서 정의하고 있는데, Map 인터페이스는 키(key)와 값(value)을 쌍으로 묶어서 관리하는 구조라서 List와 Set과는 사용방법이 완전히 다릅니다. 

 

이 인터페이스들의 특징들을 아래 표로 정리하고 구조도를 그려보았습니다.

.

인터페이스 분류 특징 구현 클래스
Collection List<E> - 순서를 유지하고 저장
- 중복 저장 가능
ArrayList, Vector, LinkedList
Set<E> - 순서를 유지하지 않고 저장
- 중복 저장 불가
HashSet, TreeSet
Map <K,V> - 키와 값이 한 쌍이 되어 저장
- 키는 중복 저장 불가
HashMap, Hashtable,
TreeMap, Properties

.

 

 

Collection Framework Diagram

.

표와 구조도에 작성된 구현 클래스들은 각 인터페이스에서 제공해주는 클래스들입니다. 인터페이스를 사용한다면 그 안에 미리 구현되어 있는 클래스들을 가져와서 사용할 수 있다는 것인데요, 이는 프레임워크를 자주 사용하다 보면 익숙해질 겁니다 ㅎㅎ 

.

오늘은 컬렉션 프레임워크에 대한 개념과 특징들을 이렇게 정리해 보았는데요! 역시 야매로 알고 있는 것보다는 직접 정리하면서 찾아보는 것이 개발할 때 많이 도움이 되는 것 같습니다 ㅎㅎ 다음 포스팅에서는 예제 소스를 가져와서 어떻게 사용하는지 정리해보도록 하겠습니다! 

 

그럼 이만~~~~!

블로거 워누입니다. 

 

지난번 포스팅에 이어 String 메소드에서 제공하는 equals에 대해서 포스팅하고자 합니다! 

equals는 문자열을 비교할 때 사용하는 메소드입니다. 이 메소드를 이용해서 서로 다른 문자열 타입 변수의 문자열을 서로 비교합니다. 

....

그런데 말입니다.. 우리가 일반적으로 변수 타입을 비교하려면 같다는 의미의 이항연산자인 "==" 연산자를 통해서 많이 비교하는데, 문자열은 굳이 equals를 쓸 필요가 있을까요?

 

 

확인을 위해 직접 실험해 보았습니다. 우리에게 늘 익숙한 Hello 시리즈로 소스코드를 만들었습니다.


[equalsPrac.java 소스코드]

public class equalsPrac {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		String str1 = new String("HelloJava");
		String str2 = "HelloJava";
		String str3 = "HelloJava";
		
		if(str1 == str2) 
			System.out.println("같은 문자열");
		else 
			System.out.println("다른 문자열");
		
		if(str2 == str3) 
			System.out.println("같은 문자열");
		else 
			System.out.println("다른 문자열");
		
	}

}

결과는 아래와 같이 나옵니다. 

equalsPrac.java 실행화면

.

.

.

?

분명 똑같이 비교연산자를 썼는데 str1과 str2가 왜 다른걸까요..?

(대학교에서 이 내용을 가르쳐주지 않았습니다. 교수님이 몰랐을수도...ㅎ)

 

사실 자바는 문자열 값이 완전히 똑같으면, 동일한 String 객체를 참조합니다. 즉, str2와 str3는 같은 객체라는 것인데요, 반면 str1은 new 연산자를 사용하는 바람에 다른 String 객체를 참조하게 되버린 것입니다.

 

쉽게 말하면 클래스를 하나 만들어놓고 객체를 따로 만들어놓은 것처럼 말이죠!

.

Class cl1 = new Class();

Class cl2 = new Class();.

.

대충 이런 느낌인데 여기서 cl1과 cl2는 완전히 다른 객체인 것처럼, str1과 str2, str3 사이도 마찬가지라고 합니다. 

 

이런 경우, "=="을 사용하면 다른 객체간 문자열 비교가 불가능하겠죠?

이래서 equals를 사용합니다. 

 

이번엔 지난 포스팅에서 사용했던 substring() 메소드까지 같이 써서 비교해볼게요!

 


[equalsPrac2.java 소스코드]

public class equalsPrac2 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		String str1 = new String("Java");
		String str2 = "Java";
		String str3 = new String("HelloJava");
		String str4 = "HelloJavaProject";
		
		if(str1 == str2) 
			System.out.println("같은 String 객체를 지정");
		else
			System.out.println("다른 String 객체를 지정");
		
		if(str2.equals(str1))
			System.out.println("같은 문자열");
		else 
			System.out.println("다른 문자열");
		
		if(str3.substring(5).equals(str1))
			System.out.println("같은 문자열");
		else 
			System.out.println("다른 문자열");
		
		if(str4.substring(5,9) == str2)
			System.out.println("같은 String 객체를 지정");
		else
			System.out.println("다른 String 객체를 지정");
		
		if(str4.substring(5,9).equals(str2))
			System.out.println("같은 문자열");
		else 
			System.out.println("다른 문자열");
		
	}

}

이번 결과는 아래와 같이 나옵니다.

equalsPrac2.java 실행결과

.

어떤 느낌인지 대략 감이 오시나요..? "==" 연산자를 사용해버리면 객체의 값만 비교하는게 아니라 객체 동일 여부까지 따지게 되서, 문자열 비교할 때 원하는 값을 가져오지 못할 수도 있습니다.

이전 포스팅에서 언급한 것처럼 자바에서의 String은 단순한 문자열 타입 변수가 아닌 Class로 분류되기 때문에

문자열의 값 자체를 비교할 때는 비교 연산자 "=="이 아닌 equals() 메소드로 비교해야 정확한 값을 가져올 수 있습니다. 

(이거땜에 회사에서 쓸때없이 잡아먹은 시간이 얼만지 모르겠습니다...)

 

만약 이 글을 읽으시는 초급개발자분들은 예시를 보면서 직접 소스도 짜보고 여기저기 바꿔가면서 테스트 해보셨으면 좋겠습니다! 그래야 저처럼 버리는 시간 없이 효율적으로 개발하실 수 있거든요... ㅎ

 

오늘 포스팅은 여기까지 작성하고 다음 포스팅에서 뵙겠습니다 ㅎㅎ

워누입니다!

 

오늘은 Java 공부를 하다가 많이 헷갈리는 개념이 있길래 개념도 정리할 겸, 자주 쓰이는 것도 연습해볼 겸 블로그를 포스팅해보겠습니다. 

 

보통 모든 프로그램에서 문자열(문자들의 집합)은 많이 쓰이는데요, 자바에서는 문자열을 위한 String이라는 클래스를 별도로 제공합니다.

 

보통 String을 학생 때에는 변수 타입 중 하나라고만 생각하겠지만 자바에서는 이렇게 접근해버리면 개발하다가 100%의 확률로 오류가 발생합니다. (String 인스턴스는 한 번 생성되면 그 값을 읽기만 할 수 있고, 변경할 수는 없다고 합니다!)

어떤 말이냐면, 자바에서 덧셈(+) 연산자를 이용하여 문자열 결합을 수행하면, 기존 문자열의 내용이 변경되는 것이 아니라 내용이 합쳐진 새로운 String 인스턴스가 생성되는 것입니다.

 

String 클래스는 java.lang 패키지에서 제공하며, 문자열과 관련된 작업을 할 때 유용하게 사용할 수 있는 다양한 메소드가 포함되어 있습니다. 

자바에서 필요한 메소드를 찾는다면 하기 링크를 통해서 더 편하게 찾을 수 있습니다. 

(https://docs.oracle.com/javase/8/docs/api/)

 

어찌 되었든, Java를 사용하는 개발자라면 String 클래스를 이해하고, 문자열을 생성하는 방법부터 추출, 비교, 찾기, 분리, 변환 등을 제공하는 메소드를 익혀두면 차후 개발 시에 매우 유용하게 쓸 수 있습니다. 

 

개념은 이정도만 정리하도록 하겠습니다.(역시 개념은 지루해..)

 

오늘은 String을 통해 제공되는 메소드 중 trim(), substring(), charAt()을 써보고자 합니다. 

앞으로도 종종 String 메소드를 소개해드릴 일이 많을 것 같거든요 ㅎㅎ 

String 클래스의 인스턴스 변수 선언 후 .만 찍었는데 이렇게 많은 메소드들이...ㄷㄷㄷㄷㄷㄷ

많기는 더럽게 많죠?? 저 중에서 제대로 쓰는건 없겠지라고 생각했는데.. 

(아마 Java 복습하기 글들 둘러보시면 은근 String 메소드들을 썼더라구요..모르면서 쓰다니..)

 

오늘은 제가 공부 겸, 토이 프로젝트에서 써먹는 코드 중 핵심만 빼서 가져와보았습니다. 

 


public class strMethodPrac {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		String ssn = "9503071234567"; 	// 주민번호
		String name = "     워누";
		String newName = name.trim();
		
		System.out.println("이름 :" + name);	
		System.out.println("trim처리한 이름 :" + newName);
		
		String birth = ssn.substring(0, 6);
		char gender = ssn.charAt(6);
		
		switch(gender) {
			case '1':
			case '3':
				System.out.println(newName + "님은 남자입니다.");
				break;
			case '2':
			case '4':
				System.out.println(newName + "님은 여자입니다.");
				break;
		}
	}
		
}

 

 

 

 

 

그럼 소스코드를 실행한 결과부터 우선 보도록 하겠습니다. 

.

strMethodPrac 클래스 실행 결과

.

 

간단하지만 이런 처리결과를 가지고 회사든, 프로젝트든 많이 쓰이고 있습니다! 

그럼 이제 메소드에 대해서 가볍게 설명을 드릴게요! 

 

1. trim()

 

맨 먼저 쓰인 trim() 메소드는 앞뒤 공백을 제거해주는 역할을 합니다. 
그래서 name에 있던 "     워누"라는 값은 newName.trim()으로 처리하여 앞의 공백이 제거되어 "워누"라는 값으로 반환됩니다. 

 

2. substring()

 

substring() 메소드는 문자열을 잘라내주는 역할을 하며, 아래와 같은 형태로 쓰입니다.


substring(포함할 인덱스 번호, [제외할 인덱스 번호])

만약, [제외할 인덱스 번호]의 값을 채워주지 않는다면 끝까지 다 가져올 것입니다. 
예시에 나와있는 소스코드를 보면 저는 0번째를 포함해서 6번째를 제거했으니 아래와 같이 결과를 반환합니다. 

 9  5  0  3  0  7   1  2  3  4  5  6  7   -> 문자열(ssn)
 0/ 1/ 2/ 3/ 4/ 5/ 6/ 7/ 8/ 9/10/11/12  -> Index 번호

ssn.substring(0,6) -> 950307

 

제 개인 프로젝트에서는 이렇게 주민번호 앞 6자리를 가져와 생년월일을 검증하도록 하고 있습니다!

 

3. charAt()


charAt() 메소드는 괄호 안에 매개값으로 주어진 인덱스의 문자를 가져오며 아래와 같은 형태로 사용됩니다. 


charAt(인덱스 번호)

예시에 나와있는 소스코드를 보면 저는 6번째를 가져왔으니 (주민번호 뒷 7자리중 첫자리)
성별을 구분하는 값으로 사용하도록 아래와 같이 결과를 반환할 수 잇습니다. 

 9  5  0  3  0  7   1  2  3  4  5  6  7   -> 문자열(ssn)
 0/ 1/ 2/ 3/ 4/ 5/ 6/ 7/ 8/ 9/10/11/12  -> Index 번호

charAt(6) -> 1

 

쉽게 설명을 드렸다고 생각하지만 어렵게 느껴지셨다면 직접 소스코드를 작성해보시면서 계속 연습해보셔야 합니다!

그래야 익숙해지거든요ㅎㅎ (아는 애가 이러고 있냐..)

 

String 클래스에서 제공하는 메소드가 많아서 아마 "문자열 가지고 놀기"라는 제목으로 가끔씩 포스팅이 올라올 것입니다. 중, 고급 개발자분들은 잘 아셔서 지루하시겠지만 저와 같이 초급 개발자거나, 이제 막 입문하신다면 꼭 도움이 되셨길 바랍니다 ㅎㅎ 오늘 포스팅은 여기서 마치도록 하겠습니다!

워누입니다! 

오늘은 어제 포스팅한 파일 쓰기에 이어서 파일을 읽는 방법을 포스팅해보고자 합니다! 

파일을 작성하는 것 만큼 읽어오는 것도 중요하게 쓰입니다!

이것도 잘 익혀두면 필요할 때마다 유용하게 쓸 수 있거든요ㅎㅎ

 

txt 파일 쓰는 방법은 어제 포스팅(https://seoneu.tistory.com/20?category=395796)을 참고해주세요!

 

그럼 거두절미하고, 바로 보여드리겠습니다. 


[파일 읽기 소스코드 - filereadTest.php]

<?php 

//내용을 읽어올 파일명
$fileName = "fwriteTest.txt";


if(file_exists($fileName)){
	//파일 열기 
	$fp = fopen($fileName, 'r');
	if($fp){
		//파일 읽기 
		$fr = fread($fp, filesize($fileName));
		if($fr){
			//내용 출력
			echo $fr;
			//파일 닫기
			fclose($fp);
		} else { 
			echo "파일 읽기에 실패하였습니다.";
		} //end if_fr
	} else { 
		echo "파일 열기에 실패하였습니다."; 
	} //end if_fp
} else { 
	echo "파일이 존재하지 않습니다."; 
} //end if_fe

?>

이전 포스팅 내용을 확인한 후 위 소스를 보면 이해가 빠를 겁니다! 

fopen이 파일 열기 함수였으니 위 소스를 그대로 가져와서 예시를 들게요!

 

파일 열기 함수[fopen()] : $fp = fopen($fileName, 'r'); // r -> 읽기 권한을 말합니다.

파일 읽기 함수[fread()] : $fr = fread($fp, '불러올 파일의 용량');

파일 용량 확인[filesize()] : filesize('불러올 파일 경로와 파일명');

파일 존재 여부 확인 함수 [file_exists()] : file_exists('파일명');

 

fread() 함수를 사용하려면 파일 용량을 알아야 하는데 그 용량을 일일이 체크하지 않고 filesize() 함수로 가져올 수 있습니다. (byte 단위로 가져옵니다.) 그리고 읽으려는 파일의 존재 여부를 체크하기 위해 file_exists() 함수를 사용하였습니다. 괄호 안에 파일 명이 존재하면 true를 반환하고, 존재하지 않는다면 false를 반환합니다. 

 

그래서 위 소스를 실행하면 어제 만들어놨던 fwriteTest.txt 파일의 내용을 그대로 읽어옵니다.

.

fwriteTest.txt
filereadTest.php 실행결과

만약 없는 파일명이나 파일이 존재하지 않는다면 if문이 아닌 else문이 동작하여 다른 결과가 나오니까, 

직접 테스트해보시길 바랍니다 ㅎㅎ

.

파일을 읽어오는 함수가 fread만 있는건 아니더라구요!

찾아보니 fgets()라는 함수가 있는데, 파일 내용을 한 라인씩 읽어오는 함수라고 하더라구요.

(이런 것도 몰랐는데 그동안 개발은 어떻게 했니 나레기야..)

.

여튼, 쓰는 방법은 이렇게 쓴다고 합니다.

$fg = fgets($fp, '불러올 용량')

.

이걸 기반으로 소스코드를 아래와 같이 적어보았습니다.


[파일 한줄씩 읽기 소스코드 - fgetsTest.php]

<?php 

//내용을 읽어올 파일명
$fileName = "fgetstext.txt";


if(file_exists($fileName)){
	//파일 열기 
	$fp = fopen($fileName, 'r');
	
	//파일 용량의 크기가 얼마나 될지 몰라서 filesize() 함수 사용
	$readByte = filesize($fileName);
	if($fp){
		$fg=fgets($fp,$readByte);
		echo $fg."<br>";
	} //end if_fp 
} //end if_fe

?>

[미리 적어놓은 fgetstext.txt, 라인을 구분하기 위해 번호를 적었습니다!]

더보기

1 : fgetsTest
2 : 티스토리
3 : 만세!


fgetsTest.php를 실행해봅시다.

fgetsTest.php 실행 결과

정말 한줄만 읽어와서 가져오네요! fread()랑은 다른 용도로 잘 사용할 수 있을 것 같습니다. 

이걸 반복문을 돌리면 다 읽어올 수 있을것 같네요!

fgetsTest.php를 수정해보겠습니다. 

 


[fgetsTest.php, 반복문 추가]

<?php 

//내용을 읽어올 파일명
$fileName = "fgetstext.txt";


if(file_exists($fileName)){
	//파일 열기 
	$fp = fopen($fileName, 'r');
	
	//파일 용량의 크기가 얼마나 될지 몰라서 filesize() 함수 사용
	$readByte = filesize($fileName);
	if($fp){
    	// 수정한 부분 -> while을 이용한 반복문을 돌림.
        // fgets() 함수 사용 시, 더이상 불러올 용량이 없으면 false 반환!
		while($fg=fgets($fp,$readByte)){
			echo $fg."<br>";
		} // end while_fgets
	} //end if_fp 
} //end if_fe

?>

반복문을 추가했으니 다시 한 번 실행해보겠습니다. 

 

수정한 fgetsTest.php 결과.

오.. 예상한 그대로 나오니 짧은 코드를 쓰더라도 뭔가 뿌듯하네요ㅋㅋㅋ (이런거에 만족하는 초급개발자란..)

 

이전 포스팅이나 오늘 포스팅이나 회사에서는 주로 개발한 내용에 대해서 요청-응답 기록을 남기기 위해 로그 파일을 찍고 읽어오도록 소스 코드를 작성할 때가 많을 것입니다. 그러다보니 쉬워 보이는 내용이지만 실제로 많이 쓰이는 함수라고 보시면 될 것 같습니다!

 

오늘 포스팅은 여기서 마치도록 하겠습니다아~!!

+ Recent posts