C에서 파일의 크기를 어떻게 결정합니까?


137

바이트 단위로 파일 크기를 어떻게 알 수 있습니까?

#include <stdio.h>

unsigned int fsize(char* file){
  //what goes here?
}

파일의 세부 사항을 검색하려면 라이브러리 함수를 사용해야합니다. C는 완전히 플랫폼에 독립적이므로 개발중인 플랫폼 / 운영 체제를 알려 주셔야합니다!
Chris Roberts

char* file, 왜 안돼 FILE* file? -1
Mr Oscar

파일 기능은 파일 경로가 아닌 파일 디스크립터를 허용해야하기 때문에 -1
Mr Oscar

답변:


144

NilObject의 코드를 기반으로 :

#include <sys/stat.h>
#include <sys/types.h>

off_t fsize(const char *filename) {
    struct stat st; 

    if (stat(filename, &st) == 0)
        return st.st_size;

    return -1; 
}

변경 사항 :

  • 파일 이름 인수를 a로 만들었습니다 const char.
  • struct stat변수 이름이 누락 된 정의를 수정했습니다 .
  • 빈 파일에 대해서는 모호한 -1대신에 오류가 발생하면 반환 0합니다. off_t부호있는 유형이므로 가능합니다.

당신이 원하는 경우 fsize()에러 메시지를 인쇄하려면, 당신은이를 사용할 수 있습니다 :

#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>

off_t fsize(const char *filename) {
    struct stat st;

    if (stat(filename, &st) == 0)
        return st.st_size;

    fprintf(stderr, "Cannot determine size of %s: %s\n",
            filename, strerror(errno));

    return -1;
}

32 비트 시스템에서는이 옵션을 사용하여이를 컴파일해야하며 -D_FILE_OFFSET_BITS=64, 그렇지 않으면 off_t최대 2GB의 값만 보유합니다. 자세한 내용은 Linux에서 큰 파일 지원 의 "LFS 사용"섹션 을 참조하십시오.


19
이것은 Linux / Unix에만 해당되며, 질문에 OS를 지정하지 않았으므로 지적 할 가치가 있습니다.
Drew Hall

1
리턴 유형을 ssize_t로 변경하고 문제없이 off_t에서 크기를 캐스트 할 수 있습니다. ssize_t :-)를 사용하는 것이 더 합리적 일 것입니다.
Ted Percival

1
더 휴대하기 쉬운 코드를 사용하려면 Derek에서 제안한대로 fseek+ ftell를 사용하십시오 .
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

9
더 휴대하기 쉬운 코드를 사용하려면 Derek에서 제안한대로 fseek+ ftell를 사용하십시오 . 아니오 C 표준은 특별히 그 상태 fseek()SEEK_END바이너리 파일이 정의되지 않은 동작이다에. 7.19.9.2 fseek기능 ... 이진 스트림 fseek은 whence 값이SEEK_END 이고 아래에 설명 된 것처럼 각주 234에서 나온 호출을 의미있게 지원할 필요는 없습니다 . 267은 연결된 C 표준으로, 특별히 정의되지 않은 동작으로 이진 스트림에 레이블 fseek을 지정 SEEK_END합니다. .
Andrew Henle

74

를 사용하지 마십시오 int. 크기가 2 기가 바이트를 초과하는 파일은 요즘 먼지처럼 일반적입니다.

를 사용하지 마십시오 unsigned int. 크기가 4 기가 바이트를 넘는 파일은 약간 덜 일반적인 먼지로 일반적입니다.

IIRC 표준 라이브러리는 off_t부호없는 64 비트 정수로 정의 되며, 이는 모든 사람이 사용해야합니다. 우리는 16 엑사 바이트 파일을 가지고 시작했을 때 몇 년 안에 128 비트로 재정의 할 수 있습니다.

Windows를 사용하는 경우 GetFileSizeEx 를 사용해야 합니다. 실제로 부호있는 64 비트 정수를 사용하므로 8 엑사 바이트 파일에 문제가 발생하기 시작합니다. 어리석은 Microsoft! :-)


1
off_t가 32 비트 인 컴파일러를 사용했습니다. 물론 이것은 4GB 파일이 일반적이지 않은 임베디드 시스템에 있습니다. 어쨌든 POSIX는 off64_t 및 해당 메소드를 정의하여 혼란에 추가합니다.
Aaron Campbell

나는 항상 Windows를 가정하는 답변을 좋아하고 그 외에는 아무것도하지 않습니다. POSIX 호환 제품을 추가해 주시겠습니까?
SS Anne

1
@ JL2210 Ted Percival의 대답은 posix 호환 솔루션을 보여 주므로 명백한 반복은 의미가 없습니다. 나는 (그리고 다른 70 명) 창에 대한 메모를 추가하고 부호있는 32 비트 정수를 사용하여 파일 크기를 나타내지 않는 것이 그 위에 부가 가치라고 생각했습니다. 건배
오리온 에드워즈

30

Matt의 솔루션은 C 대신 C ++이라는 점을 제외하고는 작동해야하며 초기 텔은 필요하지 않습니다.

