파일 입·출력


 지금까지 공부하면서 짰던 코드들은 프로그램이 종료되면 그대로 종료됩니다. 출력하는 내용이나 코드를 파일로 저장하고 읽어오면 다시 사용할 수 있겠죠? 파일 입·력은 파일을 열어서 쓰고 덧붙이는 방법으로, 다른 프로그래밍 언어와 유사한 형태로 사용합니다. 

- open() 내장 함수


 파일 입출력은 open()이라는 내장함수를 이용하고, 사용이 끝나면 close() 함수로 종료를 해줘야 합니다. close() 쓰지않아도 자동으로 자원을 반납하지만, 코드의 가독성을 위해서라도 써주는게 좋다고합니다. 

 아래 내용은 open() 내장 함수의 세부적인 내용입니다.
----------------------------------------------------------------------------------------

- open("filename",'mode')


- open()함수의 모드

1. 'r'(read) : 생략을 하면 기본적으로 사용되는 모드로, 읽기 전용모드, 파일 포인터를 처음위치에 놓음

2. 'w'(write) : 쓰기모드로 존재하지 않는 파일은 생성하고, 존재하는 파일내용을 모두 지우고 파일포인터를 처음위치에 놓음

3. 'a'(append) : 이미 존재하는 파일 뒤쪽에 내용을 추가, 파일 포인터를 파일의 마지막 위치에 놓음


- 이진 파일로 저장하기 위한 모드

1. rb

2. wb

3. ab

----------------------------------------------------------------------------------------


- 파일 쓰기


 파일을 쓰기에 앞서 현재 작업중인 디렉토리를 알아보는 명령을 알아보겠습니다. os모듈을 임포트하고 getcwd() 함수를 이용하면 현재 작업중인 디렉토리를 확인할 수 있습니다. 파일 쓰게되면 같은 경로에 파일이 생기게됩니다.

----------------------------------------------------------------------------------------

import os

print os.getcwd() # 현재 작업중인 디렉토리를 알아보는 함수

----------------------------------------------------------------------------------------
(실행 결과)

D:\PythonProject\Python\13

----------------------------------------------------------------------------------------


 open() 내장 함수를 이용해 파일 쓰기를 해 보겠습니다. 파일에 쓰기위해서는 write()메소드를 활용 합니다.
----------------------------------------------------------------------------------------
s='''애써 미안한 표정 하지마
싫어진 거잖아 이제 널 떠나줄게
비겁해지는 널 보는 게 아파
내가 갈게 널 보내줄게
-권진아 끝 中에서- '''

f=open('end.txt','w') # 'end.txt' 쓰기모드로 열기
f.write(s) # s 문자열을 파일에 써줌
f.close() # 자원 반납
----------------------------------------------------------------------------------------
 위 코드를 실행하면, 이클립스 콘솔창에는 아무런 내용이 출력되지 않습니다. 작업중인 코드의 경로에 가면 텍스트 파일이 하나 생성되어 있습니다. 


- 파일 읽기


이번에는 이클립스에서 텍스트 파일을 읽어보겠습니다. 파일을 읽을때에는 read()메소드를 이용합니다.

----------------------------------------------------------------------------------------
f=open('end.txt') # 모드 생략 시 읽기 모드
s2=f.read()
print s2
----------------------------------------------------------------------------------------
(실행 결과)
애써 미안한 표정 하지마
싫어진 거잖아 이제 널 떠나줄게
비겁해지는 널 보는 게 아파
내가 갈게 널 보내줄게
-권진아 끝 中에서- 
----------------------------------------------------------------------------------------


- 라인단위로 파일 읽기/쓰기


 파일을 읽을때 라인단위로 읽을 수가 있습니다. 라인 단위로 읽는 방법은 총 4가지가 있습니다.


1. 객체 반복자 사용

 아래와 같이 for-in 문을 이용해서 라인 단위로 출력이 가능합니다. 파일을 라인단위로 읽을때 가장 효율적인 방법이라고 합니다.

----------------------------------------------------------------------------------------
f=open('end.txt')

i=1

for line in f:

    print i,":",line,

    i+=1

f.close()

