Fortran90 파일 읽기 기본적인 질문

knightflow의 이미지

Fortran90에서 파일을 읽을 경우,

파일 내의 데이터 중에서 빈 곳이 있을 경우 어떻게 처리해야하나요?

예를 들어,

1 2 3 4
a c d
i j

이런 식으로 중간중간 공백이 있을 경우 컴파일 후 실행을 하게 되면

'At line xx of file test.f90 (unit=200, file='test.dat')
Fortran runtime error: Bad real number in item 13 of list input'

이라는 메시지가 뜨면서 안되더라구요.

당장 생각나는 원인은 위 처럼 공백이 있어서 그런 것 같구요.

저런 공백이 있을 경우 어떻게 읽어야 하나요? 무슨 옵션이 따로 있는건지 모르겠네요..

yeonpil_net의 이미지


1. 기본적인 list directed input은 공백, 콤마 를 구분자로 하여 읽어들입니다. fmt=* 의 경우

2. 님의 에러는 입력 예를 보면 읽어 들이는 포맷이 실수인데 데이터가 실수가 아니라서 생기는 문제인 듯 보이네요.

!23456---1----+----2----+----3----+----4----+----5----+----6----+----7-2--+----8
"배웠다"는 "할 수 있다"의 동의어가 아니다.

knightflow의 이미지

1. 공백이 구분자가 아니고, column 데이터가 있다면 데이터가 있어야할 자리에 공백이 있는거죠. 그러니까...데이터가 띄엄띄엄 있다고 해야하나요..^^;;

2. 데이터 테이블 주석에는 분명 F6.3 이라고 되어 있어서 real(8)이면 되겠지해서 선언했는데, 이러네요...ㅜㅜ 문제는 그 전 column의 경우, 정보도 동일하고 선언도 똑같이 했음에도 잘 읽혔다는 것;;

yeonpil_net의 이미지

포멧이 일정치 않다는 이야기네요.

흔히 다른 언어에서 말하는 파싱 parsing을 해야 할 수도 있습니다.

프로그램을 "어느 정도까지 유연하게 작동시킬 작정인지" 선택하시고..

라인전체를 문자열로 읽고, 구분자 등으로 구분시키고.. 등등

또는 보통 심플하게 예상되는 포멧과 다른 입력라인은 그냥 넘어가게 한다든지 하게되죠.

포멧문을 동적으로 결정하게 할 수도 있고...

!23456---1----+----2----+----3----+----4----+----5----+----6----+----7-2--+----8
"배웠다"는 "할 수 있다"의 동의어가 아니다.

knightflow의 이미지

공백 데이터는 null로 판단 혹은 skip할 수 있게 해 줄 수 있으면 좋은데,

포트란90의 기본만 쓰다보니 저런 자세한 옵션 설정들은 잘 모르겠더라구요...

구현을 못하겠지만 생각해본 방법은,

1. 공백 데이터를 null로 판단하고 넘어가거나 skip할 수 있게 한다.

혹은

2. 만약 포맷 판단이 잘못된 거라면, 앞의 12개 컬럼은 따로 포맷 지정없이 그대로 읽고 에러나는 컬럼만 포맷을 지정하여 읽는다.

정도입니다.

1번의 경우는 방법(혹은 옵션)을 모르겠고..;;

2번의 경우는 format을 12x, 6f6.3 (에러나는 해당 컬럼 앞에 12 컬럼이 있고, 에러나는 컬럼 포함하여 이후로 6개 컬럼이 있습니다.) 로 지정했는데, 아무래도 x는 그냥 아예 안 읽고 지나가라는 의미 같더라구요.
이것 역시 방법을 잘 몰라서 못했네요.

yeonpil_net의 이미지

그 정도 io처리는 매우 기본적인 사용법이라서..

open문에 들어가는 속성, read문에 대한 속성, format, 포트란의 기본 i/o에 대한 것은 프로그래밍의 기본지식이라..

!23456---1----+----2----+----3----+----4----+----5----+----6----+----7-2--+----8
"배웠다"는 "할 수 있다"의 동의어가 아니다.

knightflow의 이미지

이런 속성은 잘 사용을 안해봐서..

그럼 만약 간단하게 아래와 같은 데이터가 있다고 가정했을 때, (tab으로 구분된 데이터)

1 (tab) 2 (tab) 3 (tab) (blank) (tab) 4
5 (tab) 6 (tab) (blank) (tab) 7 (tab) 8
4 (tab) (blank) (tab) 6 (tab) 7 (tab) 8
3 (tab) (blank) (tab) 1 (tab) 6 (tab) 7

