чтение строк фиксированного размера из файла в c - PullRequest
0 голосов
/ 31 марта 2012

Я хочу обрабатывать файл построчно в c, все строки в файле должны иметь длину 100 символов, если строка превышает это или строка пуста. Я хочу напечатать номер строки с ошибкой и продолжить доследующая строка.

Я использую это, но это не работает:

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
}

Спасибо за помощь.

Редактировать: я добавил этот образец моегоfile:

                                                            // 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

Ответы [ 6 ]

1 голос
/ 31 марта 2012

Поскольку вам необходимо надежно обнаруживать линии как нижней, так и сверхдлинной длины, а также синхронизировать ввод после каждой из них, вероятно, проще всего написать функцию, которая использует getc() для чтения данных.

Ваши стандартные функции включают в себя:

  • fgets() & mdash; не будет читать слишком много данных, но вам нужно будет определить, получил ли он новую строку (которая будет включена во входные данные), и иметь дело с ресинхронизацией при чтении слишком длинной строки (не очень сложно).
  • fread() & mdash; будет читать точно правильную длину, и будет хорошим выбором, если вы думаете, что линии длины и длины будут исчезающе редкими случаями. Ресинхронизация после ошибки совсем не тривиальна, особенно если вы получаете соседние ошибочные строки.
  • getline() & mdash; из POSIX 2008. Выделяет достаточное количество памяти для длины строки, которую он читает, что немного расточительно, если вы просто собираетесь отбрасывать слишком длинные строки.

Поскольку они не подходят, вы заканчиваете тем, что пишете свои собственные.

Теперь проверенный код. (Исправление было необходимо в первом if, как было установлено Дейвом . Проблема заключалась в том, что я изначально написал обратное условие (if ((c = getc(fp)) != EOF && c != '\n')), а затем отвлекся после того, как перевернул логику, что привело к ' неполная инверсия 'условия.)

Ключевыми частями этого цикла являются два цикла while.

Первый цикл while читает до конца строки, сохраняя данные и считая символы & mdash; нормальная работа. Если строка имеет правильную длину, цикл будет прерван при чтении новой строки. Обратите внимание на условие <=; если учесть цикл, когда linelen == 1, вы увидите, что <= здесь правильный, хотя < является более обычным. Если линия короткая, count укажет, что.

Второй цикл 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, '\0', sizeof(line));

    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>>
$ 
1 голос
/ 31 марта 2012

Попробуйте fgetc() (или fgetwc() при необходимости).

1 голос
/ 31 марта 2012

Попробуйте это:

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 голосов
/ 01 апреля 2012

Опции доступа к файлам широко освещались другими.Однако, если у вас системный вызов 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;
    }
}
0 голосов
/ 31 марта 2012

Прежде чем вы на самом деле напишите код для чтения строк, вам нужно решить одну большую проблему:

  • Недостаточное распределение Вам необходимо выделить 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 голосов
/ 31 марта 2012

Попробуйте это:

#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;
}
...