----------------------------------------------------------------------------------------
(실행 결과)
1 : 애써 미안한 표정 하지마
2 : 싫어진 거잖아 이제 널 떠나줄게
3 : 비겁해지는 널 보는 게 아파
4 : 내가 갈게 널 보내줄게
5 : -권진아 끝 中에서- 
----------------------------------------------------------------------------------------

2. readline() 사용
 readline()을 사용할때에는 while문을 이용합니다. 현재의 파일포인터에서 개행문자까지 읽어줍니다. 아래코드에서는 줄바꿈을 개행문자로 인지합니다. 실행 결과는 위와 동일합니다.
----------------------------------------------------------------------------------------
f=open('end.txt')
line=f.readline()
i=1
while line:
    print i,":",line,
    line=f.readline() # 파일 포인터가 개행문자 다음의 가장 처음에 위치합니다.
    i+=1
f.close()
----------------------------------------------------------------------------------------


3. readlines() 사용

 각 라인을 모두 읽어서 메모리에 리스트 형태로 저장합니다. 라인이 100줄 1000줄이면 메모리를 굉장히 비효율적으로 사용하게 됩니다. 한글이여서 아스키코드로 변화해서 저장되는걸 확인 할 수 있습니다.

----------------------------------------------------------------------------------------
f=open('end.txt')

print f.readlines() # 리스트로 저장

print # 한줄 개행


f.seek(0) # 파일포인터를 처음으로 되돌려줌

i=1


for line in f:

    print i,":",line,

    i+=1

f.close()

----------------------------------------------------------------------------------------
(실행 결과)
['\xec\x95\xa0\xec\x8d\xa8 \xeb\xaf\xb8\xec\x95\x88\xed\x95\x9c \xed\x91\x9c\xec\xa0\x95 \xed\x95\x98\xec\xa7\x80\xeb\xa7\x88\n', '\xec\x8b\xab\xec\x96\xb4\xec\xa7\x84 \xea\xb1\xb0\xec\x9e\x96\xec\x95\x84 \xec\x9d\xb4\xec\xa0\x9c \xeb\x84\x90 \xeb\x96\xa0\xeb\x82\x98\xec\xa4\x84\xea\xb2\x8c\n', '\xeb\xb9\x84\xea\xb2\x81\xed\x95\xb4\xec\xa7\x80\xeb\x8a\x94 \xeb\x84\x90 \xeb\xb3\xb4\xeb\x8a\x94 \xea\xb2\x8c \xec\x95\x84\xed\x8c\x8c\n', '\xeb\x82\xb4\xea\xb0\x80 \xea\xb0\x88\xea\xb2\x8c \xeb\x84\x90 \xeb\xb3\xb4\xeb\x82\xb4\xec\xa4\x84\xea\xb2\x8c\n', '-\xea\xb6\x8c\xec\xa7\x84\xec\x95\x84 \xeb\x81\x9d \xe4\xb8\xad\xec\x97\x90\xec\x84\x9c- ']

1 : 애써 미안한 표정 하지마
2 : 싫어진 거잖아 이제 널 떠나줄게
3 : 비겁해지는 널 보는 게 아파
4 : 내가 갈게 널 보내줄게
5 : -권진아 끝 中에서- 
----------------------------------------------------------------------------------------

4. xreadlines() 사용

 위의 readlines()의 메모리 비효율성을 개선할 수 있는 함수입니다. 리스트가 반환되지 않고, 파일 객체 내용이 찍힙니다. 사용과 실행 결과는 위와 동일합니다.



 그렇다면, 반대로 라인단위로 파일 쓰는건 어떻게 할까요? 이미 위에서 사용했던 write() 함수와 wrtielines() 함수가 있습니다. 라인단위로 파일을 쓸때에는개행문자(\n)를 꼭 써줘야 합니다.

----------------------------------------------------------------------------------------

f=open("end.txt",'a') # 기존 파일에 내용 추가

f.writelines('\n\n')

f.writelines('오늘은 2월 22일 \n')

f.writelines('하루종일 날씨가 흐리다.\n')

f.writelines('얼른 봄이 왔으면 좋겠다.\n')

f.close()


f=open('end.txt')

print f.read()

----------------------------------------------------------------------------------------

(실행 결과)

애써 미안한 표정 하지마

싫어진 거잖아 이제 널 떠나줄게

비겁해지는 널 보는 게 아파

내가 갈게 널 보내줄게