unsigned long fsize(char* file)
{
    FILE * f = fopen(file, "r");
    fseek(f, 0, SEEK_END);
    unsigned long len = (unsigned long)ftell(f);
    fclose(f);
    return len;
}

중괄호도 당신을 위해 고쳤습니다. ;)

업데이트 : 이것은 실제로 최고의 솔루션은 아닙니다. 그것은 Windows에서 기가 바이트 파일 제한 그리고 그것은 단지 같은 플랫폼 별 호출을 사용하는 것보다 가능성이 느리다 GetFileSizeEx거나 stat64.


그렇습니다. 그러나 플랫폼별로 작성하지 않는 강력한 이유가 없다면 open / seek-end / tell / close 패턴 대신 플랫폼 별 호출을 사용해야합니다.
Derek Park

1
답변이 늦어 죄송하지만 여기에 큰 문제가 있습니다. 암호로 보호되거나 시스템 파일과 같은 제한된 파일에 액세스 할 때 앱이 중단됩니다. 필요한 경우 사용자에게 비밀번호를 요청하는 방법이 있습니까?
저스틴

@Justin, 당신은 아마도 당신이 겪고있는 문제에 대한 새로운 질문을 열어보고, 현재 사용중인 플랫폼, 파일에 액세스하는 방법 및 동작에 대한 세부 정보를 제공해야합니다.
데릭 파크

1
C99와 C11은 모두 long int에서 반환 됩니다 ftell(). (unsigned long)캐스팅은 기능에 의해 이미 제한되어있는 범위를 개선하지 않습니다. ftell()오류가 발생하면 -1을 반환하고 캐스트로 인해 난독 화됩니다. fsize()와 같은 유형을 반환하도록 제안 하십시오 ftell().
chux-복원 Monica Monica

나는 동의한다. 캐스트는 문제의 원래 프로토 타입과 일치하는 것이 었습니다. 그래도 왜 unsigned int 대신 unsigned long으로 바꾸 었는지 기억할 수 없습니다.
Derek Park

15

**이 작업을 수행하지 마십시오 ( 왜? ) :

온라인 내가 발견하는 C99 표준 문서를 인용 : "파일의 끝을,와 마찬가지로 파일 위치 지정자를 설정 fseek(file, 0, SEEK_END)(때문에 가능 뒤에 널 문자) 바이너리 스트림에 대한 정의되지 않은 동작이 있거나 상태에 의존하는 인코딩 어떤 스트림 초기 변속 상태에서 종료되지 않습니다. **

오류 메시지가 전송 될 수 있도록 INT, 다음 사용하도록 정의를 변경 fseek()하고 ftell()파일 크기를 결정합니다.

int fsize(char* file) {
  int size;
  FILE* fh;

  fh = fopen(file, "rb"); //binary mode
  if(fh != NULL){
    if( fseek(fh, 0, SEEK_END) ){
      fclose(fh);
      return -1;
    }

    size = ftell(fh);
    fclose(fh);
    return size;
  }

  return -1; //error
}

5
@ mezhaka : CERT 보고서는 단순히 잘못되었습니다. fseekoftello(또는 fseek그리고 ftell당신은 당신이 작업 할 수 지정 크기가 파일에 대한 제한으로 이전하고 행복한없이 붙어 인 경우) 파일의 길이를 결정하는 올바른 방법입니다. stat기반 솔루션 많은 "파일"(예 : 블록 장치)에서 작동하지 않으며 POSIX가 아닌 시스템으로 이식 할 수 없습니다.
R .. GitHub 중지 지원 얼음

1
이 (예 : 내 아주 최소한의 mbed로) 많은 비 POSIX 호환 시스템에서 파일 크기를 얻을 수있는 유일한 방법입니다
Earlz

9

POSIX

POSIX 표준은 파일 크기를 얻기 위해 자신의 방법이있다. 기능을 사용
하려면 sys/stat.h헤더를 포함하십시오 .

개요

  • 를 사용하여 파일 통계를 가져옵니다 stat(3).
  • st_size재산을 얻으십시오 .

참고 : 크기는로 제한됩니다 4GB. Fat32파일 시스템 이 아닌 경우 64 비트 버전을 사용하십시오!

#include <stdio.h>
#include <sys/stat.h>

int main(int argc, char** argv)
{
    struct stat info;
    stat(argv[1], &info);

    // 'st' is an acronym of 'stat'
    printf("%s: size=%ld\n", argv[1], info.st_size);
}
#include <stdio.h>
#include <sys/stat.h>

int main(int argc, char** argv)
{
    struct stat64 info;
    stat64(argv[1], &info);

    // 'st' is an acronym of 'stat'
    printf("%s: size=%ld\n", argv[1], info.st_size);
}

ANSI C (표준)

ANSI C는 직접 파일의 길이를 결정하는 방법을 제공하지 않습니다.
우리는 마음을 사용해야합니다. 지금, 우리는 탐색 접근법을 사용할 것입니다!

개요

  • 을 사용하여 파일을 끝까지 찾으십시오 fseek(3).
  • 를 사용하여 현재 위치를 가져옵니다 ftell(3).

