2012-03-31 65 views
0

我想在c中逐行處理文件,如果該行被執行或該行爲空,則文件中的所有行必須長度爲100個字符我想打印錯誤的行數並繼續到下一行。從c中的文件中讀取固定大小的行

我使用這一點,但它不工作:

int maxLineLen = 101; // 100 + 1 for the '\n' end of line 
char myBuffer[101]; 
FILE *myFile; 

myFile = fopen("dataFile.txt", "r"); 

while (fgets(myBuffer, maxLineLen, myFile) != NULL) { 
    // I can't figure out how to detect and print empty or error lines 
} 

感謝的來回幫助。

編輯:我將我的文件中,這個例子:

              // Empty line : Wrong line 
FirstName-Paolo-LastName-Roberto-Age-23-Address-45,abcdefghijklmnopqrst-CustomerId-xxxxxxxxxxxxxxxx // Correct line 
FirstName-Juliana-LastName-Mutti-Age-35-Address-28,abcdefghijklmnopqrst-CustomerId-xxxxxxxxxxxxxxxABCDEFGHIJx // Exeed the length : Wrong line 
FirstName-David-LastName-Lazardi-Age-59-Address-101,abcdefghijklmnopqrst-CustomerId // Short length : Wrong line 

當我運行我的程序我應該得到:

Line 1 : ERROR 
Line 3 : ERROR 
Line 4 : ERROR 

回答

1

由於需要可靠地檢測兩個underlength和超長線,並重新同步你輸入之後或者,它可能比較容易編寫使用getc()讀取數據的功能。

你的標準功能選項包括:

  • fgets() —將無法​​讀取數據太多,但你必須確定它是否有一個換行符(這將被包含在輸入)和處理閱讀長度過長的行時重新同步(不是非常困難)。
  • fread() —將讀取正確的長度,並且如果您認爲長度過長和長度過短的行將是極少出現的情況,那麼這將是一個不錯的選擇。出現錯誤後的重新同步不是微不足道的,特別是如果出現相鄰的錯誤行。
  • getline() — POSIX 2008.分配足夠的內存用於它讀取的行的長度,如果你只是要放棄長度過長的行,這是有點浪費。

因爲它們不合適,你最終會寫自己的。

現在測試的代碼。 (在第一個if需要修復,通過Dave診斷出來,問題是我最初寫了反相條件(if ((c = getc(fp)) != EOF && c != '\n')),然後在我將邏輯反轉後導致分心,導致條件「不完全倒置」。)

這個關鍵部分是兩個while循環。

第一次while循環讀取到行尾,存儲數據和計數字符—正常操作。如果該行長度正確,則在讀取換行符時循環將被中斷。請注意<=的條件;如果你考慮linelen == 1時的循環,你會發現<=在這裏是正確的,儘管<比較平常。如果線路短路,則count將指示該線路。

while while循環處理過長的行,讀到行尾並丟棄結果。它使用x而不是c,因爲在返回語句中需要c

/* 
@(#)File:   $RCSfile: rdfixlen.c,v $ 
@(#)Version:  $Revision: 1.2 $ 
@(#)Last changed: $Date: 2012/04/01 00:15:43 $ 
@(#)Purpose:  Read fixed-length line 
@(#)Author:   J Leffler 
*/ 

/* Inspired by https://stackoverflow.com/questions/9957006 */ 

#include <stdio.h> 
#include <assert.h> 

extern int read_fixed_length_line(FILE *fp, char *buffer, int linelen); 

/* Read line of fixed length linelen characters followed by newline. */ 
/* Buffer must have room for trailing NUL (newline is not included). */ 
/* Returns length of line that was read (excluding newline), or EOF. */ 
int read_fixed_length_line(FILE *fp, char *buffer, int linelen) 
{ 
    int count = 0; 
    int c; 
    assert(fp != 0 && buffer != 0 && linelen > 0); 
    while (count < linelen) 
    { 
     if ((c = getc(fp)) == EOF || c == '\n') 
      break; 
     buffer[count++] = c; 
    } 
    buffer[count] = '\0'; 
    if (c != EOF && c != '\n') 
    { 
     /* Gobble overlength characters on line */ 
     int x; 
     while ((x = getc(fp)) != EOF && x != '\n') 
      count++; 
    } 
    return((c == EOF) ? EOF : count); 
} 

#ifdef TEST 

#include "posixver.h" 
#include <stdarg.h> 
#include <unistd.h> 
#include <string.h> 