-권진아 끝 中에서- 


오늘은 2월 22일 

하루종일 날씨가 흐리다.

얼른 봄이 왔으면 좋겠다.

----------------------------------------------------------------------------------------


- 파일 내 임의 위치로 접근


 위에서 몇번 언급한 파일포인터는 파일 내에서 현재 위치를 가리키고 있습니다. 이때 seek(5)를 하면 문자열의 5번째 인덱스를 가리키게 됩니다.

 tell()을 사용하면 현재 위치를 돌려주고, read(1)을 사용하게되면 현재 위치에서 문자하나를 읽고나서 파일포인터를 하나 이동합니다.


- 표준 출력 방향 전환


 일반적으로 print 함수를 사용하게되면 문자열을 화면(콘솔)에 출력하게됩니다. sys 모듈의 sys.stdout의 표준출력이 정해져있기 때문인데, 이를 바꿔주면 print함수를 사용하면 바꿔준 형태로 실행이 됩니다.

 아래 코드는 표준출력을 파일에 저장하는것으로 바꾸고 실행 후 다시 되돌리는 코드입니다.

----------------------------------------------------------------------------------------

# -*- coding: utf-8 -*-


import sys

f=open('t.txt','w')

stdout=sys.stdout # 표준출력 저장(백업 개념)

sys.stdout=f


print '테스트 메시지1'

print '테스트 메시지2'

print '테스트 메시지3'


f.close()

sys.stdout=stdout # 다시 원상태로 되돌려줌

----------------------------------------------------------------------------------------

 아래와같이 화면(콘솔)에 출력되는것이 아니라 't.txt'파일에 문자열이 써집니다.


 이밖에도 sys모듈에는 sys.stderr(표준 에러출력)과 sys.stdin(표준 입력)이 있습니다. stderr을 변경하면, 에러메시지 처럼 콘솔창에 빨간색 글씨로 출력이 됩니다.


- StringIO 모듈 사용

 StringIO 모듈의 StringIO 클래스 객체는 사용하면, 파일 객체처럼 입출력 가능한  문자열 객체로, StringIO에 지원되는 메소드는 파일 객체가 지원하는 메소드와 거의 유사합니다. 메소드중에서 getvalue() 메소드가 있는데 현재까지 담아 놓은 전체 내용을 반환하는 메소드입니다.

----------------------------------------------------------------------------------------

import StringIO


f=StringIO.StringIO()

f.write('abc')

f.seek(0)

s=f.read()

print s


f.write('def')

s2=f.getvalue()

print s2

----------------------------------------------------------------------------------------

(실행 결과)

abc

abcdef

----------------------------------------------------------------------------------------


- 파일로의 지속 모듈


- 지속성 : 프로그램 내에 생성된 각종 객체들을 해당 프로그램 종료이후에도 존재하게 만들고, 그것들을 동일한 또는 다른 프로그램에서 사용하는 기능

- 지속성 기능을 지원하는 모듈

DBM 관련 모듈 : anydbm, dbm, gdbm, dbhash, dumbdbm

pickling 모듈 : 파이썬의 객체를 저장하는 일반화된 지속성 모듈


 pickling 모듈이 좀 더 일반적으로 사용한다고해서 pickle모듈만 사용해 봤습니다. 이클립스에서는 에러가 발생해서 Enthought Canopy로 실습을 진행했습니다.

----------------------------------------------------------------------------------------

import pickle


color={'r':'red','g':'green','b':'blue'}

fruits=['banana','apple','grape']

Tuple=(color,fruits)


f=open('pickle.txt','w')


pickle.dump(Tuple,f) # 저장하고자 하는 Tuple을 f에 넣어서 얼림

f.close()


####################################


f=open('pickle.txt')


x,y=pickle.load(f) # dump()와 반대

print x

print y

----------------------------------------------------------------------------------------




출처 한국기술교육대학교 온라인평생교육원 파이썬프로그래밍




'언어 > Python' 카테고리의 다른 글

[파이썬] 디렉토리 다루기  (0) 2017.02.25
[파이썬] 파일 다루기  (0) 2017.02.24
[파이썬] 사전  (0) 2017.02.19
[파이썬] 튜플과 집합자료형  (0) 2017.02.14
[파이썬] 리스트 활용  (4) 2017.02.07

