2010-07-20 68 views
0

好吧,我一直在讀fread()[它返回一個類型size_t],並看到有關大型文件和其他一些問題的一些問題 - 但我仍然有一些問題。這個函數傳入一個文件指針和一個long long int。該lld是從我使用另一個函數獲取實際文件大小爲6448619520字節的主要位置。fread()在6GB文件失敗

char *getBuffer(FILE *fptr, long long size) { 
    char *bfr; 
    size_t result; 

    printf("size of file in allocate buffer: %lld\n", size); 
     //size here is 6448619520 


    bfr = (char*) malloc(sizeof(char) * size); 
    if (bfr == NULL) { 
     printf("Error, malloc failed..\n"); 
     exit(EXIT_FAILURE); 
    } 
     //positions fptr to offset location which is 0 here. 
    fseek(fptr, 0, SEEK_SET); 
     //read the entire input file into bfr 
    result = fread(bfr, sizeof(char), size, fptr); 
    printf("result = %lld\n", (long long) result); 


    if(result != size) 
    { 
     printf("File failed to read\n"); 
     exit(5); 
    } 
    return (bfr); 

} 

我已經測試過它的面積約爲1-2GB的文件,它工作正常,但是,當我測試它6GB的文件中,沒有到緩衝區中讀取。忽略其他結果(注重結果的粗體),問題在於讀取數據bfr。這裏是我得到的一些結果。一個文件的

第一即735844352個字節(700 + MB)

根@紅盒子:/數據/項目/ C /存根/#./testrun -x 45004E00 -i /數據/ Helix2008R1 .ISO

圖像文件是/data/Helix2008R1.iso
十六進制字符串= 45004E00
>文件的總大小:735844352
在GET緩衝文件尺寸:735844352
結果= 735844352

** 開始解析所述命令行十六進制值:45004E00
在十六進制字符串的總字節數:
十六進制字符串45004E00被發現在字節位置:4個

十六進制字符串搜索結果:37441
十六進制字符串45004E00被發現在字節位置:524768
....

試驗#2針對一個6GB的文件: 根@redbox:/數據/項目/ C /存根/#./testrun -x BF1B0650 -i /data/images/sixgbimage.img

圖片文件/data/images/sixgbimage.img
十六進制字符串= BF1B0650
文件的總大小:在文件6448619520
大小分配緩衝區:6448619520
結果= 0
文件無法讀取

我仍然不知道爲什麼它是大文件,而不是失敗小一些,這是一個> 4GB的問題。我使用以下內容:

/* Support Large File Use */ 
#define _LARGEFILE_SOURCE 1 
#define _LARGEFILE64_SOURCE 1 
#define _FILE_OFFSET_BITS 64 

順便說一句,我使用的是Ubuntu 9.10盒(2.6.x內核)。 TIA。

+1

它是一個32位函數嗎? 32位,你只能訪問4 GB的字節尋址內存。如果您無法訪問超過4GB的任何內容,我懷疑這至少是部分責任。 – 2010-07-20 00:23:08

+0

是的,它是一個32位函數。我猜測這可能是一個> 4GB的問題,仍然在研究如何解決這個問題.. – labgeek 2010-07-20 00:54:36

+1

我正在閱讀這個權利嗎?你試圖一次性讀取6GB的文件到RAM中?即使你認爲自己有足夠的記憶,也不要這樣做。像sarnold建議使用mmap。 – 2010-07-20 01:02:26

回答

0

在收到所有人的建議之後,我將6GB文件分解爲4K塊,分析了十六進制字節,並且能夠獲得什麼字節位置,稍後我將從VMFS分區中取出MBR被dd鏡像了。這裏是一個閱讀它每塊的快速和骯髒的方式:

的#define DEFAULT_BLOCKSIZE 4096
...

while((bytes_read = fread(chunk, sizeof(unsigned char), sizeof(chunk), fptr)) > 0) { 
    chunkptr = chunk; 
    for(z = 0; z < bytes_read; z++) { 
     if (*chunkptr == pattern_buffer[current_search]) { 
      current_search++; 
      if (current_search > (counter - 1)) { 
       current_search = 0; 
       printf("Hex string %s was found at starting byte location: %lld\n", 
         hexstring, (long long int) (offsetctr-1)); 
       matches++; 
      } 
     } else { 
      current_search = 0; 
     } 
     chunkptr++; 
     //printf("[%lld]: %02X\n", offsetctr, chunk[z] & 0xff); 
     offsetctr++; 
    } 
    master_counter += bytes_read; 
} 

...

這裏是我得到的結果。 ..

[email protected]:~/workspace/bytelocator/Debug# ./bytelocator -x BF1B0650 -i /data/images/sixgbimage.img 

Total size of /data/images/sixgbimage.img file: 6448619520 bytes 
Parsing the hex string now: BF1B0650 

Hex string BF1B0650 was found at starting byte location: 18 
Hex string BF1B0650 was found at starting byte location: 193885738 
Hex string BF1B0650 was found at starting byte location: 194514442 
Hex string BF1B0650 was found at starting byte location: 525033370 
Hex string BF1B0650 was found at starting byte location: 1696715251 
Hex string BF1B0650 was found at starting byte location: 1774337550 
Hex string BF1B0650 was found at starting byte location: 2758859834 
Hex string BF1B0650 was found at starting byte location: 3484416018 
Hex string BF1B0650 was found at starting byte location: 3909721614 
Hex string BF1B0650 was found at starting byte location: 3999533674 
Hex string BF1B0650 was found at starting byte location: 4018701866 
Hex string BF1B0650 was found at starting byte location: 4077977098 
Hex string BF1B0650 was found at starting byte location: 4098838010 


