c# 을 이용하여 streamreader 개체로 텍스트를 읽는 방법은 매우 효율 적이고 손쉽게 작업을 수행하도록 해줍니다. 빠르고 간단하게 개발을 할 수 있어 저도 자주 사용하고는 합니다.
그런데 이번에 방대한 크기의 텍스트 파일을 이용해서 작업을 하는 중 고민 거리가 생겼습니다. 미리 텍스트 파일을 읽어서 중간중간 핵심이 되는 ID 별로 위치를 저장해놓고 나중에 ID 에 해당되는 위치로 seek 하여 읽어 들이는 방법을 사용하려고 했습니다.
그런게 steramreader 는 seek 기능이 없더군요. -_-
그래서 streamreader.basestream 으로 들어가보니 seek 도 있고 position 도 있길레 해당 메소드와 프라퍼티로 구현을 해보기로 하였습니다.
long filePos = -1;
using (StreamReader cini = new StreamReader(fs, Encoding.Default))
{
do
{
filePos = cini.BaseStream.Position; //readLine 을 하기 전 위치를 저장한다
string cline = readline();
if (cline == "내가 원하는 정보")
{
break;
}
}while(cini.EndOfStream == false);
}
// filePos 에 저장된 값을 나중에 이용할 경우
using (StreamReader cini = new StreamReader(fs, Encoding.Default))
{
cini.DiscardBufferedData();
cini.BasePosition.Seek(filePos, SeekOrigin.Begin);
// 자 이제 읽어 볼까!
string myResult = cini.readLine();
}
이런 식으로 말이지요..
간단하잖아요? 상식적으로 저렇게 하면 될 것 같기도 하고요...
그런데 안됩니다.
엉터리 값이 나오게 됩니다.
라인 위치도 안맞고 알수 없는 위치의 값들이 튀어 나옵니다.
인터넷을 좀 뒤적거려보니 StreamReader 의 readline 이라는 녀석이 특이한 녀석이더군요.
우리가 생각하는 문자열에서 실제 한줄을 읽어서 반환해주는 게 아닌 어떤 블럭 단위로 데이터를 읽어 들인 뒤 newLine 에 해당하는 기호까지의 데이터를 돌려주는 것으로 블록 안에는 한줄이아닌 여러줄이 들어 있을 수도 있습니다.
바로 요 링크에 있는 코드인데요. 사용하기도 편리하게 해당 개발자 분께서 함수로 깔끔하게 구현을 해주셨습니다.
바로 아래코드를 본인의 개발중인 클래스에 포함시킵니다.
public static long GetActualPosition(StreamReader reader)
{
System.Reflection.BindingFlags flags = System.Reflection.BindingFlags.DeclaredOnly | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.GetField;
// The current buffer of decoded characters
char[] charBuffer = (char[])reader.GetType().InvokeMember("charBuffer", flags, null, reader, null);
// The index of the next char to be read from charBuffer
int charPos = (int)reader.GetType().InvokeMember("charPos", flags, null, reader, null);
// The number of decoded chars presently used in charBuffer
int charLen = (int)reader.GetType().InvokeMember("charLen", flags, null, reader, null);
// The current buffer of read bytes (byteBuffer.Length = 1024; this is critical).
byte[] byteBuffer = (byte[])reader.GetType().InvokeMember("byteBuffer", flags, null, reader, null);
// The number of bytes read while advancing reader.BaseStream.Position to (re)fill charBuffer
int byteLen = (int)reader.GetType().InvokeMember("byteLen", flags, null, reader, null);
// The number of bytes the remaining chars use in the original encoding.
int numBytesLeft = reader.CurrentEncoding.GetByteCount(charBuffer, charPos, charLen - charPos);
// For variable-byte encodings, deal with partial chars at the end of the buffer
int numFragments = 0;
if (byteLen > 0 && !reader.CurrentEncoding.IsSingleByte)
{
if (reader.CurrentEncoding.CodePage == 65001) // UTF-8
{
byte byteCountMask = 0;
while ((byteBuffer[byteLen - numFragments - 1] >> 6) == 2) // if the byte is "10xx xxxx", it's a continuation-byte
byteCountMask |= (byte)(1 << ++numFragments); // count bytes & build the "complete char" mask
if ((byteBuffer[byteLen - numFragments - 1] >> 6) == 3) // if the byte is "11xx xxxx", it starts a multi-byte char.
byteCountMask |= (byte)(1 << ++numFragments); // count bytes & build the "complete char" mask
// see if we found as many bytes as the leading-byte says to expect
if (numFragments > 1 && ((byteBuffer[byteLen - numFragments] >> 7 - numFragments) == byteCountMask))
numFragments = 0; // no partial-char in the byte-buffer to account for
}
else if (reader.CurrentEncoding.CodePage == 1200) // UTF-16LE
{
if (byteBuffer[byteLen - 1] >= 0xd8) // high-surrogate
numFragments = 2; // account for the partial character
}
else if (reader.CurrentEncoding.CodePage == 1201) // UTF-16BE
{
if (byteBuffer[byteLen - 2] >= 0xd8) // high-surrogate
numFragments = 2; // account for the partial character
}
}
return reader.BaseStream.Position - numBytesLeft - numFragments;
}
그런 다음 위에서 제가 작성했던 코드에 position 을 기록하는 부분을 위에 소개한 함수를 이용해서 찾는 것이지요.
GetActualPosition 이라는 함수를 이용해서요. 그럼 아래와 같이 되겠죠.
long filePos = -1;
using (StreamReader cini = new StreamReader(fs, Encoding.Default))
{
do
{
filePos = GetActualPosition(cini); //readLine 을 하기 전 위치를 저장한다
string cline = readline();
if (cline == "내가 원하는 정보")
{
break;
}
}while(cini.EndOfStream == false);
}
// filePos 에 저장된 값을 나중에 이용할 경우
using (StreamReader cini = new StreamReader(fs, Encoding.Default))
{
cini.DiscardBufferedData();
cini.BasePosition.Seek(filePos, SeekOrigin.Begin);
// 자 이제 읽어 볼까!
string myResult = cini.readLine();
}
이렇게 해서 결과를 확인해보면 아주 완벽하게 동작이 됩니다.
해당 개발자 분께서 페이지에 그리고 주석으로 상세하게 소개를 하고 있으니 관심 있으신 분께서는 한번 찬찬히 분석해보시는 것도 큰 공부가 될 것 같습니다.
c# 을 이용해 StreamReader 를 사용하시는 분들~
readline 수행 후 정확한 위치를 구해야 하는 문제에 봉착하셨다면 한번 시도해 보세요.
본격적으로 캠핑의 계절이 왔습니다. 야외에서 침낭이 없어도 춥지 않은 환상적인 날씨죠. 이제 가을까지 계속 캠핑하기 좋은 날이 이어질거라 믿습니다. 그래서 이것저것 캠핑용품을 구입하였는데요.
문제는
차에 안들어 간다는 것입니다. i30cw 의 트렁크가 작지 않다고 믿었지만 ... 무리데스. -_-;;
이때는 몰랐다. 이게 다인줄 알았지...
위의 사진에추가로 구입한 물품이
야전텐트 2개, 캠핑의자 2개, 자충식 에어 매트리스 가 되겠으며 이제 여름이니까 여름 물놀이 용품과 보트, ....
... (-_-)>"
그래서 차량용 루프박스를 구입하기로 마음 먹었습니다.
툴레 루프박스, 최고로 멋지고 최고로 비싸다. -_-
우선 여러가지 제품을 살펴보았는데요. 단연 THULE 제품이 눈에 들어오더군요. 많은 사람들에게 인기가 있는건 다 이유가 있는 것이지요. 유럽에서 안전 인증도 받았을 뿐더러 디자인이 정말 너무나 예쁩니다. 하지만 문제는 가격이죠. 마음에 든다 싶으면 100만원이 훌쩍 넘어가더군요. 결재 버튼에 손이 몇번이나 갔는지 모르겠습니다.
어쨌든 구입을 망설이며 며칠을 루프박스를 검색하며 알아본 결과 중요한 포인트를 몇가지 알게 되었습니다.
차량용 루프박스 선택 시 체크해야 할 사항 (중요)
내 차량에 루프레일 / 루프랙이 달려있는가?
기본 장착 구조가 아니라면 별도로 장착하기 위한 구조로 설계가 되어있는가?
루프박스의 높이가 생각보다 높다. 가로바와 루프박스 설치를 완료한 높이가 2.1 m 를 넘는가? (건물 지하주차장 최소 진입 높이가 대부분 2.1m라고 합니다.)
루프 박스의 잠금 방식은 안전한가?
과연 내차에 올라가는 사이즈(길이, 폭) 인가? (생각보다 루프박스가 큽니다. 길이가 2m 가 훌쩍 넘는 제품도 있지요)
열리는 방향은 양쪽으로 다 열리는가?
뚜껑이 견고한 플라스틱으로 이루어져 있는가? (재질, 두께)
적어도 이 정도의 검토를 하고 구입을 하는 것이 후회를 하지 않습니다. 인터넷에 찾아보면 주차장 진입시 루프박스가 부딪혀 박살난 이야기들을 종종 찾아볼 수 있는데요. i30cw 의 경우 워낙 오래된 차여서인지 생각보다 정보가 없더군요. 어떤 제품을 사야할지 많이 고민이 되었습니다.
i30cw의 경우 일단 SUV 보다는 차고가 낮으니 선택의 폭은 좀 넓어 지겠으나 루프랙 자체의 높이도 있고 하니 최소한의 높이가 되는 조합을 찾기로 하였습니다.
그런데 루프박스의 높이가 낮아지면 가격은 올라가는 것을 아시나요? 얇은 루프박스들은 정말 많이 비쌉니다.
일단 제차는 높이가 낮으니 조금은 선택의 폭이 넓어진 셈 입니다. 중대형 SUV 였다면 아마 눈물을 머금고 비싸고 얇은 루프박스를 구입했어야 하겠죠.
제 차량에 과연 루프박스가 문제 없이 올라갈까 싶어 포토샵으로 시뮬레이션도 해보았습니다.
가로바의 선택
높이를 낮추기 위해서는 가로바를 휘습바 라는 제품을 설치하는 것이 좋습니다. 물론 루프랙이 있는 차량의 이야기 입니다. 휘습바는 루프랙 안쪽으로 설치가 가능한데 좌우로 가로바가 튀어 나오지 않아 깔끔한 외관을 보이고 높이도 장착할 수 있는 최저 높이가 되므로 아주 적당한 솔루션이 되겠습니다. 툴레와 야키마의 제품이 유명한데 가격이 만만치 않습니다. 국산 유일 캐리어에서는 휘습바는 나오지 않지만 루프랙에 장착할 수 있는 고급형 가로바의 거의 두배에 가까운 금액이 필요합니다. 이것도 고민이 되는 부분입니다.
루프렉이 있는 차량에 높이를 최소한으로 설치할 수 있다.
하지만 결국 저는 유일 캐리어의 가로바를 최종 선택하였는데요. 아무래도 국산 제품이며 제품에 대한 신뢰도가 생각보다 높았습니다. 만약 루프박스도 생산하였다면 유일 캐리어 제품을 고민 했을 지도 모릅니다.
유일캐리어의 루프랙용 가로바 시스템
어쨌든 제가 구입한 가로바는 유일 캐리어의 YI-127WB 제품을 구입하였습니다. 참고로 YI-127 은 가로바 아래쪽에 루프랙과 고정되는 부품(풋) 의 제품명이며 WB 는 윈드 블레이드?? 정도로 구분되는 제품명으로 보여집니다. 어쨌든 제품이 튼튼해 보이고 디자인도 유려하였으며 (툴레 못지 않게) 가로바의 단면 형상이 공기 저항에 최적화된 '에어로 바' 를 제공하므로 툴레와 비교하여도 부족할 것이 없었습니다. 다만 휘습바에 비하여 높이가 높아지기 때문에 루프박스 선택에 야간의 고민이 늘게 되었습니다.
설치는 직접 하는 것으로 하고 인터넷으로 구입하니 툴레 제품의 반값 밖에 안되더군요.
또 나중에 차량을 바꿔 루프랙이 없는 차량이라도 풋만 따로 구입이 가능하므로 풋만 구입하면 바로 재사용 할 수 있겠다 싶었습니다.
유일 캐리어 가로바는 이틀만애 배송 완료.
3개의 박스에 포장되어 도착
루프박스 선택
어쨌든 가로바를 먼저 구입하고 나서 루프박스를 살펴보았습니다.
처음엔 THULE 에서만 고르다가 인터넷에 찾아보니 가성비 루프박스들이 많이 소개되어 있었습니다. 하지만 국내 루프박스의 3대장 하면 결국 THULE, Hapro, Yakima 요렇게 3가지로 압축 되더군요. 중국산 제품은 일단 믿음이 잘 안가고 심지어 많이 알려진 제품의 경우 가격도 그다지 저렴하지도 않았습니다.
결국 안전성, 디자인, 가격 모두 합리적이다 판단된 Hapro 브랜드로 선택의 폭이 좁혀졌고 그 중에 제니스, 트랙서로 압축이 되었습니다.
제니스는 높이가 비교적 낮고(37cm) 디자인이 훌륭합니다. 하지만 가격이 비싼게 걸렸습니다. 가장 큰 사이즈인 8.6 의 경우 100만원이 훌쩍 넘는 가격이어서 포기, 6.6 역시 가격에 있어서는 큰 차이가 없었습니다.
날렵한 디자인의 제니스 (가격이 부담스럽다)
약간 통통해 보이는 트랙서, 제니스 8.6에 가까운 수납 용량을 보인다.
트랙서 제품은 70만원대에 가격이 형성되어 있고 6.6 으로 사게 되면 크기도 적당해 보여 해당 제품으로 구입해야 겠다 마음을 먹었습니다. 높이가 제니스에 비하여 약간 높지만(43cm) 설마 2.1m 가 넘겠나 싶었습니다. 결국 인터넷에서 검색되는 최저가로 구입을 하였습니다. 물론 최저가는 60만원대 초반에 올라와 있더군요.
그런데 이게 왠일 인가요.. 판매자가 갑자기 물건이 없다며 환불을 해버린 것 입니다. 어의가 없었지만 재고가 없다니 어쩌겠습니까... 그렇게 구매에 실패하고 나니 좀 현실감이 생겼습니다. 중고도 한번 알아볼까?
결국 중고나라를 며칠 뒤적거린 후 아주 마음에 드는 녀석을 발견!! 판매자 분과 바로 약속을 잡고 두근거리는 마음을 안고 퇴근길에 올랐습니다.
바로 제니스 8.6 을 구입할 설렘을 안고 말이지요. ㅋㅋ
유일캐리어 가로바 직접 설치하기!
집에오자 마자 저녁을 입으로 먹었는지 코로 먹었는지 모릅니다. 숟가락을 놓자마자 중고거래를 위하여 미리 사놓은 가로바를 부랴부랴 설치합니다.
가로바 설치는 처음해보았는데요. 유일 캐리어에서 설치하는 메뉴얼을 영상으로 제작해 주어 아주 쉽게 따라할 수 있었습니다. 손재주 좋으신 분은 혼자서도 20분이면 충분히 설치할 수 있을 것 같습니다.
순서는 다음과 같습니다.
가로바 상단에 고무 마개 씌우기 끝까지 딱 맞게 끼우시면 됩니다. 고무 길이가 가로바 길이의 1/2 보다 조금 짧으므로 두개 끼우고 나서 하나는 끼우고 끝을 커터칼로 잘라주시면 됩니다.
하단 양쪽에 풋이 들어갈 부분에 밀어주는 마개가 있는데요. 안쪽으로 밀어줍니다.
풋을 박스에서 꺼내서 나사를 풀어 아래쪽을 좀 벌려준 후 양쪽에 하나씩 끼워줍니다. 안쪽으로 여유있게 넣어 둡니다.
반듯하게 들고 이동하여 루프랙 위에 얹어봅니다.
한쪽씩 풋의 위치를 조정하여 루프랙에 고정 부분이 끼워지도록 위치합니다. (양쪽 모두)
줄자를 가져와서 좌우 길이가 동일해 지도록 맞춥니다.
다른 한세트를 동일하게 조립해서 역시 루프랙에 위치하고 길이를 맞춥니다.
가로바와 가로바 사이의 길이를 최소한 550mm 이상으로 벌려서 조임 나사를 돌려 본격적으로 고정을 합니다. 이때 루프랙의 끝부분으로 부터 거리를 잘 확인하셔서 양쪽이 동일한 위치에 자리잡도록 확인해 주셔야 합니다. 그리고 약간 앞 쪽으로 위치시켜야 나중에 루프박스를 올렸을때 트렁크와의 간섭이 안생깁니다.
네군데 나사를 모두 조여줍니다. YI-127 제품은 별도의 공구 없이도 손으로 나사를 조일 수 있게 되어 있으니 설지 작업이 매우 편리한 편 입니다.
아까 안쪽으로 밀어 두었던 하단부 마개를 풋에 딱 맞도록 다시 당겨서 맞춥니다.
가로바 양쪽에 플라스틱 마개를 덮고 동전 등을 이용하여 잠금장치를 잠그어 줍니다. 4군데 모두
풋의 덮개를 덮어주기 전에 네군데 모두 확실하게 조여질 수 있도록 한번더 확인합니다.
풋의 덮개를 덮고 열쇠로 잠그면 설치 완료!
글로 설명하려니 장황하지만 직접 해보시면 간단한 작업이고요. 옆에서 누가 도와주면 정말 쉬운 작업입니다.
줄자는 필수 입니다.묵직한 풋, 내부 채결 부품이 모두 튼튼한 금속으로 구성되어 있다.YI-127 풋의 최대 장점은 설치, 분해시 별도의 도구가 필요없다는 점이다. 가운데 보이는 손잡이를 돌리면 고정됨모양새도 괜찮은 편이다.루프랙으로 부터의 높이는 약 8cm 정도? 생각보다 높지 않다.
디자인도 굳!
자 이제 머리 올리러 출발!
i30cw 에 215cm 의 제니스 8.6 루프박스가 거뜬히 올라가다.
직접 만나서 거래를 하고 판매자 분과 함께 제차에 올려보며 크지는 않은지 확인까지 하며 중고 거래를 마쳤습니다. 생각보다 크지 않더군요. 사이즈가 아주 마음에 듭니다. 판매자 분도 6.6으로 구입했으면 후회했을거라 하시더라구요. 짐 들어가는게 많이 차이가 난다고 합니다.
크기를 보기위해 살짝 얹어놓은 모습
색상도 제 차량과 잘 어울립니다. 진회색인 제 차량과 카본 실버 색상이 톤이 비슷하여 깔끔하고 예뻐 보입니다.
가로바도 마칭 600mm 정도로 간격을 벌려놨기 때문에 루프박스가 바로 올라갑니다. 전 주인분께서 친절히 설치를 도와 주셨고요, 고정장치를 손으로 돌려 고정하기 때문에 별도의 장비도 필요가 없었습니다.
하프로 제니스 스펙자가 설치를 하려면 반드시 위의 내용을 숙지하고 가로바를 설치하는 것이 좋다.하프로 제니스 전체 외부 크기
모든 분들이 가능한 방법은 아니지만 또 이런 방법이 있구나 하고 다른 응용방안을 찾아내는 분들도 계시리라 믿고 제가 사용한 방법을 공유 드립니다.
이름은 잘 모르겠는 비닐 진공 압축 기계
이 기계는 제가 재활용품 버리는 곳에서 주워온 것인데요, 원하는 크기로 비닐 봉지를 만들어서 진공으로 압축해서 보관할 수 있는 혁신적인 제품인데요, 아마 그냥 일회용 봉투 사용하는 것에 비하여 번거로움이 있고 뭔가 세련된 디자인이 아니어서인지 히트상품은 아니었던거 같아요.
요즘은 세련된 디자인으로 동일한 기능의 제품이 나오는 것 같습니다.
하지만 들여다 보면 정말 효용성있게 잘만든 제품이지요.
어쨌든.. . 이기계에는 roll 타입으로 아주 긴 비닐이 감겨있는 것이 있습니다. 한쪽은 막혀 있지만 나머지는 뚫려있어 양쪽을 녹여 붙여주고 내용물을 담은 뒤 나머지 부분을 녹여 붙여주면 외부와 완전히 밀폐되는 공간이 만들어 집니다.
일단 롤에 감겨 있는 비닐을 돌돌 말아놓은 카펫 길이만큼 풀어낸다.
저는 이 롤 타입의 비닐을 길게 뜯어 긴 한쪽을 모두 접착해서 아주 긴 비닐 봉투를 만든것인데요, 얇고 아주 길게 만들어진 봉투에 돌돌 말은 카펫을 넣어서 여름내 습기와 먼지로부터 완벽하게 보호될 수있도록 보관을 하는 것이죠.
빨간 선 부분을 길게 이어 붙여 준다.
길게 띁어낸 봉투의 옆면을 이어 녹여 붙여 주면 이렇게 길고긴 봉투가 하나 만들어 집니다.
돌돌 말아놓은 카펫을 여기에 끼워 넣는 것이죠.
이렇게 다 끼우고 나면 끝부분은 테이프로 붙여주면 됩니다.
우왕 굳!
이런식으로 보관하면 여름이 지나고 다시 겨울이 되어 꺼내는 약 5 개월여간의 보관 기간 동안 먼지, 습기 등의 피해를 입지 않고 깨끗하고 안전하게 카펫을 보관할 수 있습니다. 이렇게 말아둔 카펫은 붙박이장 한켠에 세워 두거나 장롱 상단에 멀찌감치 밀어넣어 두면 지저분하게 보이지 않도록 잘 보관할 수 있답니다.
이번에 사용한 진공 압축기역시 위에서 적은 것처럼 재활용품 수집장에서 주워온 것인데 벌써 3년째 카페트 정리하는데 유용하게 사용하고 있습니다 ㅋㅋ 본래의 목적으로는 생각처럼 잘 사용하게 되지 않더군요. 지퍼백이나 위생백이 너무나 편리하기도 하고 쉽게 사용할 수 있기 때문이겠습니다만 불필요한 비닐의 사용을 막고 사용할 만큼씩만 딱 사용할 수 있는 제품인만큼 요즘같은 시대에 오히려 각광을 받아야 하는 제품이 아닐까 생각해 봅니다.
위의 문자열들에서 color_A 는 제가 아래 올린 코드의 color_a 에 대한 설정 값으로 사용되게 됩니다. 일일이 if 문을 이용하여 color_A == color_a 인지 color_b 인지 확인하지 않고 해당 클래스가 들고 있는 프라퍼티들의 이름 중에 같은 것이 있는지 찾는 방법이지요.
// 제일 상단에 지시문 추가
using System.Reflection;
// 본 클래스는 메인 클래스가 아니어도 상관 없습니다.
// 예를 들면 Form 클래스내에 기능적인 용도나 구조체로 사용할 클래스 여도 상관 없음
public class MyColorStyle
{
private string color_a;
private string color_b;
private string color_c;
private string color_f;
private string color_e;
private string color_f;
private string color_g;
// 외부에서 가져가고 세팅할 수 있도록 get set 함수 하나씩 준비
public string color_A {get { return color_a;} set { color_a= value; } }
public string color_B {get { return color_b;} set { color_b= value; } }
public string color_C {get { return color_c;} set { color_c= value; } }
public string color_D {get { return color_d;} set { color_d= value; } }
public string color_E {get { return color_e;} set { color_e= value; } }
public string color_F {get { return color_f;} set { color_f= value; } }
public string color_G {get { return color_g;} set { color_g= value; } }
public golfMapcolorStyle()
{
//생성자 부분에는 초기화 값 넣어 주시고요..
}
public void setColor(string clrString) // clrString : "color_A=#FFEECC" 형식의 설정 문자열이 줄단위로 기록되어 있는 파일 전체
{
string[] tmps = clrString.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries); // 줄바꿈 단위로 분리해준다.
foreach (string str in tmps)
{
string[] tmp = str.Split('='); // = 기호를 기준으로 앞의 문자열은 변수 명칭을 검색, 뒤의 문자열은 값으로 사용
foreach (PropertyInfo p in typeof(MyColorStyle).GetProperties())
{
if (tmp[0] == p.Name)
{
tmp[1] = tmp[1].Trim(); // 잘려진 문자열 뒤에 지저분하게 붙는 경우가 있어서 사용함
p.SetValue(this, tmp[1], null);
}
}
}
}
}
총 7개의 변수가 있지만 단 하나의 방법으로 설정을 할 수 있게 됩니다.
만약 변수가 100 개 이상이었다면 위와 같은 방식으로 사용하는게 개발 시간을 크게 단축할 수 있을 것입니다. 오류도 많이 줄어들 것이고요.
위 코드에서 제일 핵심이 되는 부분은 바로 아래 부분입니다.
foreach (PropertyInfo p in typeof(MyColorStyle).GetProperties())
{
// p 에 대하여 무었인가를 할 수 있음
}
클래스가 가지고 있는 변수를 프라퍼티로 보고 프라퍼티의 이름을 확인하여 뭔가를 할 수 있게 되는 것이죠.
p.SetValue 라는 명령어를 이용하여 p 라는 MyColorStyle 라는 클래스의 프라퍼티(변수) 의 값을 설정하는 것이 이번 포스트의 핵심 내용입니다.
만약 변수가 문자열 뿐만 아니라 int 형식도 존재한다고 하면 아래와 같이 간단하게 구현할 수도 있습니다.
코로나로 바깥 활동이 뜸해지고 집에만 머무르는 시간이 길어지며 많은 분들이 답답함을 호소하는 시기입니다. 그래서인지 요즘 캠핑이 특히 인기가 많은 것 같은데요, 사람들 바글바글한 오토캠핑장보다는 한적한 곳을 찾아 떠나는 캠핑카나 차박 캠핑이 많은 사랑을 받는 것 같습니다.
보통 차박 캠핑하면 SUV 차량을 이용해서 즐기는 정보만 가득한데요... i30CW 와 같은 왜건 차량으로도 차박 캠핑이 가능한지 궁금해 졌습니다.
일단 텐트를 주문 하자
바로 인터넷 쇼핑몰을 둘러보며 이런저런 제품들을 찾아보던 중 캠프밸리에서 출시한 차박 캠핑용 텐트인 "오토카하우스 차박텐트"를 구입하였습니다. 가격이 저렴한 편 (235,000원) 이어서 저와 같은 입문용으로 적당해 보였고 천정이 높은 것 (무려 210cm) 이 마음에 들었으며 차량 연결 부위가 충분히 커서 나중에 차량을 변경하게 되더라도 무난히 사용할 수 있을 거라 판단 되었고요. 무엇보다 원터치로 모기장 텐트를 펼수 있다는 점에 높은 점수를 주었습니다. 캠핑장에서 텐트치다보면 한나절인 분들 계시잖아요? 저는 손재주는 좋은 편이지만 그런 귀찮은 과정을 마주하기는 싫었기 때문에 설치가 편리한 제품을 우선으로 하였습니다.
온라인 쇼핑몰 소개사진. (광고는 아닙니다)온라인 소핑몰 소개사진 (광고아님)
색상이 조금 마음에 들지 않았지만 구입할 수 있는 제품이 당장 하나 밖에 없어 카키(황토색) 제품을 구입하게 되었습니다.
차량용 차박 텐트는 기본적으로 차량안에서 잠을 자는 것을 기본으로 하기 때문에 텐트 바닥은 없습니다. 바닥이 있는 제품도 있었으나 신발 신고 다닐 수 없다면 신발 신고 벗기가 불편할 것 같고 또 청소도 매번 해주어야 하니 바닥이 없는 제품이 낫겠다 싶었습니다.
막상 제품이 도착하고 보니 예상을 깨는 패키지였습니다.
??? 가방이 두개?
가방이 두개??
펼쳐보니 긴 가방은 안쪽에 설치하는 기둥 역할을 하는 모기장 텐트이고 짧은게 그 모기장 텐트를 덮는 텐트 외부 천 이었습니다.
일단 모기장 텐트를 펴보았습니다. 폴대를 끼우고 자시고 없이 바닥에 펴놓고 뒤로 제껴주기고 위로 당겨 올리기만 하면 끝 입니다. 정말 간단하네요. 모기장 치는건 1분이면 충분합니다.
정말 생각지도 못했던 정체(?) 가 아니고 ㅋ크기
모기장의 크기가 생각보다 크네요. 실내에 설치해보니 그 크기가 실감이 됩니다. 32평 아파트 거실만하군요.
높이가 210cm 라기에 음.. 높구나 했는데 정말 깜놀 하였습니다. 저희집 천장이 낮은건지...
그때 불현듯 걱정이 스쳐지나갔는데, 이게 과연 차에 실릴까 하는 것이었죠. 제차는 i30cw 다 보니 SUV 들처럼 트렁크가 넓고 높지 못한것이 떠올랐습니다. 물론 왜건이다 보니 작지는 않죠. 근데 생각보다 공간은 안나옵니다.
차에 가지고 내려가 봅니다.
음.. 길다.
어깨에 매면 이정도 입니다.
작지는 않죠? 물론 대형 텐트들에 비하면 큰건 아니지만 제가 생각했던 것보다는 분명 큽니다.
주차장에 도착해서 트렁크안을 살펴보고 답이 나왔습니다.
다행히 트렁크 위쪽 공간에 텐트 패키지가 모두 실렸다.
쨔잔~
트렁크 양쪽 창문 부분 옆으로 슬라이드 덮개를 끼는 레일이 있는데 그 레일위에 얹으니 딱 맞더구요. 길이가 더 긴 모기장 텐트는 트렁크 창문쪽에 끼우면 적당하게 잘 맞습니다. 아래 보이는 코스트코 파라솔이 외부 텐트를 받쳐주고 있습니다.
오호.. 이렇게 되면 실제 트렁크 적재 공간이 그대로 살아나는것 아니겠습니까?
정말 뭔가 맞춘것처럼 딱 맞아 신이 다 나더군요.
자 그럼 이제 남은 일은 뭐다?
차박 텐트 설치해 보기
일단 짐을 싣고 출발해 봅니다. 자고올건 아니고 정말 텐트쳐보고 잠깐 놀고 올 계획입니다.
정말 대충넣어도 공간이 남는다. SCX10 은 사랑이죠. ㅋ
짜잔~ ㅋㅋ 먹을거랑 제 장난감까지 넣었는데도 공간이 남네요 남아.
아.. 이거 진짜 괜찮겠는데 싶은 순간이었습니다.
어쨌든 텐트 설치 테스트를 해보기위하여 집에서 멀지 않은 영종도를 찾았습니다. 처음 펴보는 장소는 당일로 하루 노는데 3만원 정도를 받는 사유지 캠핑장이었습니다. 돈이 조금 아까웠지만 이미 영종도 해안가는 인산인해더군요. -_- 텐트한번 쳐볼 자리 마련하기가 쉽지 않아 보였습니다.
여름인지 덮구나. 테이블이 너무 작아보이는건 기분 탓인가
음... 상당히 괜찮은데? 진짜 높이가... 와..
첫날은 뭐 대단한걸 준비해 간게 아니었기 때문에 바닷가에서 조금 놀다가 라면만 먹고 왔습니다. 한가족이 앉아 쉬고 놀기에는 정말 딱 괜찮은 사이즈인것 같습니다.
i30cw 의 뒷좌석을 눕히니 성인도 누워서 잘 수 있는 크기가 됩니다. 관리 잘된 i30cw 있으면 세컨카로 하나 장만 해 놓으셔도 괜찮을 것 같습니다. 사실 상당히 잘만든 차라고 생각하고 있습니다.
차안에서 본 텐트의 모습.. 어디 휴양지에 온줄알았다. 아늑하구만
와.. 휴양지가 따로 없네요. (옆에 나온 다리가 좀 거슬리기는 하지만... 사진이 이것밖에 없어서.)
음... 제대로 사진 찍힌게 없네요... 다음번에 제대로 찍어 올리겠습니다.
이렇게 아이들과 갯뻘에서 작은 게도 잡고 고동도 주으며 즐거운 하루를 보내고 왔습니다.
갯뻘에서 즐거운 시간을 보내는 중
더 필요한 것들
어쨌든 텐트를 직접 설치해보니 캠핑을 위해 필요한게 하나둘 보이더군요.
필요한 것들 중 1순위는 단연 작고 편안한 의자. 그리고 4식구가 차안에서 모두 자기에는 힘들기 때문에 간단한 야전 침대도 필요하다고 생각했습니다.
음.. 추가로 예쁜 가랜드 조명과 야간에 사용할 실내용 조명.. 정도가 필수로 있어야 겠습니다. 가랜드 조명은 구입, 실내용 조명은 직접 만들어 보기로 하였고 나머지는 얼른 주문을 하였습니다.
라고 생각하시겠지만 아이들을 키우다 보면 생각보다 음악 CD 를 재생할 일이 많이 있습니다. 동화책 같은 곳에 딸려오는 CD 도 있고요, 영어 교재나 음악 교재 등에도 여전히 CD 로 음악을 담아 배포하는 경우가 흔하답니다. 저역시 지금 사용하는 노트북은 CD 롬 드라이브가 장착이 안되어 있을 정도로 중요하다고 생각하지 않았습니다.
어쨌든 당장 CD 음악을 들어야 하는 상황이 되니 당황스럽더군요. 그래서 온라인으로 USB 타입 외장형 CD-ROM 을 하나 구입하였습니다.
USB 외장형 CD-ROM (별도전원 불필요)
그런데 구형 미디어의 불편함이랄까요? 요즘은 음악을 듣고 싶으면 유튜브나 멜론 같은 스트리밍으로 언제 어디서든 음악을 들을 수 있지만 제가 구입한 외장형 CD 만 하더라도 장착하고 CD 를 넣고 재생될때 까지 기다리고 하는 과정이 생각보다 귀찮아서 CD 안의 음악을 꺼내야겠다 생각이 들었습니다.
음악 CD 안의 음악을 mp3 파일로 추출해 보자
그래서 적어도 노트북에 꺼내 놔야 겠다 생각을 하게 되었던 것이죠.
CD-ROM 드라이브를 윈도우 탐색기를 통해 열어보면 아래와 같은 모습입니다.
1kb 짜리 파일만 가득하다?
이것 때문에 아내가 저에게 복사가 안된다며 이야기를 건냈습니다.
저역시 열어보고 살짝 당황했는데요.
사실 윈도우 미디어 플레이어에 기본으로 지원하는 기능 중에 음악 파일을 라이브러리로 꺼내는 기능이 있습니다.
먼저 CD를 재생할 플래이어를 윈도우 미디어 플레이어로 지정해 주어야 합니다.
미디어 플레이어가 실행되면 아래와 같은 모습이 되겠죠.
윈도우 미디어 플레이어가 CD 안의 음악을 재생중인 모습
그럼 우측 상단에 보이는 네모네모 아이콘을 클릭해 줍니다.
그럼 아래와 같이 미디어 라이브러리가 보이게 됩니다.
아래 그림의 빨간 네모 박스를 선택하셔서 내 컴퓨터로 가져올 음악을 모두 선택해 줍니다. 물론 개별로 선택하셔도 됩니다.
원하는 파일만 체크하여 복사하는 것도 가능
아래 사진의 CD 복사를 눌러줍니다.
전체 음악을 복사한다.
그럼 아래 그림처럼 선택된 음악 파일이 하나씩 하나씩 컴퓨터로 복사되기 시작합니다.
선택된 음악 파일이 복사되기 시작함
그럼 복사된 파일은 어디에 저장이 될까요?
바로 라이브러리 - 음악 폴더에 저장이 된답니다.
내컴퓨텅 mp3 파일로 복사가 진행중이다.
간단하죠?
참고로 복사설정을 누르시면 복사할 파일의 음질이나 포멧 등에 대하여 선택이 가능하므로 원하는 설정을 먼저 골라준 뒤 복사를 진행해도 되지만 이것저것 잘 모르겠으면 그냥 CD 복사 를 하셔도 무방합니다.