본문 바로가기
매트랩(Matlab)/매트랩 강의

[Matlab / 매트랩] 12. 외부 데이터(파일) 불러오기와 저장하기

by freezkim 2010. 3. 12.

그래프를 그리고 싶은데, 데이터가 txt파일이다.
붙여넣기는 너무 많고....

텍스트 파일은 100개가 넘는데 일일이 어떻게 다 붙이니

난 한번만이라도 햄보카고 싶은데 왜 나나
꽈찌쭈는 햄보칼수가 없어

에라이 매트랩 안써 이런 개같은 경우


이런 식의 문제가 있었다면 이젠 그 고민 말끔하게 해결해 드리겠습니다.

오늘은 외부 데이터 파일을 불러와서 매트랩에 입력하는 방법과

매트랩에서 처리한 데이터를 다시 출력해서 저장하는 것을 해보도록 하겠습니다.


1. 데이터가 알흠답구나. load를 쓰자.

load라는 명령어는 외부 데이터에 주석따위 없이 참으로 간단 명료하게 데이터만 딱딱 나와 있을 때 쓰기 딱 좋습니다.
(오우 롸임이 끝내주는걸)


예를들면 1.txt란 파일에 요런 데이터가 있다고 합시다: 
다운은 하시려면 클릭:

-1.485830e+000 -1.007270e+000 5.023739e-002 -3.098390e-001
-1.485830e+000 -1.007270e+000 5.023739e-002 -3.098390e-001
-1.485830e+000 -1.007270e+000 5.023739e-002 -3.098390e-001
-1.485830e+000 -1.007270e+000 5.023739e-002 -3.098390e-001
-1.485830e+000 -1.007270e+000 5.023739e-002 -3.098390e-001
-1.485830e+000 -1.007270e+000 1.007626e-001 -3.098390e-001
-1.485830e+000 -1.007270e+000 1.007626e-001 -3.098390e-001
-1.485830e+000 -1.007270e+000 1.007626e-001 -3.098390e-001
-1.485830e+000 -1.007270e+000 1.007626e-001 -3.098390e-001
-1.485830e+000 -1.007270e+000 4.239205e-005 -1.555173e-001
-1.485830e+000 -1.007270e+000 1.007626e-001 -1.555173e-001
-1.485830e+000 -1.007270e+000 1.007626e-001 -3.098390e-001
-1.278774e+000 -1.007270e+000 1.007626e-001 -1.555173e-001
-1.485830e+000 -1.007270e+000 1.007626e-001 -3.098390e-001
-1.485830e+000 -1.007270e+000 1.007626e-001 -3.098390e-001
-1.485830e+000 -1.007270e+000 1.007626e-001 -3.098390e-001
-1.485830e+000 -1.007270e+000 1.007626e-001 -3.098390e-001
-1.485830e+000 -1.007270e+000 1.007626e-001 -3.098390e-001
-1.278774e+000 -1.007270e+000 1.516203e-001 -3.098390e-001
-1.485830e+000 -1.007270e+000 1.516203e-001 -3.098390e-001
-1.485830e+000 -1.007270e+000 1.007626e-001 -3.098390e-001
-1.485830e+000 -1.007270e+000 1.007626e-001 -3.098390e-001
-1.485830e+000 -1.007270e+000 1.007626e-001 -3.098390e-001
-1.485830e+000 -1.007270e+000 1.007626e-001 -3.098390e-001
-1.485830e+000 -8.985647e-001 1.516203e-001 -3.098390e-001
-1.485830e+000 -1.007270e+000 1.007626e-001 -3.098390e-001
-1.278774e+000 -1.007270e+000 1.007626e-001 -3.098390e-001
-1.278774e+000 -1.007270e+000 1.007626e-001 -3.098390e-001
-1.485830e+000 -1.007270e+000 1.007626e-001 -3.098390e-001
-1.278774e+000 -8.985647e-001 1.007626e-001 -3.098390e-001

