簡體   English   中英

UNIX C解析文件

[英]UNIX C parse file

我有帶有標頭和正文的二進制文件格式。 標頭字段和每個字節的字節數是

  1. 靈力:1
  2. 標頭大小:2
  3. 版本:1
  4. 節數:1
  5. Section_headers:No_of_sections * sizeof(section_header)節頭:17 + 4 + 4 + 4宗名:17; Sect_type:4; Sect_offset:4; 大小:4

我需要驗證一些限制並打印此

version=<version_number>
nr_sections=<no_of_sections>
section1: <NAME_1> <TYPE_1> <SIZE_1>

限制條件:

  1. 魔術字段的值必須為“ Q”
  2. 文件版本的值必須在41到67之間,包括該值。
  3. 部分數必須在3到10之間,包括該值。
  4. 現有節的類型必須僅為44 68 35

我已經完成了魔術和版本部分,但是我無法做到這一部分,它總是打印一些字符。

我知道我的代碼真的很亂。 抱歉:(

void parse(const char *path)
{
    int fd;
    unsigned char c[17];
    char name[17];
    int type;
    off_t size;

    fd = open(path, O_RDONLY);
    size=  lseek(fd,0,SEEK_END);
    lseek(fd,0,SEEK_SET);
    for(int i = 0 ; i <=size; i++)
    {
        lseek(fd,0,SEEK_CUR);
        read(fd,&c,1);
        if(i==0)
            if(c[0]=='Q')
                printf("SUCCESS\n");
        if(i<5 && c[0]>=')' && c[0]<='C')
            printf("version=%d \n", c[0]);
    }

    lseek(fd,5,SEEK_SET);
    for(int j=1; j<10; j++)
    {
        read(fd, &name, 17);
        name[17]='\0';
        read(fd, &type, 4);
        printf("section%d: %s %d\n", j + 1, name, type);
    }
}

第二個應該是

for(int j =1;j<=no_of_section;j++)

但我不知道nr_of_section :(我的輸出

SUCCESS
version=46 
section2: fJ00pYisvmveDqS 44
section3: V 1515418709
section4: fRo 2054764888
section5: e6NpWyIifXZ -1392508919
section6:  738197570
section7:  1247047749
section8: J5ArY 1985282048
section9: 707OpGRoR8l9Yen# 381353984
section10:  2053662817

輸出應為:

        SUCCESS
        version=46
        nr_sections=7 
        section1: fJ00pYisvmveDqS 44 1016 
        section2: LLSWA0rSmUtSZfRo 44 890
        section3: lX9yze6NpWyIifXZ 44 941 
        section4: de0cLp2V907jC9B 44 1178
        section5: JrUrWEEpTJJ5ArY 68 724
        section6: Uv707OpGRoR8l9Yen 35 1014 
        section7: BOWdKpZwrBaahhzz 44 972

二進制文件示例 (僅包含標頭和2個部分)

查看您的代碼

您的代碼有很多錯誤。 讓我們來看一下:

void parse(const char *path)
{
    int fd;
    unsigned char c[17];
    char name[17];
    int type;
    off_t size;

    fd = open(path, O_RDONLY);

您沒有檢查對open()的調用是否成功。 如果有錯誤,則fd將為-1 確保檢查並正確處理這種情況。

    size=  lseek(fd,0,SEEK_END);

同樣, lseek()可以返回錯誤。 某些文件可能無法搜索。 您可能可以避免確定文件的大小,請參見下文。

    lseek(fd,0,SEEK_SET);
    for(int i = 0 ; i <=size; i++)
    {

如果size類型為off_t ,則最好也使i成為off_t

        lseek(fd,0,SEEK_CUR);

這個電話沒有任何作用! 為什么在這里呢?

        read(fd,&c,1);

同樣,您不檢查read()的返回值。 可能存在讀取錯誤,或者文件可能比您想象的要小。 檢查返回值是否不是-1 ,並且不是期望的長度( 1 )。

        if(i==0)
            if(c[0]=='Q')
                printf("SUCCESS\n");

這看起來像是嘗試實現循環切換模式 請不要這樣做。 如果要讀取第一個字節並對其進行特殊處理,請不要將其放入for循環中。

        if(i<5 && c[0]>=')' && c[0]<='C')
            printf("version=%d \n", c[0]);

在這里,您說的是文件的第二到第五個字節必須在')''C' 但是根據您的描述,這不是您想要的。 相反,您應該讀取兩個字節(標題長度),一個字節(版本)和另一個字節(段數)。 無需for循環即可執行此操作。

    }

在第五個字節之后,您的for循環只讀取字節而已。

    lseek(fd,5,SEEK_CUR);

讀取size字節后,現在嘗試從當前位置再跳過另外五個字節,這意味着您要超出文件末尾5個字節。

    for(int j=1; j<10; j++)
    {

如果您正確閱讀了節數,則可以使用該數來代替對10進行硬編碼。 另外,您確定j = 1開始嗎?

        read(fd, &name, 17);

再次檢查返回值。

        name[17]='\0';

糟糕,這是緩沖區溢出! 您聲明的name只有17個字節,現在您正在寫入第18個字節。

        read(fd, &type, 4);

您確定type足夠大以容納4個字節嗎? 在C中, int大小取決於平台。 當然,一個int通常使用4個字節,但是如果您確實想要一個4個字節的int,則最好使用int32_t

        printf("section%d: %s %d\n", j + 1, name, type);

由於您以j=1開頭,因此您打印的第一行將以section2:開頭。

    }
}

建議的前進方向

您應該做的第一件事是嘗試正確解析標頭。 確保已閱讀標題中的節數,因此您無需知道文件大小和/或對任何數字進行硬編碼。 不要使用lseek() 在您的代碼處理標頭之前,不必擔心文件的其余部分。

一旦正確解析了標題的所有元素,就可以開始閱讀標題后面的部分。 同樣,每個節都有一個標頭,因此首先要正確解析該節標頭。 每個段標題都有一個指示段長度和偏移量的值。 將它們存儲在數組中。

現在,您已經解析了節標題,可以轉到實際數據。 可能現在您應該開始使用lseek()轉到節標題中提到的文件中的偏移量,然后再read()與節大小一樣多的字節。

作為@G。 Sliepen已經提到您的代碼有很多錯誤。

根據我的評論,您現在已經替換了lseek(fd,5,SEEK_CUR); 通過lseek(fd,5,SEEK_SET);

因此,第一輸出的結果很好。 但是對於2.,3等輸出是錯誤的。

在您對binay格式的描述中,您已經寫過

  1. 宗派名稱:17
  2. Sect_type:4
  3. Sect_offset:4
  4. 大小:4

但是在循環代碼中,您僅讀取Sect_nameSec_type 現在,您應該跳過8個字節(對於Sect_offsetSect_size )或讀入它。否則,您將獲得已經看到的結果。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM