<fopen 관련> "w" 모드로 연 파일엔 써지는데.. "w+" 모드로 연 파일엔 안 써짐
소켓 프로그래밍을 통해 원격 서버에서 읽어온 메세지를 파일에 쓰려고 합니다.
처음에 아래와 같이 파일을 열었습니다.
if((raw_html_fd=fopen(tmpfile,"w+"))==NULL)
{
fatal("Could not open temporary file for storing raw html document");
}
위와 같이 파일을 열고 mincho.hani.co.kr 라는 사이트의 html 문서를 읽어와 fwrite()을 이용해 raw_html_fd 에 썼습니다. fwrite() 의 리턴값은 '5945' 이던가로 기억됩니다만 상황에 따라 달라지겠죠.. 어쨌든 '0' 은 아니었습니다. (아래 실행 화면 참조)
그런데 해당 파일을 열어보니.. 아무것도 안 써져 있었습니다.
혹시나 하는 마음에 아래와 같이 파일을 "w" 모드로 열었습니다.
if((raw_html_fd=fopen(tmpfile,"w"))==NULL)
{
fatal("Could not open temporary file for storing raw html document");
}
아래와 같이 실행을 했습니다.
그 후, 파일을 열어 봤습니다. 그랬더니 아래처럼 내용이 써져 있네요..
man 페이지를 참조해 보니..
w or wb : truncate to zero length or create file for writing
w+ or wb+ or w+b : truncate to zero length or create file for update
와 같이 나와 있던데...
파일에 쓰는 건 둘 다 마찬가지 아닌가요?
그런데 왜 "w+" 로 파일을 열면 안 써지는 건가요?
혹시나 하는 마음에 "a" 와 "a+" 에 대해서도 해 봤는데.. 역시 "a" 로 파일을 열었을 경우엔 정상적으로 써지는데, "a+" 로 열었을 경우엔 "w+"와 마찬가지로 빈 파일이 생성됩니다.
fopen말고 다른 파일
fopen말고 다른 파일 입출력 관련 소스도 보여주세요.
문제의 소스가
문제의 소스가 부족하군요.
버그를잡으실려면 소스를 보여 주든지해야 가능하죠..
----------------------------------------------------------------------------
전체 코드입니다..^^;;
#include "engine_header.h"
//PORT : port number through which we can access target site
#define PORT 80
//MAXBUFSIZE : maximum capacity of buffer for retrieving web page from remote site
#define MAXBUFSIZE 20000
int ret_html(char *target_site,char *msg_to_server,pid_t crawler_pid,int doc_num)
{
int sockfd,numbytes;
char buf[MAXBUFSIZE+1]; //buffer for retrieving web text
struct hostent *he;
struct sockaddr_in their_addr;
char *prefix="txt_from_html"; //prefix to be attached to the output filename
char tmpfile[50]; //Temporary file storing raw html document
char txtfile[50];
//Text file which resulted from temporary html document by eliminating tags
//-------------------------------------------------------------------------------
//Create filename : tmp__.txt for raw html file
// __.txt for tag_eliminated file
//To show which crawler has retrieved that page, attach crawler_pid to filename
//To show document number , attach doc_num to file name
//To show this file is text file, attach expension '.txt' to the file name
//-------------------------------------------------------------------------------
sprintf(tmpfile,"%s%d%s%d%s","html_",(int)crawler_pid,"_",doc_num,".txt");
//is a temporary file name storing raw html document
sprintf(txtfile,"%s%s%d%s%d%s",prefix,"_",(int)crawler_pid,"_",doc_num,".txt");
//is a tag-eliminated text file name
//------------------------------------------------------------------------------
FILE *raw_html_fd; //FILE structure for raw html document
FILE *tag_eliminated_fd; //FILE structure for tag-eliminated html document
if((raw_html_fd=fopen(tmpfile,"w"))==NULL)
{
fatal("Could not open temporary file for storing raw html document");
}
if((tag_eliminated_fd=fopen(txtfile,"w"))==NULL)
{
fatal("Could not open tag-eliminated file");
}
//------------------------------------------------------------------------------
if((he=gethostbyname(target_site))==NULL) {
herror("gethostbyname in ret_html()");
printf("%d\n",h_errno);
exit(1);
}
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
{
fatal("socket in ret_html()");
}
their_addr.sin_family=AF_INET;
their_addr.sin_port=htons(PORT);
their_addr.sin_addr=*((struct in_addr *)he->h_addr);
bzero(&(their_addr.sin_zero),8);
if(connect(sockfd,(struct sockaddr *)&their_addr,sizeof(struct sockaddr))==-1)
{
fatal("connect in ret_html()");
}
int bytes_sent;
if((bytes_sent=send(sockfd,msg_to_server,strlen(msg_to_server),0))==-1)
{
fatal("send in ret_html()");
}
//----------------------------------------------------------------
//Following while loop retrieve numbytes bytes from target site
//Each time search engine retrieves web page from target site,
//----------------------------------------------------------------
int i; //for couting the number of zero bytes receptions
int totalbytes=0; //for total bytes read
while((numbytes=recv(sockfd,buf,MAXBUFSIZE,0)) != -1)
{
//Test ----------------------------------------
//printf("numbytes read : %d\n",numbytes);
//Test ----------------------------------------
if(numbytes == 0)
{
i++;
if(i == 5)
{
printf("\nZero bytes received over the predefined limit\n");
break;
}
else
{
// printf("Zero bytes received\n");
sleep(1);
continue;
}
}
else
{
totalbytes += numbytes;
if(fwrite((void *)buf,sizeof(char),numbytes,raw_html_fd) != numbytes)
{
fatal("fputs in ret_html()");
}
//insert '\n' to output file to avoid 'line too long' error
putc('\n',raw_html_fd);
//Wait for receiving new message from remote web server
//(Essential part for retrieving full html document)
sleep(1);
}
}
//Test ------------------------------
printf("totalbytes : %d\n",totalbytes);
printf("numbytes : %d\n",numbytes);
//Test ------------------------------
//----------------------------------------
//Eliminate tags from raw html document
//----------------------------------------
tag_eliminator(raw_html_fd,tag_eliminated_fd);
//Test --------------
printf("raw HTML file : %s\n",tmpfile);
//------------------
//----------------------
//Close file descriptor
//----------------------
fclose(raw_html_fd);
fclose(tag_eliminated_fd);
//---------------------------
//Close socket descriptor
//----------------------------
close(sockfd);
return 0;
}
//--------------------------
이 부분이 수상합니다.
tag_eliminator() 안에서 raw_html_fd의 내용을 읽으려고 하신 거 아닙니까?
출력 스트림의 내용을 읽으려고 하는 것은 잘못이지요. 위의 그림을 보니까
"w" 모드로 출력한 파일의 내용도 정상적으로 보이지는 않네요.
이런 식으로 해보세요.
"w+" 모드일 때는 이렇게 해도 됩니다.
해결 됐습니다..^^
감사합니다..^^
doldori 님께서 말씀하신대로 하니까 정상적으로 동작하네요..^^
예상하신 것과 같이 tag_eliminator() 내부에 getc(raw_html_fd) 를 호출하는 부분이 있었습니다.
tag_eliminator() 를 호출하는 부분을 주석처리한 경우와,
tag_eliminator() 를 호출하되, 말씀하신 것처럼 rewind(raw_html_fd) 를 먼저 호출한 경우에 대해서 실행시켜 봤는데.. 정상적으로 동작합니다.
그런데.. 일단 파일에 쓰는 작업을 마친 후에, 별도의 함수(tag_eliminator) 를 호출해 읽는 작업을 수행하는데.. 파일에 써지는 건 제대로 써져야 하는 거 아닌가요?
w+ 로 열었으니까.. 일단 쓰는 건 제대로 써지고.. 그 후에 읽는 과정에서 rewind() 를 안 해줘서 문제가 발생한 걸로 보이는데..
문제가 읽어오는 데서 발생해야 할 것 같은데.. 왜 쓰는 것까지 영향을 받는건지 모르겠습니다...
update mode로 입출력을
update mode로 입출력을 할 때 주의할 점은
출력->입력으로 바뀔 때 fflush() 또는 file positioning 함수(fsetpos(), fseek(), rewind() 등)을,
입력->출력으로 바뀔 때 file positioning 함수를 그 사이에 넣어줘야 한다는 겁니다.
그렇지 않으면 그 결과는 알 수 없죠. 지금처럼 아무것도 쓰지 않거나
일부만 쓰거나 전혀 엉뚱한 내용을 쓸 수도 있습니다.
감사합니다..^^
많은 도움이 됐습니다..
좋은 하루 보내세요..^^
댓글 달기