Quick stats: 
================ 
Number of bytes that have been read: 6448619520 
Number of signature matches found: 13 
Total number of bytes in hex string: 4 
+0

我覺得你的新計劃將錯過跨越兩個區塊的字節串的副本:說,'BF1B'塊0,'0650'塊1 – sarnold 2010-07-23 00:53:41

+0

是的,你是正確的。這是目前的限制之一,十六進制塊之間的十六進制模式搜索僅搜索那些4k塊內的那些模式,而不是跨越兩個連續塊的模式 - 這是必須解決的! – labgeek 2010-07-23 10:40:02

2

fread失敗時,它會設置errno來指示失敗的原因。撥打fread返回零後errno的值是多少?

更新: 您是否需要一舉讀取整個文件?如果您一次讀入512MB文件,會發生什麼情況?

根據以上評論,您正在使用32位操作系統。在這種情況下,您將無法一次處理6 GB(其中之一,size_t將無法​​保存大量的數字)。但是,您應該能夠以較小的塊讀入和處理文件。

我會爭辯說,即使在64位操作系統上,將6GB文件讀入內存也可能不是解決問題的最佳解決方案。你試圖完成什麼,需要你緩衝一個6GB的文件?可能有更好的方法來解決這個問題。

+0

的fread()返回0之後,它返回的錯誤值是:22個 結果: 文件的總大小:在GET緩衝6448619520 尺寸文件的:6448619520 結果= 0 錯誤號= 22 文件未能讀取 – labgeek 2010-07-20 00:39:12

+0

一次讀入一個行業就可以。它只是我已經習慣了使用小測試文件,當我在更大的文件上測試它時,我沒有考慮到我不會提供的內存...... ty。 – labgeek 2010-07-20 01:25:16

+0

你的問題是一個很好的問題,我應該儘早意識到,閱讀一些大的內容將是不可行和低效的。所以是的,一個小的重新設計是爲了將讀取分成小塊,處理每個塊,直到文件結束。此程序的總體原因是在dd映像或VMFS分區內獲取十六進制偏移量模式。一些VMFS分區往往會變得非常大,例如200 + GB或更大。再次,不是最好的方式來處理它,我現在看到了。 – labgeek 2010-07-20 01:49:47

4

如果你只是要通讀文件,而不是修改它,我建議使用mmap(2)而不是fread(3)。這應該更有效率,雖然我還沒有嘗試過大文件。如果這是你想要的,你需要改變我非常簡單的找到/未找到的報告偏移量,但我不確定你想要的指針。 :)

#define _GNU_SOURCE 
#include <string.h> 

#include <fcntl.h> 
#include <sys/mman.h> 
#include <stdio.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <unistd.h> 


int main(int argc, char* argv[]) { 
    char *base, *found; 
    off_t len; 
    struct stat sb; 
    int ret; 
    int fd; 
    unsigned int needle = 0x45004E00; 

    ret = stat(argv[1], &sb); 
    if (ret) { 
      perror("stat"); 
      return 1; 
    } 

    len = sb.st_size; 

    fd = open(argv[1], O_RDONLY); 
    if (fd < 0) { 
      perror("open"); 
      return 1; 
    } 

    base = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0); 
    if (!base) { 
      perror("mmap"); 
      return 1; 
    } 

    found = memmem(base, len, &needle, sizeof(unsigned int)); 
    if (found) 
      printf("Found %X at %p\n", needle, found); 
    else 
      printf("Not found"); 
    return 0; 
} 

一些測試:

$ ./mmap ./mmap 
Found 45004E00 at 0x7f8c4c13a6c0 
$ ./mmap /etc/passwd 
Not found 
+0

我一直使用malloc之前,從未使用mmap之前...在這裏看到了一個很好的解釋:http://stackoverflow.com/questions/1739296/malloc-vs-mmap-in-c – labgeek 2010-07-20 01:06:49

+0

在我的觀點使用'fread'進入如此大的緩衝區是一種濫用。 即使你想讀你應該使用'mmap'後更改緩衝:在國旗給了''MAP_PRIVATE' mmap'確保您的副本保留在內存中的所有變化,並沒有被重新寫入文件。 'mmap'效率更高,因爲只要不修改它們就不需要換出任何'bfr'頁面。所有頁面都直接在頁面緩存中處理。如果您真的不想更改內容,請將其映射爲只讀,然後即使您的程序的多個實例可以使用相同的物理頁面共存。 – 2010-07-20 06:28:34

4

如果這是一個32位的過程,就像你說的,然後size_t是32位的,你根本可以在進程的地址大於4GB不儲存更多空間(實際上,實際上,少於3GB)。在這條線的位置:

bfr = (char*) malloc(sizeof(char) * size); 

相乘的結果將模SIZE_MAX + 1,這意味着它只會儘量和周圍2GB分配減少。類似的,同樣的事情發生在size參數在這條線:

result = fread(bfr, sizeof(char), size, fptr); 

如果你想在32位進程具有較大的文件工作,你只有其中的一部分在時間上工作(例如,讀取前100 MB,讀取下100 MB的過程,...)。您無法一次讀取整個文件 - 您的流程沒有足夠的內存來執行此操作。

+0

好點,這是我最感興趣的。看起來我必須讀取每個文件讀取x MB直到達到文件大小的末尾。 – labgeek 2010-07-20 01:20:56

0

您是否已驗證mallocfread實際上是否採用了正確的參數類型?您可能需要使用-Wall選項進行編譯,並檢查您的64位值是否真的被截斷。在這種情況下,malloc將不會報告錯誤,但最終的分配將遠遠小於您所要求的。