我想在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
}
感谢帮助。
编辑:我添加了我的文件示例:
// 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
答案 0 :(得分: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);
}
}
答案 1 :(得分:1)
根据需要尝试fgetc()
(或fgetwc()
。
答案 2 :(得分:1)
由于您需要可靠地检测欠长和超长线,并在两者之后重新同步输入,因此编写一个使用getc()
来读取数据的函数可能是最简单的。
您的标准功能选项包括:
fgets()
- 不会读取太多数据,但您必须确定它是否有换行符(将包含在输入中)并在读取超长行时处理重新同步(不是很难)。fread()
- 将读取完全正确的长度,如果您认为超长和欠长线将极少发生,那将是一个不错的选择。错误之后的重新同步是微不足道的,特别是如果你得到相邻的错误行。getline()
- 来自POSIX 2008.为其读取的行长度分配足够的内存,如果您只是丢弃超长行,这会有点浪费。因为它们不适合,你最终会自己编写。
现在测试过代码。 (由Dave诊断出来的第一个if
需要修复。问题是我最初编写了反向条件(if ((c = getc(fp)) != EOF && c != '\n')
),然后在我颠倒逻辑之后分心了,导致这种情况的“不完全倒置”。)
这是两个while循环的关键部分。
第一个while循环读取到行尾,存储数据和计算字符 - 正常操作。如果该行是正确的长度,则在读取换行符时将断开循环。 注意如果行很短,{{1}将表明。<=
条件;如果你在linelen == 1
时考虑循环,你会看到<=
在这里是正确的,即使<
更常见。
第二个while循环处理超长行,读取到行尾并丢弃结果。它使用count
而不是x
,因为在return语句中需要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 */
答案 3 :(得分:0)
在您实际编写行读代码之前,您应该解决一个大问题:
'\n'
分配1,为'\0'
分配 1。这总计为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.
}
答案 4 :(得分: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;
}
}
答案 5 :(得分:-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;
}