계좌 관리 프로그램

 

 지금까지 공부한 내용들을 바탕으로 계좌 관리 프로그램을 작성해 봤습니다. 계좌를 생성하는 기능과 입금, 출금하는 기능 계좌 전체를 조회하는 기능이 있습니다. 파일 입출력을 이용해서 "data.txt"라는 텍스트 파일에 있는 계좌정보를 가져오기도하고, 계좌를 생성한 뒤에 입금, 출금 한 내용을 "data.txt"파일에 저장할 수 있도록 했습니다. "bank.h"헤더파일과 "bank.c","main.c" 세 파일로 분할 컴파일 했습니다. "bank.h"헤더파일에는 구조체 정의와 각 함수정의 및 헤더파일들을 인클루드했고, "bank.c"에서는 각 함수들의 기능 구현을 했습니다. 마지막으로 "main.c"는 "bank.h"헤더파일을 인클루드하고 "bank.c"의 함수를 호출해서 사용하도록 작성 했습니다.


- bank.h

----------------------------------------------------------------------------------------

#define NAME_LEN 20 // define은 단순매크로로 값을 정해 편하게 사용할 수 있습니다. 

// 아래 헤더파일을 bank.h에 인클루드한 이유는 main.c와 bank.c에서 사용하기 위해서 입니다.

#include <stdio.h> 

#include <stdlib.h>

#include <string.h>

#pragma warning(disable:4996)


typedef struct bank{ // 계좌정보를 저장할 구조체 선언

char *name[NAME_LEN]; // 예금주[최대20자리]

int id;                         // 계좌번호

int money;                   // 잔액

struct bank *next;

}bank;


bank *head, *tail; // 노드의 처음과 끝

void Init_account(FILE *fp); // 노드의 처음과 끝에 메모리 할당하고, 파일에서 입력을 받도록 하는 함수

void Make_account(FILE *fp); // 계좌를 생성하는 함수

void Deposit(FILE *fp); // 입금 함수

void WithDraw(FILE *fp); // 출금 함수

void WriteAccount(FILE *fp); // 계좌의 정보를 저장하는 함수

void Account_inquire(void); // 계좌를 조회하는 함수

void ReadAccount(int id, char *name, int money); // 텍스트 파일에서 입력을 받는 함수

----------------------------------------------------------------------------------------


- bank.c

----------------------------------------------------------------------------------------


#include "bank.h"


void Init_account(FILE *fp)

{

int id;

char name[NAME_LEN];

int money;

head = (bank *)malloc(sizeof(bank));

tail = (bank *)malloc(sizeof(bank));

head->next = tail;

tail->next = tail;


while (fscanf(fp, "%d %s %d", &id, name, &money) == 3){ // 정수형, 문자형, 정수형 3개일 때만 입력을 받음

ReadAccount(id, name, money);

}

}


void ReadAccount(int id, char *name, int money)

{

bank *t;

t = (bank *)malloc(sizeof(bank));

t->id = id;

strcpy(t->name, name);

t->money = money;


t->next = head->next; // 다음 노드를 가리킴

head->next = t; // 노드의 처음을 가리킴

}


void Make_account(FILE *fp)

{

int id;

char name[NAME_LEN];

int money;

bank *t;

t = (bank *)malloc(sizeof(bank));


printf("\n*********계좌 생성*********\n");

printf("계좌번호 : "); scanf("%d", &id);

printf("예 금 주 : "); scanf("%s", name);

printf("입 금 액 : "); scanf("%d", &money);


t->id = id;

strcpy(t->name, name);

t->money = money;


t->next = head->next;

head->next = t;


WriteAccount(fp); // 저장하는 함수로 파일 포인터를 넘겨줌

}


void Deposit(FILE *fp)

{

int id;

int money;

bank *t;

printf("계좌번호 : "); scanf("%d", &id);

printf("입 금 액 : "); scanf("%d", &money);


for (t = head->next; t != tail; t = t->next)

{

if (t->id == id)

{

t->money += money; // 잔액에 입금할 금액을 더해서

WriteAccount(fp); // 저장

return;

}

}

printf("없는 계좌번호입니다.\n");

}


void WithDraw(FILE *fp)