이 경우, 매트랩에서 파일이 있는 폴더를 지정해준 다음
load('1.txt');를 한번만 써버리면 데이터가 알아서 쫘자작 들어와주게 되죠.
직접 한번 보실까요?
먼저 이렇게 데이터가 있는 폴더를 지정해 주시구요.

이렇게 명령어를 입력해 봅니다.
>> data=load('1.txt');
>> plot(data(:,1),data(:,2));


그 결과, data라는 이름으로 txt파일에 있던 숫자들이 저장된 것을 확인할 수 있습니다.
물론 1.txt 데이터의 1열과 2열의 데이터로 그래프를 그릴 수 있는 거죠ㅋ

자, 여기서 load 명령어는
load(파일명) 의 형태를 가집니다.
이때 파일명의 '타입'은 뭐다? '문자'타입입니다. 따라서 ' ' 작은 따옴표를 찍어 줬던 거죠.

그런데, 여기서 바로 저번시간에 했던 sprintf의 진가가 드러납니다. 1.txt를 직접 입력할 수도 있지만,
sprintf 명령어를 써서 이렇게 나타낼 수도 있는거죠.

>> sprintf('%d.txt',1);
이렇게 하면 char 타입의 1.txt라는 문자가 출력됩니다
. 이걸 그대로 load에 넣어 줄 수 있겠죠.

>>load(sprintf('%.d.txt',1));
자 이런 형태인 쓸 수 있는 겁니다. 되나 확인해봅시다 :)

>> data=load(sprintf('%d.txt',1);
>> plot(data(:,1),data(:,2));

네, 역시나 되는 것을 확인 할 수 있습니다.

근데 이걸 왜 했냐구요??

예를들어 데이터가 1.txt, 2.txt, 3.txt 등등으로 이름이 되어 있을 때, 이 데이터를 모두 다 매트랩에 불러온다 칩시다.
근데 만약에 load(파일이름 일일이 다 쳐야돼) 이건 좀 미친거죠.
설마 이때까지 이래오셨다면 이제부터는 정상(?)으로 돌아오자구요

sprintf를 응용해서, 숫자 부분만 이름을 솨솨삭 바꿔주면 요런 짓거리가 가능해집니다.

>> for i=1:10
 data = load(sprintf('%d.txt',i));
 figure(i)
 plot(data(:,1),data(:,2))
end

이렇게 for문과 sprintf를 응용하면
1.txt~10.txt 의 제목을 가진 파일 10개를 힘들이지 않고
 
그래프를 그려줄 수 있는 거죠.
요거 아마 무지 유용하게 써먹으실 수 있을 거에요ㅎ

2. fopen - fscanf 사용하기

이건 어떤 파일의 데이터에 주석처리가 되어 있다던지, 혹은 16진수의 데이터라서 변환이 필요하다던지 할 때 쓰이는 명령어 입니다.
저의 경우는 대부분 직렬통신처리 할때 썼던것 같네요. 16->10진수 변환 용으로 말이죠.

이건 어떤 파일이 있으면 그 파일을 fopen으로 열어준 다음, fscanf라는 것을 이용해 매트랩에 일정양만큼 데이터를 불러오는 구조입니다. 타입변환이나, 원하는 형태로 행렬의 모양을 바꿀 수 있다는 장점 있지만, 그만큼 사용하기 더 힘든감이 없잖아 있습니다.

사용법이 좀 어려운 면이 없잖아 있어서, 코드를 한번 만들어두시고 두고두고 사용하시는게 편하지 않을까...싶네요ㅎ

구조는 이런 식입니다.
1) a = fopen( 불러올 파일 이름(char타입으로), r(reading의 약자:파일을 읽겠다는 뜻) )    
-> 먼저 파일을 열어 준 다음, a라는 곳에 저장합니다.
2) k = fscanf(a(읽을 파일 이름), '읽어들일 파일 내용', [행렬크기])
-> fscanf로 파일 내용을 한줄 씩 읽어 들입니다. 이때 읽어들인 데이터는 순서대로 k에 하나하나씩 저장되는데,
    행렬크기를 지정하지 않으면 그냥 한줄로 주루룩 저장되게 됩니다.
    행렬크기를 지정하면 그 크기에 맞게 데이터가 샤샤삭 들어가게 됩니다ㅎ
