<fopen 관련> "w" 모드로 연 파일엔 써지는데.. "w+" 모드로 연 파일엔 안 써짐

cabjaewon의 이미지

소켓 프로그래밍을 통해 원격 서버에서 읽어온 메세지를 파일에 쓰려고 합니다.

처음에 아래와 같이 파일을 열었습니다.

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+"와 마찬가지로 빈 파일이 생성됩니다.

File attachments: 
첨부파일 크기
Image icon 1.JPG31.5 KB
Image icon 2.JPG20.96 KB
Image icon 3.JPG56.97 KB
Image icon 4.JPG95.55 KB
kewlbear의 이미지

fopen말고 다른 파일 입출력 관련 소스도 보여주세요.

ㅡ,.ㅡ;;의 이미지

문제의 소스가 부족하군요.
버그를잡으실려면 소스를 보여 주든지해야 가능하죠..


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

cabjaewon의 이미지

#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;
}

doldori의 이미지

//----------------------------------------
//Eliminate tags from raw html document
//----------------------------------------
tag_eliminator(raw_html_fd,tag_eliminated_fd);

이 부분이 수상합니다.
tag_eliminator() 안에서 raw_html_fd의 내용을 읽으려고 하신 거 아닙니까?
출력 스트림의 내용을 읽으려고 하는 것은 잘못이지요. 위의 그림을 보니까
"w" 모드로 출력한 파일의 내용도 정상적으로 보이지는 않네요.
이런 식으로 해보세요.

fclose(raw_html_fd);
raw_html_fd = fopen(tmpfile, "r");
tag_eliminator(raw_html_fd,tag_eliminated_fd);

"w+" 모드일 때는 이렇게 해도 됩니다.

rewind(raw_html_fd);
tag_eliminator(raw_html_fd,tag_eliminated_fd);

cabjaewon의 이미지

감사합니다..^^

doldori 님께서 말씀하신대로 하니까 정상적으로 동작하네요..^^

예상하신 것과 같이 tag_eliminator() 내부에 getc(raw_html_fd) 를 호출하는 부분이 있었습니다.

tag_eliminator() 를 호출하는 부분을 주석처리한 경우와,
tag_eliminator() 를 호출하되, 말씀하신 것처럼 rewind(raw_html_fd) 를 먼저 호출한 경우에 대해서 실행시켜 봤는데.. 정상적으로 동작합니다.

그런데.. 일단 파일에 쓰는 작업을 마친 후에, 별도의 함수(tag_eliminator) 를 호출해 읽는 작업을 수행하는데.. 파일에 써지는 건 제대로 써져야 하는 거 아닌가요?

w+ 로 열었으니까.. 일단 쓰는 건 제대로 써지고.. 그 후에 읽는 과정에서 rewind() 를 안 해줘서 문제가 발생한 걸로 보이는데..

문제가 읽어오는 데서 발생해야 할 것 같은데.. 왜 쓰는 것까지 영향을 받는건지 모르겠습니다...

doldori의 이미지

update mode로 입출력을 할 때 주의할 점은
출력->입력으로 바뀔 때 fflush() 또는 file positioning 함수(fsetpos(), fseek(), rewind() 등)을,
입력->출력으로 바뀔 때 file positioning 함수를 그 사이에 넣어줘야 한다는 겁니다.
그렇지 않으면 그 결과는 알 수 없죠. 지금처럼 아무것도 쓰지 않거나
일부만 쓰거나 전혀 엉뚱한 내용을 쓸 수도 있습니다.

cabjaewon의 이미지

많은 도움이 됐습니다..

좋은 하루 보내세요..^^

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.