{

int id;

int money;

bank *t;

printf("계좌번호 : "); scanf("%d", &id);

printf("출 금 액 : "); scanf("%d", &money);


for (t = head->next; t != tail; t = t->next)

{

if (t->id == id)

{

if (t->money<money) // 출금액이 잔액보다 클 경우

{

printf("출금액이 잔액을 초과할 수 없습니다.\n");

return;

}

else{

t->money -= money; // 잔액에서 출금액을 빼서

}

WriteAccount(fp); // 저장

return;

}

}

printf("없는 계좌번호입니다.\n");

}

void Account_inquire(void)

{

bank *t;

for (t = head->next; t != tail; t = t->next)

{

printf("\n*********잔액 조회*********\n");

printf("계좌번호 : %d\n", t->id);

printf("예 금 주 : %s님\n", t->name);

printf("잔    액 : %d원\n\n", t->money);

}

}


void WriteAccount(FILE *fp)

{

bank *t;

rewind(fp); // 파일 읽는 포인터 지점을 맨 첨으로 돌리는 함수

for (t = head->next; t != tail; t = t->next)

{

fprintf(fp, "%d %s %d\n", t->id, t->name, t->money);

}

}

----------------------------------------------------------------------------------------


- main.c

----------------------------------------------------------------------------------------

#include "bank.h"

int main()
{
int input;
FILE *fp;
fp = fopen("data.txt", "r+"); // 파일모드가 r+일 경우  읽고쓰기를 동시에 수행 합니다.
Init_account(fp);

do{
printf("계좌 생성&관리 프로그램입니다. 원하시는 번호를 입력하세요.\n");
printf("*********************************************\n");
printf("1)계좌 생성 2)계좌 조회 3)입금 4)출금 5)종료\n");
printf("*********************************************\n");
printf("입력 >");
scanf("%d", &input);

switch (input){
case 1:
Make_account(fp);
break;
case 2:
Account_inquire();
break;
case 3:
Deposit(fp);
break;
case 4:
WithDraw(fp);
break;
case 5:
input = 0;
free(head); // 종료하면서 메모리 반환
free(tail);
break;
default:
printf("잘못 입력하셨습니다. \n");
return main();
}
}
while (input != 0);
}

----------------------------------------------------------------------------------------


 위 코드의 실행 결과는 다음과 같습니다. 우선 "data.txt"파일에 초기값으로 아래 그림과 같이 입력 하고 저장한뒤에 프로그램을 실행했습니다.


 계좌 하나를 추가로 생성하고, 새로만든 계좌와 기존의 계좌 각각 입금, 출금을 수행했습니다. 


 계좌를 조회하고 종료하는 그림입니다. 새로만든 계좌와 기존의 계좌 모두 정상적으로 출력됩니다. "data.txt"파일에도 저장되었을까요?


 살짝 깨지기는 했지만 값이 정상적으로 저장된걸 확인 할 수 있습니다.




'언어 > C' 카테고리의 다른 글

VSCODE 환경 C개발 환경  (0) 2019.03.27
[C] 파일 입·출력  (0) 2017.01.05
[C] 자기 참조 구조체와 연결리스트  (2) 2017.01.04
[C] 동적 메모리  (0) 2017.01.03
[C] 공용체  (0) 2016.12.27

파일 입·출력


 파일에 대한 개념은 잘 알고계실겁니다. 응용 프로그램 부터 시작해서 텍스트파일 엑셀파일 등 모든 파일이 파일에 속합니다. 지금까지 앞에서 공부했던 내용들만 가지고 프로그램을 짜보면 한번 실행하면 다시 또 처음부터 실행해야됩니다. 파일 입·출력을 이용하면 파일을 이용해서 입력을받거나, 프로그램에서 입력한 내용을 파일로 출력을 할 수 있습니다. 파일 입·출력은 <stdio.h>헤더파일을 인클루드 하면 사용할 수 있습니다.


 우선, 파일 입·출력 공부에 앞서 비쥬얼 스튜디오의 프로젝트 경로를 쉽게 확인할 수 있는 방법을 알려드리겠습니다. 파일의 입력, 출력을 하기위해서는 소스코드가 생성되는 프로젝트 경로를 알고 있어야합니다. 아래 그림처럼 프로젝트를 우클릭하고 "파일 탐색기에서 폴더 열기"를 누르면 소스코드가 있는 프로젝트의 경로가 열립니다.