(blank)는 아무런 데이터가 없는 공백
------------------------------------------------
program testpro

implicit none

integer :: io_status, i, j
integer, dimension(:) :: a(4), b(4), c(4), d(4), e(4)

in_file = 'test.dat'
open(unit=10, file=in_file, status='old')
do i=1, 4
read(10,fmt='(5i1)',iostat=io_status) a, b, c, d, e
if(io_status .ne. 0) then
write(0,*) 'read error or blank', io_status
endif
enddo

end testpro
------------------------------------------------

이렇게 하게 되면 첫번째 row를 읽고 에러 메시지가 뜨면서 종료되더라구요.(에러코드번호는 5010)
혹시 에러가 있더라도 메시지만 띄우고 계속 읽도록 하려면 어떻게 해야할까요?

yeonpil_net의 이미지

1. 포트란에서 탭은 표준적으로 기본 character set이 아닙니다.
2. 입력에 탭이 있으면 보통 포트란 컴파일러들은 기본적으로 white space 취급을 하긴 합니다.
3. 포멧에서 X descriptor를 이용할 수 있습니다.
4. 탭과 기본 화이트스페이스의 개수가 반복 섞여있네요.. 입력이 저런 모양이면 list directed 형태의 입력이 가장 편할 때가 많습니다. fmt=*. 알아서 white space또는 콤마를 구분자로하여 입력구분을 합니다.
5. 완전하게 포멧 매칭및 파싱을 시도해볼 수도 있지만.. 그건 힘드시겠죠. 그렇게까지 무리할 필요도 없을 테고요.
6. 포트란은 배열지향적 언어입니다. a는 a전체를 의미하는 표현입니다. read ..... a(4), b(4) ...e(4) 배열의 모든 원소의 개수의 합은 20이 되겠죠. 하지만 fmt=5i1 을 하셨네요. 포멧문과 리스트의 개수를 매칭하는 아주 기본적인 것들을 더 아셔야 할 정도이십니다.
7. iostat으로 포멧 불일치 에러에 대한 에러 번호가 저장되면, 기본적으로 프로그램을 그냥 에러 종료시키진 않게되죠. 코드에 분기하라고 된 곳으로 가는 것이죠. read를 한번 더하면 다른 라인을 읽을 것이고
기본적으로 do loop 의 다음 cycle로 보내면 되겠죠. format 불일치는 iostat값에 양수값이 저장될 겁니다. EOF를 만나면 음수가 저장되고...

if (iostat /= 0) -> 문제상황
=> iostat > 0 -> 포멧 불일치및 기타 read 에러 => 처리를 따로 할지. 그냥 줄넘김 할 지 결정.
=> iostat < 0 -> 파일끝 만남 => 더이상 read하지 않음. 루프바깥으로 exit
else
정상 read
endif

의 구조가 됩니다.

소스코드에서든 입력되는 텍스트에서든 포트란에선 탭은 안쓰는게 좋습니다.
뭐 윈도 비주얼 포트란계열에서 고정형식 코딩시 첫 6스페이스 공백 대신 탭을 집어넣는 방법을 쓰기도 하지만.. 바람직하지 않은 방법입니다. 인텔 컴파일러에서도 이제 그렇게 하지마라고 권고하고요.

!23456---1----+----2----+----3----+----4----+----5----+----6----+----7-2--+----8
"배웠다"는 "할 수 있다"의 동의어가 아니다.

knightflow의 이미지

예를 든다고 급하게 쓴 코드라서 설명이 조금 부족했네요.

