그냥 심심해서 바이너리파일복사 프로그램을 만들려고 하는데 잘

pjs0919의 이미지

/*
 * Very Simple File Copy
 */
#include <stdio.h>

static unsigned int cnt=0;

int main(int argc, char **argv)
{
        FILE *ifp, *ofp;
        char temp;
        if(argc != 3)
        {
                printf("Argument Error! \n");
                return 1;
        }
        printf("Usage : %s source_file target_file\n", argv[0]);

        if(!(ifp_final = ifp = fopen(argv[1], "rb")))
        {
                printf("Error\n");
                return 1;
        }
        ofp = fopen(argv[2], "wb");
        /* Copy to target_file */
        while((temp = getc(ifp)) != EOF)
                putc(temp, ofp);
        fclose(ifp);
        fclose(ofp);
        printf("OK\n");
        return 0;
}

그냥 혹시나 하는 생각에 바이너리파일 copy프로그램좀 만들어 보려고 했는데 잘 않되네요.....이유가 뭔지 ...알려주시면 감사하겠습니다.
보시면 아시겠지만 1Byte씩 타겟파일에 기록을 하는데요..
그냥 아스키파일의 경우는 이상없이 잘됩니다...하지만 바이너리파일의 경우 복사가 중단되더군요....아마도 EOF의 define 값때문이 아닌지...의심이 가네요..

lazarus의 이미지

바이너리라면 fread 와 fwrite 함수를 사용하면 될듯 합니다.

man page를 참고하세요 ^^

최종호의 이미지

    char temp;


    int temp;

로 바꿔보세요~

근데 이거 컴파일은 되는 소스인가요? ㅡ.ㅡ?

오호라의 이미지

#include<stdio.h>
#include<stdlib.h>

#define O_READ "rb"
#define O_WRITE "wb"

const int SIZE = 5;   /* size는 적당한 값을 알아서  */

int main(int argc, char **argv)
{
	FILE *ifp, *ofp;
	char buf[SIZE];
	int buf_size = SIZE;
	int count = 0;
	
	if(argc != 3)
	{
		printf("argument error!\ntest.exe a.txt b.txt\n");
		exit(0);
	}

	ifp = fopen(argv[1], O_READ);
	ofp = fopen(argv[2], O_WRITE);

	while(buf_size == SIZE)
	{
		count++;
		buf_size = fread(buf, sizeof(char), SIZE, ifp);
		fwrite(buf, sizeof(char), buf_size, ofp);
	}

	printf("%s에서 %s로 %dbyte 복사되었습니다.\n", argv[1], argv[2], (count-1) * SIZE + buf_size);

	fclose(ifp);
	fclose(ofp);
	
	return 0;
}

개인 소견으로는 소스에서 파일안에 어디인가에 존재할지 모르는 EOF값때문에 루프를 빠져나오는 것같습니다.

EOF도 define에 있는 상수값입니다. -1, 0...등 특별한 의미로만 쓰일뿐... EOF가 파일 마지막에만 존재하리란 법은 없습니다.

while(buf_size == SIZE)
	{
		count++;
		buf_size = fread(buf, sizeof(char), SIZE, ifp);
		fwrite(buf, sizeof(char), buf_size, ofp);
	}

이런 방법이 파일입출력에서 종종 쓰이곤 합니다. 참고하세요.

Hello World.

pjs0919의 이미지

^^
"stdio.h"에 보면
define EOF -1

로 기록되있죠..만약 시스템이 이런구조가 아니라면 debine 값을 바꿔주면 되는거구요.

흠....답변들을 보면, fread()함수에 너무 의지하는게 아닌까요?
분명히 파일의 끝을 어떻게 인지하는법이 있을텐데............
inode같은 심볼릭테이블에서 파일의 끝을 인지하는 건지....쩝...

어쨋든, 답변해주신 여러분들 감사합니다... :D