파일 입력

 파일 입력은 파일 열기, 작업, 파일 닫기 세 단계로 구성됩니다. 파일 열기는 fopen()함수, 파일에서 값을 불러올때는 fscanf()함수 파일을 닫을때는 fclose()함수를 사용합니다. 파일을 열고나서 닫지 않으면, 다른 곳에서 해당파일에 접근할 수 가 없으므로 꼭 사용한 후에는 닫아줘야 합니다. 파일 입·출력에서는 파일 포인터를 사용합니다. 파일 포인터는 타입이 파일인 포인터 라고 생각하시면 됩니다.


- fopen()함수

 파일을 열 때 사용하는 함수입니다. 열 파일이 존재하지 않거나, 실패할 경우 NULL값을 반환합니다.

----------------------------------------------------------------------------------------

fopen(파일이름, 파일모드); // 파일모드 r(read)=읽기 w(write)=쓰기(파일 출력에 사용)

FILE *fp; // 파일포인터 선언

fp=fopen("test.txt","r"); // test.txt 파일을 읽기

----------------------------------------------------------------------------------------


- fscanf()함수

 fscanf()함수는 파일의 내용을 읽어올 때 사용하는 함수로, 파일 포인터를 인자값으로 사용한다는 점 외에는 scanf()함수와 유사합니다.

----------------------------------------------------------------------------------------

fscanf(파일 포인터, 포맷 문자열, 값1, 값2 ...);

FILE *fp; // 파일포인터 선언

int i;
fscanf(fp,"%d",&i);

----------------------------------------------------------------------------------------


- fclose()함수

 fclose()함수는 파일을 닫는 함수로, 열려있는 파일 포인터를 인수로 넘겨주면 파일을 닫는 역할을 합니다. 

----------------------------------------------------------------------------------------

fclose(파일 포인터);

FILE *fp; // 파일포인터 선언

fclose(fp);

----------------------------------------------------------------------------------------


 위 세 함수를 이용해서 "data.txt"라는 파일에 정수를 입력해서, "data.txt"파일을 입력 받고 정수를 출력하는 코드를 작성해 봤습니다. 이 때 "data.txt"처럼 사용 할 파일은 소스파일과 같은 경로에 있어야 합니다. 아래 그림은 "data.txt"입니다.

----------------------------------------------------------------------------------------

#include <stdio.h>

#include <stdlib.h>

#pragma warning(disable:4996)


int main()

{

int a,b; // 파일에서 읽어올 때 fscanf에 사용할 변수a와 반복문에 사용할 변수 b 선언

int *data; // 동적메모리에 사용할 정수형 포인터 선언

FILE *fp; // 파일포인터 fp 선언

fp = fopen("data.txt","r"); // "data.txt"파일 열기


if (fp != NULL) // 파일이 정상적으로 열렸을 때 if문실행

{

fscanf(fp,"%d",&a); // "data.txt"파일의 첫번째 값을 입력받아서

data = (int *)malloc(sizeof(int)*a); // 첫번째 값만큼 동적으로 정수형 배열을 만듭니다.

for (b = 0; b < a; b++) // 배열의 크기만큼 값을 입력 받음

{

fscanf(fp, "%d", &data[b]); 

}

fclose(fp); // 입력을 받은뒤에 파일닫기


for (b = 0; b < a; b++) // 입력받은 배열을 출력

{

printf("data[%d] : %d \n", b, data[b]);

}

free(data); // 메모리 반환

} //close if()


else{

printf("파일 입력받기 실패 \n"); 

}

}

----------------------------------------------------------------------------------------

 위 코드를 실행한 결과입니다. "data.txt"의 처음 값은 배열의 크기가 되고, 나머지 값들은 순차적으로 배열에 저장해서 출력했습니다.


파일 출력

 파일 출력은 두 가지로 나뉩니다. 기존 파일을 사용해서 출력하는 방법과 새로운 파일을 만들어서 출력하는 방법이 있습니다. 두 방법은 기존의 파일을 이용하는 점과 새로만든다는 점만 다를뿐 구현방법은 동일합니다. 파일 출력은 파일 입력과 동일하게 fopen()함수를 사용합니다. fscanf()함수와 반대로 fprintf()함수를 이용해 파일에 출력합니다.