int main(void) 
{ 
    enum { MAXLINELEN = 10 }; 
    int actlen; 
    char line[16]; 
    int lineno = 0; 
    memset(line, sizeof(line), '\0'); 

    while ((actlen = read_fixed_length_line(stdin, line, MAXLINELEN)) != EOF) 
    { 
     lineno++; 
     if (actlen != MAXLINELEN) 
     { 
      if (actlen > MAXLINELEN) 
       printf("%2d:L: length %2d <<%s>>\n", lineno, actlen, line); 
      else 
       printf("%2d:S: length %2d <<%s>>\n", lineno, actlen, line); 
     } 
     else 
      printf("%2d:R: length %2d <<%s>>\n", lineno, actlen, line); 
     assert(line[MAXLINELEN-0] == '\0'); 
     assert(line[MAXLINELEN+1] == '\0'); 
    } 
    return 0; 
} 

#endif /* TEST */ 

測試數據和輸出

$ cat xxx 

abcdefghij 
a 
Abcdefghij 
ab 
aBcdefghij 
abc 
abCdefghij 
abcd 
abcDefghij 
abcde 
abcdEfghij 
abcdef 
abcdeFghij 
abcdefg 
abcdefGhij 
abcdefgh 
abcdefgHij 
abcdefghi 
abcdefghIj 
abcdefghiJ 
abcdefghiJ1 
AbcdefghiJ 
abcdefghiJ12 
aBcdefghiJ 
abcdefghiJ123 
$ ./rdfixlen < xxx 
1:S: length 0 <<>> 
2:R: length 10 <<abcdefghij>> 
3:S: length 1 <<a>> 
4:R: length 10 <<Abcdefghij>> 
5:S: length 2 <<ab>> 
6:R: length 10 <<aBcdefghij>> 
7:S: length 3 <<abc>> 
8:R: length 10 <<abCdefghij>> 
9:S: length 4 <<abcd>> 
10:R: length 10 <<abcDefghij>> 
11:S: length 5 <<abcde>> 
12:R: length 10 <<abcdEfghij>> 
13:S: length 6 <<abcdef>> 
14:R: length 10 <<abcdeFghij>> 
15:S: length 7 <<abcdefg>> 
16:R: length 10 <<abcdefGhij>> 
17:S: length 8 <<abcdefgh>> 
18:R: length 10 <<abcdefgHij>> 
19:S: length 9 <<abcdefghi>> 
20:R: length 10 <<abcdefghIj>> 
21:R: length 10 <<abcdefghiJ>> 
22:L: length 11 <<abcdefghiJ>> 
23:R: length 10 <<AbcdefghiJ>> 
24:L: length 12 <<abcdefghiJ>> 
25:R: length 10 <<aBcdefghiJ>> 
26:L: length 13 <<abcdefghiJ>> 
$ 
+0

@gbulmer'fgets' does not NOT ** discard the newline。 – Dave 2012-03-31 16:29:37

+0

@Dave - 感謝您發現。非常容易混淆:-(我猜我在考慮gets()(這更難以使用,因爲它不需要緩衝區長度)我將刪除以保存混淆 – gbulmer 2012-03-31 16:38:56

+0

@JonathanLeffler'c == EOF && c!=' \ n''?第二部分永遠不會失敗 – Dave 2012-03-31 16:47:45

1

試試這個:

int maxLineLen = 101; // 100 + 1 for the '\n' end of line 
int i = 0; 
int len; 
char myBuffer[101]; 
FILE *myFile; 

myFile = fopen("dataFile.txt", "r"); 

while (fgets(myBuffer, maxLineLen, myFile) != NULL) { 
    i++; 
    len = strlen(myBuffer); 
    if(len != 100) { 
     printf("Error on line %u : expected 100 but got %u\n", i, len); 
    } 
} 

http://www.cplusplus.com/reference/clibrary/cstdio/fgets/

+0

讓我添加,而不是'fgets(myBuffer,maxLineLen,myFile)'它使用'fgets(myBuffer,sizeof(myBuffer),myFile)'更強健一點''myBuffer'是一個數組,而不是一個指針。該測試可能會變成'if(len!= sizeof(myBuffer)-1)',該錯誤可能會變成'printf(「%u:%%d%%d%%d」,sizeof(myBuffer)我,len);'。其目的是爲了更明確地與字符數量的關係,並減少「幻數」的出現。對於一個小程序來說,這是一個小問題。 – gbulmer 2012-03-31 15:44:51

+0

@rkosegi:謝謝,但這不起作用,因爲當緩衝區達到最大大小,並且行被放大時,它會再次循環通過其餘的行!在輸出中,我們得到了一條不存在的額外線路! – iPadDevloperJr 2012-03-31 15:45:16

+0

@gbulmer:沒錯,謝謝,你的代碼和我在發帖之前是一樣的:) – iPadDevloperJr 2012-03-31 15:57:59