3) fclose(a)
-> 열었던 파일 a를 다시 닫아줍니다.

이 두가지 단계에서 사실 fopen이랑 fclose는 어렵지 않아요, 
fopen은 단순히 파일이름 써주고 뒤에 옵션으로 'r'만 붙여주면 되는 일이고..
fclose는 열었던 파일을 걍 이름만 써주면 되니, 어려울게 하나도 없지요.

하지만 요기서 까다로운 녀석이 있는데 그놈이 바로 fscanf 부분입니다.
꽤나 까다로우니깐 하나하나씩 분석해볼게요.ㅎㅎ

fscanf(a(읽을 파일 이름),'읽어들일 파일 내용',[행렬크기])

(1) a(읽을 파일 이름)
 a라는 건 명확하게 말하면 file identifier 이라고 불리는 건데요. 요건 사실은... 파일 이름이 아니라,
 그 파일의 상태를 나타내주는 숫자입니다.

 fopen이라는 명령어를 쓰게 되면, 파일 경로는 매트랩 내부에 지정이 되게 되고,
 a라는 것에는 파일 이름이나, 파일 경로에 대한 내용이 있는게 아니라 '파일이 어떤 상태에 있다'는 것을 숫자로 표현해 줄 뿐입니다.
 요 a라는 숫자가 얼마냐에 따라 fscanf라는 명령어가 데이터를 읽을 수 있을지 없을지를 결정하거든요. 
 
 실제로 보셔도 a라는 건 단순한 숫자일 뿐인걸 알 수 있습니다.


 네 뭐, 그냥 그렇다구요ㅋ 쓰는데 별 영향을 미치는 문제는 아닙니다

(2) '읽어들일 파일 내용'
이부분은 상당히 까다롭네요. 설명하기가....ㅎ흐흐흐흑 어떻게 말해야 할까..

먼저 이 부분에 들어가는 것은 '요렇게 요렇게 생겨먹은 내용을 읽겠다' 라는 걸 의미합니다.

예를들어 이부분에 '%g' 라고 쓴다면
'%g 라고 생겨먹은 내용을 읽겠다. 라는 건데 여기서 %g는 float type의 숫자를 의미합니다.(걍 숫자라고 생각하시면 되요)
그래서 다시한번 풀이하자면

'%g' = '숫자를 불러들이겠다.' 요런 의미가 되죠.

근데 요 fprintf라는 놈이 이 데이터를 받고 나면, 다시 또 %g 라는게 있나 관찰합니다.
만약에 숫자가 또 있다면? 그 숫자를 매트랩에 넣어주는 거죠.
그런데 없다면? 그냥 거기서 더이상 읽지 않고 멈추게 됩니다.


예를 한번 들어 볼게요.

요건 읽어들일 파일의 형식을 지정해주는 부분인데요. 파일의 내용이 만약에 이렇게 되어 있다고 합시다.

a -1.485830e+000 -1.007270e+000 5.023739e-002 -3.098390e-001
a -1.485830e+000 -1.007270e+000 5.023739e-002 -3.098390e-001
a -1.485830e+000 -1.007270e+000 5.023739e-002 -3.098390e-001

....


이때 만약에 '%g'라고 해서 읽어 들인다면 시작 부분에 a가 숫자가 아니기 때문에 아무것도 읽어 들이지 않고 끝이나게 됩니다.

보실까요?


아무것도 불러 들여지지 않습니다.

이때는 'a %g %g %g %g ' 요렇게 형식을 지정해 주어야 데이터를 읽어 들일 수 있습니다.
반복 되는 구조가 '문자 a 다음에 숫자 네개의 형식' 이므로
, 저렇게 생긴 형태를 계속해서 찾아서 읽어준다면 모든 데이터를 읽을 수 있겠죠. 단, 여기서는 %g에 해당하는 부분이 데이터로 저장됩니다.