- fopen()함수

 fopen()함수의 파일모드에는 r(read),w(write)외에도 a(append)가있습니다.

----------------------------------------------------------------------------------------

fopen()함수의 파일모드

- w = 해당 파일이 없으면 파일을 생성, 해당 파일이 있으면 내용을 덮어쓰기

- a = 해당 파일이 없으면 파일을 생성, 해당 파일이 있으면 파일의 끝부터 내용 추가

----------------------------------------------------------------------------------------


- fprintf()함수

 fprintf()함수는 파일에 문자열을 출력하는 함수로 파일 포인터를 인자값으로 사용한다는 점 외에는 printf()함수와 유사합니다.

----------------------------------------------------------------------------------------
FILE *fp;
fprintf(fp,"문자열 : %s \n",text);
----------------------------------------------------------------------------------------

 문자열이 아닌 자료형 등의 데이터를 읽고 쓰려면 어떻게 해야될까요? 이때는 2진수(binary)값을 직접 읽고 씁니다. fopen()함수의 기존 파일모드에 b를 붙여서 사용합니다. 바이너리 값을 읽고 쓸때에는 fread()함수와 fwrite()함수를 사용합니다.

----------------------------------------------------------------------------------------
fopen(“data.txt”, “rb”);
fopen(“data.txt”, “wb”);

size_t fread( void *ptr, size_t size, size_t nitems, FILE *stream); 
(파일에서 읽은 값을 저장할 포인터, 자료형의 크기, 자료형의 개수, 파일 포인터)
size_t fwrite( void *ptr, size_t size, size_t nitems, FILE *stream);
사용 방법은 동일하지만, 변수 포인터에 들어있는 값을 파일에 쓴다는점이 다릅니다.
----------------------------------------------------------------------------------------

아래 코드는 바이너리 값으로 구조체를 파일로 저장하고 읽어오는 코드입니다.

----------------------------------------------------------------------------------------

#include <stdio.h>

#include <stdlib.h>

#pragma warning(disable:4996)


struct Node{

int a;

double b;

};


int main()

{

struct Node *print;

FILE *fp;

fp = fopen("data.txt", "wb"); // 바이너리값으로 저장


print = (struct Node*)malloc(sizeof(struct Node));

print->a = 1;

print->b = 3.14;

fwrite((void*)print, sizeof(struct Node), 1, fp);

fclose(fp); // 파일 닫기

  free(print); // 메모리반환

}

----------------------------------------------------------------------------------------

 위 코드를 실행하면 도스창에는 아무런 문자열도 출력되지 않습니다.

 "data.txt"파일을 열어보면 아래 그림과 같이 1과 3.14가 아닌 깨진 문자들이 출력이 됩니다. 잘못 저장된걸까요?


 위에 저장된 "data.tx"t파일을 읽어와서 출력하는 코드입니다.

----------------------------------------------------------------------------------------

#include <stdio.h>

#include <stdlib.h>

#pragma warning(disable:4996)


struct Node{

int a;

double b;

};


int main()

{

struct Node *open;

FILE *fp;

fp = fopen("data.txt", "rb"); // 바이너리값으로 불러오기


open = (struct Node*)malloc(sizeof(struct Node));

fread((void*)open, sizeof(struct Node), 1, fp);


printf("open->a = %d \n", open->a);

printf("open->b = %.2lf \n", open->b);


fclose(fp); // 파일닫기

free(open); // 메모리반환


}

----------------------------------------------------------------------------------------

 위 코드의 실행결과입니다. 파일을 출력했을때의 값이 정상적으로 출력되는걸 확인할 수 있습니다.


* 출처 : 한국기술교육대학교 온라인평생교육원 C 프로그래밍_2 

          스타일 C프로그래밍 저.김종훈,김종진 출.WellBook




'언어 > C' 카테고리의 다른 글

VSCODE 환경 C개발 환경  (0) 2019.03.27
[C] 계좌 관리 프로그램  (2) 2017.01.10
[C] 자기 참조 구조체와 연결리스트  (2) 2017.01.04
[C] 동적 메모리  (0) 2017.01.03
[C] 공용체  (0) 2016.12.27

+ Recent posts