1

嘗試fgetc()(或根據需要fgetwc())。

+0

我仍然認爲這是最好的迴應。它應該給@iPadDeveloperJr足夠的信息來幫助解決他的作業問題。 – DLS 2012-03-31 17:20:28

-1

試試這個:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

#define maxLen 100 

int main() { 
int lineNumber = 0; 
char buffer[2048]; 
FILE *myFile = fopen("dataFile.txt", "r"); 

while ((fgets(buffer, 2048, myFile) != NULL)) { 
    buffer[strlen(buffer) - 1] = '\0'; 
    lineNumber++; 
    if (strlen(buffer) != maxLen) { 
     printf("Error in line: %d\n", lineNumber); 
    } 
} 
return 0; 
} 
+0

謝謝,但您的解決方案根本無法使用,請嘗試。 – iPadDevloperJr 2012-03-31 15:51:16

+0

@iPadDevloperJr我認爲它現在可行。 – 2012-03-31 15:58:44

+0

不,我很抱歉,由於緩衝區的大小,它不能這樣工作,所有的行都會出錯! – iPadDevloperJr 2012-03-31 16:12:27

0

在您實際編寫線讀取代碼有一個很大的問題,您應該解決:

  • 不足分配您需要分配100爲行,1爲'\n' 1爲'\0'。這總數爲102.即使您爲了安全而使用fgets,這也會阻止您檢測到太長的線條。

之後,正確的處理是很容易(大量註釋):

char *end = line + sizeof line - 2; 
int ch, nlines=0; 
while(fgets(line, sizeof line, file)){ 
    nlines++; 
    if(strchr(line, '\n')!=end){ // the line is too short or long 
     if(strlen(line) == sizeof line - 1)//line too long 
      do { ch=getc(file)); }while(ch!=EOF && ch!='\n'); //eat until newline 
     printf("Error on line %d", nlines); 
     continue; //skip line 
    } 
    //do whatever. 
} 
+0

thaks但我無法理解你的代碼!請正確縮進 – iPadDevloperJr 2012-03-31 16:46:12

+0

@iPadDevloperJr我縮進了;我錯過了一個支撐,雖然(我已經修復)。什麼讓你困惑? – Dave 2012-03-31 16:49:37

+0

謝謝但代碼仍然無法正常工作,我發佈了一些輸入數據,可以幫助您進行測試。 – iPadDevloperJr 2012-03-31 17:06:04

0

基於文件訪問的選項已經被別人覆蓋廣泛。但是,如果您有mmap系統調用,那麼還有另一種選擇。 mmap將文件映射到虛擬內存中,並在訪問時讀入它。這非常方便,可以讓您將文件視爲單個字符串。

請注意,該文件使用MAP_PRIVATE映射到下面,這意味着對字符串(文件)的更改不會寫回實際文件。使用MAP_SHARED將更改寫回文件(不是這裏所要的)。

下面是一些讓你開始的代碼。我們將映射文件,然後對其進行處理:

char * file = map_file(filename); 

if (file) 
    read_equal_sized_lines(file, size); 

首先,我們的文件映射:

static char * map_file(const char *filename) 
{ 
    struct stat st; 
    char *file = NULL; 

    int fd = open(filename, O_RDONLY); 
    if (fd < 0) 
     perror(filename); 
    else if (fstat(fd, &st) < 0) 
     perror("fstat"); 
    else if ((file = mmap(0, st.st_size, 
          PROT_READ | PROT_WRITE, 
          MAP_FILE | MAP_PRIVATE, fd, 0)) == MAP_FAILED) { 
     perror("mmap"); 
     file = NULL; 
    } 
    return file; 
} 

現在我們有了一個字符串,可以簡單地操作它:

static size_t get_line(char *s) 
{ 
    char *end = strchr(s, '\n'); 
    if (end) { 
     *end++ = '\0'; /* terminate the line */ 
     return (size_t) (end - s); 
    } 
    return strlen(s); 
} 


static void read_equal_sized_lines(char *file, size_t size) 
{ 
    int line_nr = 1; 

    while (*file != '\0') { 
     size_t len = get_line(file); 
     /* file points to nul-terminated line; do what you want with it */ 
     if (len != size) 
      printf("Line %d: ERROR\n", line_nr); 

     file += len; 
     ++line_nr; 
    } 
}