[英]UNIX C parse file
我有帶有標頭和正文的二進制文件格式。 標頭字段和每個字節的字節數是
我需要驗證一些限制並打印此
version=<version_number>
nr_sections=<no_of_sections>
section1: <NAME_1> <TYPE_1> <SIZE_1>
限制條件:
我已經完成了魔術和版本部分,但是我無法做到這一部分,它總是打印一些字符。
我知道我的代碼真的很亂。 抱歉:(
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格式的描述中,您已經寫過
但是在循環代碼中,您僅讀取Sect_name
和Sec_type
。 現在,您應該跳過8個字節(對於Sect_offset
和Sect_size
)或讀入它。否則,您將獲得已經看到的結果。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.