【问题标题】:Read unsigned long long using fscanf()使用 fscanf() 读取 unsigned long long
【发布时间】:2012-08-21 12:33:18
【问题描述】:

如何从文件中读取 64 位无符号整数?我将它存储为实际的二进制数据,而不是字符串表示形式。

【问题讨论】:

标签: c file scanf


【解决方案1】:

有人谈到可移植性问题,所以我在这里发布修改后的版本 (无符号长长)。请参阅代码中的注释。

#include <stdio.h>
//#include <stdlib.h>   //this need to working system("pause"); only
                        //system("pause"); need only to don't close window
                        //if program running by double click on exe in windows.
//#include <inttypes.h> //this need to working with uint64_t    and no need to working with (unsigned long long)

//function to dump hex from file.
void hexdump(const char *const filename)
{
    FILE         *file;
    unsigned char byte;


    file = fopen(filename, "rb");
    if (file == NULL)
        return;
    fprintf(stdout, "hexdump of `%s': ", filename);
    while (fread(&byte, 1, 1, file) == 1)
        fprintf(stdout, "0x%02x ", byte);
    fprintf(stdout, "\n");
}

int main(void) {
    //x64
    //write text, write binary,
    //read text, read binary

    FILE *fout, *filein;
    char *filename_txt = "myfile.txt";  //text filename
    char *filename_bin = "myfile.bin";  //bin filename

    //two x64 numbers

    //uint64_t
    //uint64_t my64 = 258;                      //258 (dec) = 102(hex) =  0000 0000 0000 0102 -> 0201 0000 0000 0000 -> 2010000000000000 -> to file
    //uint64_t my642 = 1234567891011121314;    //1234567891011121314(dec) = 112210F4B2D230A2 (hex) = 1122 10F4 B2D2 30A2 -> A230 D2B2 F410 2211 -> A230D2B2F4102211 -> to file

    //unsigned long long x64
    unsigned long long my64 = 1234567887654321; //as 64 bit integer
    unsigned long long my642 = 0x462D53C650DB1; //the same number, as hex

    // write as text
    fout = fopen(filename_txt, "wt");

//uint64_t
//  fprintf(fout, "%" PRIu64 "\n", my64);
//  fprintf(fout, "%" PRIu64 "\n", my642);

//unsigned long long
    fprintf(fout, "%llu%llu\n", my64);
    fprintf(fout, "%llu%llu\n", my642);

    fclose(fout);   

    // write as bytes
    fout = fopen(filename_bin, "wb");
    fwrite(&my64, sizeof(my64), 1, fout);   //write first number
    fwrite(&my642, sizeof(my64), 1, fout);  //write second number
    fclose(fout);   

    // read as text
    filein = fopen(filename_txt, "rt");
    if(filein==NULL){printf("Cann't open file \"myfile.txt\" for reading...\n");}
    else{
        printf("Try to reading file as text\n");
        char buf[1000];
        while (fgets(buf,1000,filein)!=NULL)
            printf("%s",buf); //just print buf as string.
        fclose(filein);
    }


    // read as bytes
        /* check that the content of the file is not printable, i.e. not text */
        hexdump(filename_bin);

    filein = fopen(filename_bin, "rb");
    if (filein == NULL){
        printf("Cann't open file \"myfile.bin\" for reading...\n");
        return -1;
    }
    else{
        //uint64_t value;
        unsigned long long int value;
        printf("Try to reading file as bytes\n");
        value = 0;

        while(fread(&value, sizeof(value), 1, filein) == 1){
//          fprintf(stdout, "The value read was %" PRIu64 "\n", value);     //uint64_t
            fprintf(stdout, "The value read was %llu%llu\n", value);        //unsigned long long
        }

        fclose(filein);
    }

    //system("pause");
    return 0;
}

1 字节整数可以写为二进制并从二进制中读取 如果变量具有类型 - 无符号字符。

【讨论】:

    【解决方案2】:
    #include <stdio.h>
    #include <stdlib.h>
    #include <inttypes.h>
    
    //function to dump hex from file.
    void hexdump(const char *const filename)
    {
        FILE         *file;
        unsigned char byte;
    
    
        file = fopen(filename, "rb");
        if (file == NULL)
            return;
        fprintf(stdout, "hexdump of `%s': ", filename);
        while (fread(&byte, 1, 1, file) == 1)
            fprintf(stdout, "0x%02x ", byte);
        fprintf(stdout, "\n");
    }
    
    int main(void) {
        //x64
        //write text, write binary,
        //read text, read binary
    
        FILE *fout, *filein;
        char *filename_txt = "myfile.txt";  //text filename
        char *filename_bin = "myfile.bin";  //bin filename
    
        //unsigned long long my64 = 0x1234567887654321;
        //two x64 numbers
        uint64_t my64 = 258;                        //258 (dec) = 102(hex) =  0000 0000 0000 0102 -> 0201 0000 0000 0000 -> 2010000000000000 -> to file
        uint64_t my642 = 1234567891011121314;       //1234567891011121314(dec) = 112210F4B2D230A2 (hex) = 1122 10F4 B2D2 30A2 -> A230 D2B2 F410 2211 -> A230D2B2F4102211 -> to file
    
        // write as text
        fout = fopen(filename_txt, "wt");
        fprintf(fout, "%" PRIu64 "\n", my64);
        fprintf(fout, "%" PRIu64 "\n", my642);
        fclose(fout);    
    
        // write as bytes
        fout = fopen(filename_bin, "wb");
        fwrite(&my64, sizeof(my64), 1, fout);
        fwrite(&my642, sizeof(my64), 1, fout);
        fclose(fout);    
    
        // read as text
        filein = fopen(filename_txt, "rt");
        if(filein==NULL){printf("Cann't open file \"myfile.txt\" for reading...\n");}
        else{
            printf("Try to reading file as text\n");
            char buf[1000];
            while (fgets(buf,1000,filein)!=NULL)
                printf("%s",buf);
            fclose(filein);
        }
    
    
        // read as bytes
            /* check that the content of the file is not printable, i.e. not text */
            hexdump(filename_bin);
    
        filein = fopen(filename_bin, "rb");
        if (filein == NULL){
            printf("Cann't open file \"myfile.bin\" for reading...\n");
            return -1;
        }
        else{
            uint64_t value;
            printf("Try to reading file as bytes\n");
            value = 0;
    
            while(fread(&value, sizeof(value), 1, filein) == 1){
                fprintf(stdout, "The value read was %" PRIu64 "\n", value);
            }
    
            fclose(filein);
        }
    
        system("pause");
        return 0;
    }
    

    【讨论】:

    • 这段没有解释的代码如何回答 OP 的问题?此外,您完全忽略了问题核心的可移植性问题:类型大小、编码和字节序可能因一个系统而异,因此匹配 fread / fwrite 可能不够。 (uint64_t 如果可用则指定为使用 2 的补码而不使用填充位,但字节序仍然是一个问题。)
    • 关于从二进制文件中读取 64 位数字的问题。这是编写 64 位数字并将其作为文本和二进制数据(小端 x64)读取的示例。
    【解决方案3】:

    类似这样的:

    FILE * fp = fopen("file.bin", "rb");
    
    uint64_t value;
    if (fread(&value, sizeof value, fp) != sizeof value) { /* error */ }
    
    // ...
    
    fclose(fp);
    

    如果是您编写数据,这应该是开箱即用的。如果数据来自其他地方,请检查二进制格式的文档以说明序列化格式和您的平台之间的表示差异(例如,可能需要字节交换)。


    另一种在教学上更有用但效率较低的方法是将数据读入缓冲区并应用您自己的处理。这更灵活(例如,您可以处理像 3-2-1-4-7-8-6-5 这样的疯狂字节序),但可能要慢很多:

    unsigned char buf[sizeof uint64_t];
    if (fread(buf, sizeof buf, fp) != sizeof buf) { /* error */ }
    uint64_t leval = buf[0] + (buf[1] << 8) + /* ... */;
    uint64_t beval = buf[7] + (buf[6] << 8) + /* ... */;
    uint64_t ceval = (buf[0] << 16) + (buf[1] << 8) + buf[2] + (buf[3] << 24) + /* ... */;
    

    【讨论】:

      【解决方案4】:

      它是如何编码的? endianness 中的二进制数通常不同。如果你想假设它与当前主机的字节序相同,你可以直接使用fread。否则,您需要在阅读后进行字节交换。

      对于奖励积分,假设您可以控制它的序列化方式,您可以使用一些标志或字节顺序标记来指示字节顺序。

      【讨论】:

        猜你喜欢
        • 2016-07-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-27
        • 2012-03-21
        • 1970-01-01
        相关资源
        最近更新 更多