직접 한번 볼게요ㅎ


네 요렇게 숫자 데이터가 저장되는 걸 확인할 수 있습니다ㅎㅎ

(3) [행렬크기]

위에서 보시면 아시겠지만 데이터가 주루룩 한줄로 밑으로 내려가는 걸 볼 수 있어요...
이런 경우는 행렬의 크기를 지정해 주는걸로 data가 m by n 행렬형태로 표시 될 수 있습니다.
예를들어 2 by 3으로 지정한다면.


이렇게 순서대로 6개의 데이터가 2개씩 촥촥 뒤로 붙어주게 되는거죠.

따라서 처음의 파일 형식대로 나타내기 위해서는 행렬의 크기를 이렇게 지정해주어야 합니다.

data=fscanf(a,'a %g %g %g %g ',[4,inf])
여기서 inf는 벡터의 '열'의 크기인데, 이를 무한대로 지정했으니, 데이터가 끝까지 나오게 됩니다.


자 요경우 처음 형식의 데이터를 옆으로 눕힌 형태이므로 transpose를 취해서 1.txt의 형태와 같도록 만들어 줍시다
(transpose는 1강을 참조하세요)

data=data'

이렇게 하면 파일을 불러들일 수 있게 되는거죠 완성!
fclose(a)로 닫아주고, 데이터를 맘껏 이용합시다



3. fopen - fprintf 사용하기-저장!!

파일을 불러오는 건 했으니 이젠 저장하는 걸 해볼텐데요. fscanf를 잘 익히셨다면, fprintf는 쉽게 쓸 수 있습니다.
형식은 거의 동일해요.

위에서 불러온 data파일을 이용해서 2.txt를 만들어 보겠습니다.

1) 먼저 fopen으로 파일 이름을 지정해줍니다. 단 이때는 r이 아니라 w(write)를 씁니다.
    a=fopen('2.txt','w');
2) fprintf명령어를 써서 데이터를 파일에 저장해 줍니다. 명령어 형태는 다음과 같습니다.
   fprintf(a,'저장할 형태',데이터)
3) fclose(a) 로 닫아줍니다.

마찬가지로, 1),3) 은 어려울 게 없구요.
저장할 형태는 숫자 네개 저장하고 한줄 띄우고 이런식으로 할테니
'%g %g %g %g \n' 요렇게 입력해 줍니다.

문제는 여기 데이터 부분인데, 그냥 데이터를 집어 넣게 되면 fscanf에서 파일 읽은 순서와 마찬가지로 열 벡터의 데이터부터 차례대로 읽어들여서 txt파일에 저장하게 됩니다. 뭔소리냐? 요렇게 저장된단 말이죠ㅠ

-1.48583 -1.48583 -1.48583 -1.48583
-1.48583 -1.48583 -1.48583 -1.48583
-1.48583 -1.48583 -1.48583 -1.48583
-1.27877 -1.48583 -1.48583 -1.48583
-1.48583 -1.48583 -1.27877 -1.48583
-1.48583 -1.48583 -1.48583 -1.48583
-1.48583 -1.48583 -1.27877 -1.27877
-1.48583 -1.27877 -1.00727 -1.00727
-1.00727 -1.00727 -1.00727 -1.00727

......

그래서 다시 한번 데이터를 transpose해서 저장해 주어야 합니다. 한번 볼게요 ㅎ


fprintf다음에 data를 넣은것이 아니라 transpose(data)=data' 를 넣었습니다.

그 결과 2.txt가 요렇게 생기게 되는거죠.

한 줄 넘어가는게 네모로 표시가 되긴 했는데... 워드패드나 엑셀 등으로 불러보면 정상적으로 표시된답니다.....ㅠ
이런식으로 저장을 합니다!!!

일단 이렇게 불러오기와 저장을 일단락 하고, 다음 내용에서
추가적으로 uiget이란 걸 이용하여 파일 저장+불러오기를 응용해보도록 할게요ㅎ

아 어지럽습니다. 어렵네요 허허허허