从c中的文件中读取固定大小的行
我想在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
由于需要可靠地检测两个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://*.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>>
$
试试这个:
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);
}
}
让我添加,而不是'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
@rkosegi:谢谢,但这不起作用,因为当缓冲区达到最大大小,并且行被放大时,它会再次循环通过其余的行!在输出中,我们得到了一条不存在的额外线路! – iPadDevloperJr 2012-03-31 15:45:16
@gbulmer:没错,谢谢,你的代码和我在发帖之前是一样的:) – iPadDevloperJr 2012-03-31 15:57:59
尝试fgetc()
(或根据需要fgetwc()
)。
我仍然认为这是最好的回应。它应该给@iPadDeveloperJr足够的信息来帮助解决他的作业问题。 – DLS 2012-03-31 17:20:28
试试这个:
#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;
}
谢谢,但您的解决方案根本无法使用,请尝试。 – iPadDevloperJr 2012-03-31 15:51:16
@iPadDevloperJr我认为它现在可行。 – 2012-03-31 15:58:44
不,我很抱歉,由于缓冲区的大小,它不能这样工作,所有的行都会出错! – iPadDevloperJr 2012-03-31 16:12:27
在您实际编写线读取代码有一个很大的问题,您应该解决:
-
不足分配您需要分配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.
}
thaks但我无法理解你的代码!请正确缩进 – iPadDevloperJr 2012-03-31 16:46:12
@iPadDevloperJr我缩进了;我错过了一个支撑,虽然(我已经修复)。什么让你困惑? – Dave 2012-03-31 16:49:37
谢谢但代码仍然无法正常工作,我发布了一些输入数据,可以帮助您进行测试。 – iPadDevloperJr 2012-03-31 17:06:04
基于文件访问的选项已经被别人覆盖广泛。但是,如果您有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;
}
}
@gbulmer'fgets' does not NOT ** discard the newline。 – Dave 2012-03-31 16:29:37
@Dave - 感谢您发现。非常容易混淆:-(我猜我在考虑gets()(这更难以使用,因为它不需要缓冲区长度)我将删除以保存混淆 – gbulmer 2012-03-31 16:38:56
@JonathanLeffler'c == EOF && c!=' \ n''?第二部分永远不会失败 – Dave 2012-03-31 16:47:45