\(´∇`)ノ.大韓兒 朴鐘緖人

Mins의 이미지

stat() 을 통해서, file size 를 알수 있습니다.
혹시 원하시는게 이게 맞나요??

man stat, fstat

pynoos의 이미지

바이너리 파일을 취급하는데에서는 특히나 getc를 사용해서 파일의 끝을 알 수 있는 방법은 없습니다. 바이너리 모드로 열었을 때, getc로 되돌려지는 모든 값은 바이너리로서 의미가 있기 때문입니다.

오히려 바이너리를 복사하려는 여기에서는 fread를 쓰는 것이 더 맞는 방법입니다.

정태영의 이미지

getc등으로 읽으실라면.. 파일의 끝은 feof 로 체크해야죠 :)

리턴값이 EOF 인가로 체크하는건..
fscanf fread fgets 등으로 읽을 경우에 해당되는 얘기입니다

오랫동안 꿈을 그리는 사람은 그 꿈을 닮아간다...

http://mytears.org ~(~_~)~
나 한줄기 바람처럼..

익명 사용자의 이미지

pynoos wrote:
바이너리 파일을 취급하는데에서는 특히나 getc를 사용해서 파일의 끝을 알 수 있는 방법은 없습니다. 바이너리 모드로 열었을 때, getc로 되돌려지는 모든 값은 바이너리로서 의미가 있기 때문입니다.

오히려 바이너리를 복사하려는 여기에서는 fread를 쓰는 것이 더 맞는 방법입니다.

정확한 지적이신 것같습니다. getc() 함수자체가 바이너리파일보다는 텍스트파일에 더 적합하지 않을까요?

최종호의 이미지

fgetc(또는 getc, getchar) 로 바이너리 데이터를 취급하는데 전혀 문제가 없습니다.
fgetc 는 byte단위의 input function 으로서 한 character 를 unsigned char 로 읽어서 int로 변환해서 리턴합니다.
(멀티바이트 character는 wide character 관련함수로 처리하므로 fgetc의 한 character는 한 바이트입니다.)
따라서 0xFF (-1) 을 읽더라도 fgetc 에 의해서 리턴되는 값은 -1 (EOF) 가 아니라 255 입니다.

fgetc에서 EOF를 리턴했다는 것은 *정말로* 파일의 끝에 다다라서(또는 스트림의 I/O 오류발생) 다음 데이터를 받을 수 없다는 것을 의미합니다.
파일의 끝이라는 개념은 OS 마다, 또 모드(binary, text)마다 다르게 정의됩니다.

fgetc의 리턴형이 int 라는 사실은 중요한 의미가 있습니다. pjs0919 님이 하신 실수도 바로 이것과 관련이 있고요.
파일안에 0xFF 바이트가 있었다고 하면 fgetc 는 이를 unsigned char 인 255로 읽어서 int형으로 리턴을 할 것입니다.
이 리턴값을 char 형 변수로 저장을 하면 255가 아닌 -1 이 됩니다.
불행이도 이 값은 EOF 로 정의가 되어 있고, fgetc()가 아니라 사용자가 작성한 프로그램 로직에
의해서 이 상황을 파일끝으로 간주하고 처리를 끝내므로 원 파일보다 더 적은 데이터만 복사되는 경우가 발생하는 이유가 되는 것입니다.

사용자가 fread/fwrite 의 direct I/O 함수를 쓸지 fgetc/fputc의 character I/O를 쓸지는
주어진 여러가지 조건에 따라서 결정할 문제이지 처리할 대상이 binary인지 text인지에 따라서
어떤 한쪽의 사용이 제약되는 것은 아닙니다.
성능이 요구되는 상황이라면 표준적인 fread/fwrite나 fgetc/fputc 방식이 아니라
다른 방식을 사용해서 작성하는 것이 적절한 경우도 있겠구요.

C99의 fgetc 함수 앞 부분을 인용합니다.

Quote:
7.19.7.1 The fgetc function
Synopsis
1 #include <stdio.h>
int fgetc(FILE *stream);
Description
2 If the end-of-file indicator for the input stream pointed to by stream is not set and a
next character is present, the fgetc function obtains that character as an unsigned
char converted to an int and advances the associated file position indicator for the
stream (if defined).
Returns
3 If the end-of-file indicator for the stream is set, or if the stream is at end-of-file, the endof-
file indicator for the stream is set and the fgetc function returns EOF. Otherwise, the
fgetc function returns the next character from the input stream pointed to by stream.
If a read error occurs, the error indicator for the stream is set and the fgetc function
returns EOF.246)
익명 사용자의 이미지

최종호 wrote:
fgetc(또는 getc, getchar) 로 바이너리 데이터를 취급하는데 전혀 문제가 없습니다.
fgetc 는 byte단위의 input function 으로서 한 character 를 unsigned char 로 읽어서 int로 변환해서 리턴합니다.
(멀티바이트 character는 wide character 관련함수로 처리하므로 fgetc의 한 character는 한 바이트입니다.)
따라서 0xFF (-1) 을 읽더라도 fgetc 에 의해서 리턴되는 값은 -1 (EOF) 가 아니라 255 입니다.

fgetc에서 EOF를 리턴했다는 것은 *정말로* 파일의 끝에 다다라서(또는 스트림의 I/O 오류발생) 다음 데이터를 받을 수 없다는 것을 의미합니다.
파일의 끝이라는 개념은 OS 마다, 또 모드(binary, text)마다 다르게 정의됩니다.

fgetc의 리턴형이 int 라는 사실은 중요한 의미가 있습니다. pjs0919 님이 하신 실수도 바로 이것과 관련이 있고요.
파일안에 0xFF 바이트가 있었다고 하면 fgetc 는 이를 unsigned char 인 255로 읽어서 int형으로 리턴을 할 것입니다.
이 리턴값을 char 형 변수로 저장을 하면 255가 아닌 -1 이 됩니다.
불행이도 이 값은 EOF 로 정의가 되어 있고, fgetc()가 아니라 사용자가 작성한 프로그램 로직에
의해서 이 상황을 파일끝으로 간주하고 처리를 끝내므로 원 파일보다 더 적은 데이터만 복사되는 경우가 발생하는 이유가 되는 것입니다.

사용자가 fread/fwrite 의 direct I/O 함수를 쓸지 fgetc/fputc의 character I/O를 쓸지는
주어진 여러가지 조건에 따라서 결정할 문제이지 처리할 대상이 binary인지 text인지에 따라서
어떤 한쪽의 사용이 제약되는 것은 아닙니다.
성능이 요구되는 상황이라면 표준적인 fread/fwrite나 fgetc/fputc 방식이 아니라
다른 방식을 사용해서 작성하는 것이 적절한 경우도 있겠구요.

C99의 fgetc 함수 앞 부분을 인용합니다.

Quote:
7.19.7.1 The fgetc function
Synopsis
1 #include <stdio.h>
int fgetc(FILE *stream);
Description
2 If the end-of-file indicator for the input stream pointed to by stream is not set and a
next character is present, the fgetc function obtains that character as an unsigned
char converted to an int and advances the associated file position indicator for the
stream (if defined).
Returns
3 If the end-of-file indicator for the stream is set, or if the stream is at end-of-file, the endof-
file indicator for the stream is set and the fgetc function returns EOF. Otherwise, the
fgetc function returns the next character from the input stream pointed to by stream.
If a read error occurs, the error indicator for the stream is set and the fgetc function
returns EOF.246)

죄송합니다. 소스수정 좀 해주셔서 올려주시면 안될까요?!~
getc()를 이용해서. ^^;

최종호의 이미지

Quote:
죄송합니다. 소스수정 좀 해주셔서 올려주시면 안될까요?!~
getc()를 이용해서. ^^;

맨 처음 글 올리신 분의 코드에서

char temp;

int temp; 

로 고치시고,
if(!(ifp_final = ifp = fopen(argv[1], "rb")))


if(!(ifp = fopen(argv[1], "rb")))

로 고치시면 될 듯 한데요... ㅡ.ㅡ;;
pynoos의 이미지

아..!

제가 실수했군요. :)

최종호님의 말이 맞습니다. 습관적으로 fgetc의 return 값을 char 에 받아 사용하기 때문에 익숙치 않은 용법으로 인한 오류였습니다.

그나저나 제가 굉장히 강한 확신으로 답변을 드렸군요. 이런 죄송할데가..

댓글 달기

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