#include <stdio.h>

int main(int argc, char** argv)
{
    FILE* fp = fopen(argv[1]);
    int f_size;

    fseek(fp, 0, SEEK_END);
    f_size = ftell(fp);
    rewind(fp); // to back to start again

    printf("%s: size=%ld", (unsigned long)f_size);
}

파일이 stdin파이프 인 경우 POSIX, ANSI C 가 작동하지 않습니다. 파일이 파이프 또는이면
반환 0됩니다 stdin.

의견 : 대신 POSIX 표준을 사용해야 합니다. 64 비트를 지원하기 때문입니다.


1
struct _stat64__stat64()_WINDOWS합니다.
Bob Stein

5

Windows 응용 프로그램을 빌드하는 경우 특히 다른 시스템의 파일 표현의 특성으로 인해 파일 길이를 결정하기 위해 CRT 파일 I / O가 지저분 하므로 GetFileSizeEx API를 사용하십시오 .)


5

std c 라이브러리를 사용하는 것이 좋다면 :

#include <sys/stat.h>
off_t fsize(char *file) {
    struct stat filestat;
    if (stat(file, &filestat) == 0) {
        return filestat.st_size;
    }
    return 0;
}

24
그것은 표준 C가 아닙니다. POSIX 표준의 일부이지만 C 표준은 아닙니다.
Derek Park


1

이 코드 세트를 사용하여 파일 길이를 찾았습니다.

//opens a file with a file descriptor
FILE * i_file;
i_file = fopen(source, "r");

//gets a long from the file descriptor for fstat
long f_d = fileno(i_file);
struct stat buffer;
fstat(f_d, &buffer);

//stores file size
long file_length = buffer.st_size;
fclose(i_file);

1

이 시도 --

fseek(fp, 0, SEEK_END);
unsigned long int file_size = ftell(fp);
rewind(fp);

이것이하는 일은 먼저 파일의 끝을 찾으십시오. 그런 다음 파일 포인터가 어디에 있는지보고하십시오. 마지막으로 (선택 사항) 파일의 시작 부분으로 되감습니다. 참고 fp이진 스트림해야한다.

file_size는 파일에 포함 된 바이트 수를 포함합니다. (climits.h에 따라) 부호없는 long 유형은 4294967295 바이트 (4 기가 바이트)로 제한되므로 그보다 큰 파일을 처리하려면 다른 변수 유형을 찾아야합니다.


3
8 년 전의 Derek의 답변 과 다른 점은 무엇입니까?
PP

이진 스트림에 대해 정의되지 않은 동작이며 텍스트 스트림에 ftell대해서는 파일에서 읽을 수있는 바이트 수를 나타내는 값을 반환하지 않습니다.
Andrew Henle

0

나는 잘 작동하는 기능이 있습니다 stdio.h. 나는 그것을 많이 좋아하고 매우 잘 작동하며 꽤 간결합니다.

size_t fsize(FILE *File) {
    size_t FSZ;
    fseek(File, 0, 2);
    FSZ = ftell(File);
    rewind(File);
    return FSZ;
}

0

다음은 파일 크기를 반환하는 간단하고 깔끔한 함수입니다.

long get_file_size(char *path)
{
    FILE *fp;
    long size = -1;
    /* Open file for reading */
    fp = fopen(path, "r");
    fseek(fp, 0, SEEK_END);
    size = ftell(fp); 
    fp.close();
    return 
}

1
파일을 닫을 필요가 없습니까?
Jerry Jeremiah

아니요, 경로를 기대하는 기능을 싫어합니다. 대신, 파일 포인터를 기대하십시오
Mr Oscar

-3

파일을 열고 파일 하단에서 0 오프셋으로 이동할 수 있습니다.

#define SEEKBOTTOM   2

fseek(handle, 0, SEEKBOTTOM)  

fseek에서 반환 된 값은 파일 크기입니다.

C로 오랫동안 코딩하지 않았지만 작동해야한다고 생각합니다.


12
SEEKBOTTOM과 같은 것을 정의 할 필요는 없습니다. #include <stdio.h> fseek (핸들, 0, SEEK_END);
sigjuice 5

-4

질문을 보면 ftell쉽게 바이트 수를 얻을 수 있습니다.

  long size = ftell(FILENAME);
  printf("total size is %ld bytes",size);

ftell파일 이름이 아닌 파일 설명자를 인수로 사용합니다.
Barmar

@Barmar, No ftell는 파일 디스크립터를 기대하지 않고 FILE*대신 파일 디스크립터를 기대합니다 . 맨 페이지를 먼저보십시오!

접근 방식은 완전히 잘못되었습니다 . 매번 ftell반환 되는 것은 일정합니다 0!

이 대답은 잘못되어 있습니다. 하나 fseek()는 파일의 끝을 찾기 위해 먼저 사용해야 하며 문자열이 아닌을 ftell()기대 FILE *합니다! 당신은 당신의 답을 살리기 위해 잘 봉사 할 것입니다.
Mr Oscar
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.