1. 데이터와 데이터를 구분해주는 간격을 탭으로 해주었고, 이건 제가 만든 데이터가 아닌 다른 곳에서 제공하는 것을 받아온 것으로 제가 불러와서 사용해야할 데이터 형식입니다.
경험상 아래의 read 문 형식처럼 읽게 되면 에러없이 읽혔습니다. character set이 아니다라는 게 무슨 의미인지 모르겠지만,
이해하기로는 기본 character에 포함되진 않지만 지원은 되는 것이다..라는 의미인 것 같군요.
2. 1번과 이어지는 내용으로...탭을 포트란에서는 white space형식으로 취급(일종의 지원?;;)하는 것이군요.
3. x descriptor는 데이터와 데이터 사이의 공백을 지정해주는 포맷으로 알고 있습니다. 보통 데이터를 읽어들일 때 혹은 데이터를 쓸 경우 사용하지 않아도 무방했습니다.
4. 처음에 fmt=* 형태로 읽도록 했지만, 에러 메시지가 뜨면서 안되어 포맷을 지정하게 되었습니다.
5. 파싱이 뭔지 잘 모르겠네요. 허나 5번에서 말씀하신게 혹시 각 열을 character 형식으로 불러와서 열마다 하나하나의 character를 읽어들이면서 구분해주는 형식인 것 같은데 맞는지 모르겠습니다.
6. 이 부분은 제가 급히 쓰느라 빠뜨린 부분이 있네요. do 문 안에 있으니 a(i), b(i).... 형식으로 적는게 맞고.....fmt는 1자리의 정수형 데이터가 5개가 있다는 의미로 자주 사용했던 표현인데, 어떤 점이 잘못되었는지 모르겠네요.
아마 탭을 제가 괜히 표기를 해서 헷갈리신건지....탭은 그냥 구분자인데 혹시나 싶어 표기를 한 것입니다. 예시는 하나의 열에 5개의 정수형 데이터가 있다는 것을 표현한 것 입니다.
7. 그냥 줄넘김을 하는 것을 어떻게 해야할 지 모르겠는게 이번 질문의 요점이었습니다. i=i+1 처럼 해서 다시 동일한 read 문을 반복해야하는 건지......ㅜㅜ

yeonpil_net의 이미지

1.2 -> 네 그렇습니다.
3.6 -> 포멧을 이용해 입력을 할 때, X를 이용해야 합니다. 보통이란 상황^^
-> 1자리의 정수 5개만 있지 않은데요.. 입력값 중간에 공백과 탭이 있는 것이잖아요. X 쓰라는 겁니다.
-> fmt=* 의 경우 저 공백과 탭등 white space에 대해 알아서 처리해줍니다. 포멧을 쓸땐 정확히 명시를 다 해줘야죠.
fmt*='(5i1)' 는 각 하나의 문자를 하나의 정수로 5번연속이란 의미입니다.
------------------------------
12345
56781
...

------------------------------
저런 형태를
각 1,2,3,4,5로
각 5,6,7,8,1로
읽기 위해서 써야죠. 입력파일이란 것은 엄밀히 전부 그냥 문자인 것입니다.

5. 네
7. do loop안에서 read 에러시 cycle, exit 등으로 분기. 또는 기타 처리하면 됩니다. cycle하면 한번 넘어가는 것이 되겠죠.
8. real을 읽을 때는 포멧에 f 지시자입니다. I가 아니라.
read 포멧 안에는 정수로 읽는다하면서, 변수는 real로 선언된 것을 나열해서 에러가 납니다.

!23456---1----+----2----+----3----+----4----+----5----+----6----+----7-2--+----8
"배웠다"는 "할 수 있다"의 동의어가 아니다.

knightflow의 이미지

- 쓰신 것처럼 실제 데이터는 구분자가 탭인 저러한 형태입니다. 아마 그 탭도 인지시켜주기 위해 x를 사용하여 더욱 명확히 포맷을 지정하라는 말씀이신 것 같군요.
저도 평소에는 그냥 fmt=*로 했었는데, 이번에 좀 더 확실히 개념이 잡고 갑니다.^^

- cycle이라는게 있었군요. 아무리 어떤 예문이나 문헌을 보아도 exit는 많이 나오는데 cycle은 못봐서 결국 여기에도 질문을 한 것입니다.

- 아마 a(i)..... 이 부분에서 오해가 있었던 것 같은데, 여기서 i는 do loop을 돌리기 위한 변수로 사용된 i 입니다. 선언도 integer로 했구요. 뭐..글로써 질문하고 답하고
하는 과정이다보니 좀 한계가 있는 것 같습니다.

어쨌든 이번 기회에 연필님 덕분에 많이 배워갑니다.^^

너무 초보적인 질문이라 답답하셨을 수도 있을텐데 꾸준히 답해주셔서 고맙습니다.

정말 감사합니다.

yeonpil_net의 이미지

^^ 코드엔 정수로 선언하셨는데.. 맨 처음 에러메세지는 real변수에 제대로된 값이 안들어왔다는 메세지라서..

!23456---1----+----2----+----3----+----4----+----5----+----6----+----7-2--+----8
"배웠다"는 "할 수 있다"의 동의어가 아니다.

knightflow의 이미지

중간에 예시 코드는 처음 에러 메시지와는 직접적인 관련이 없습니다.

처음 에러 메시지는 현재 제가 활용하는 실제 코드에 의한 메시지이고,

중간에 예시코드는 그 이전에 지적해주신 여러 옵션들의 활용방안에 대해 여쭙고자 임의로 보인 것입니다.

헷갈리게 해드려 죄송합니다.^^;;

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.