我有一个像这样的文件:
<int>
<int>
<int>
<strig1>
....
<stringk>
其中int
是数字,string
是路径。
我想将每个int
保存到一个不同的变量中,与string
相同。
如何仅使用C进行系统调用逐行读取?
如何使用read
?
答案 0 :(得分:0)
您可以使用 fgets 或更简单的 getline 来读取行,以允许任意长度的行,而不必管理仅一部分行的读取,因为您的缓冲区太小,请使用 strtol 查看该行是否仅包含 int (在分隔符之外)
例如:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main(int argc, char ** argv)
{
if (argc != 2)
printf("Usage : %s <file path>\n", *argv);
else {
FILE * fp = fopen(argv[1], "r");
if (fp == NULL)
fprintf(stderr, "cannot open '%s'\n", argv[1]);
else {
long * longs = malloc(0);
char ** strings = malloc(0);
size_t nlong = 0;
size_t nstring = 0;
char *lineptr = NULL;
size_t n = 0;
ssize_t len;
while ((len = getline(&lineptr, &n, fp)) != -1) {
errno = 0;
char * endptr;
long v = strtol(lineptr, &endptr, 10);
if ((errno == 0) &&
(*lineptr != 0) && (*lineptr != '\n') &&
((*endptr == 0) || (*endptr == '\n'))) {
/* a valid long */
longs = realloc(longs, (nlong + 1) * sizeof(long));
longs[nlong++] = v;
}
else {
/* consider a string, use strdup to limit needed size, lineptr can be long for nothing */
if (lineptr[len - 1] == '\n')
/* probably you do not want to save the newline */
lineptr[--len] = 0;
strings = realloc(strings, (nstring + 1) * sizeof(char *));
strings[nstring] = malloc(len + 1);
strcpy(strings[nstring++], lineptr);
}
}
free(lineptr);
fclose(fp);
/* debug */
printf("read %zu longs\n", nlong);
for (size_t i = 0; i != nlong; ++i)
printf("\t%ld\n", longs[i]);
printf("read %zu strings\n", nstring);
for (size_t i = 0; i != nstring; ++i)
printf("\t'%s'\n", strings[i]);
/* free memory */
free(longs);
for (size_t i = 0; i != nstring; ++i)
free(strings[i]);
free(strings);
}
}
return 0;
}
编译和执行:
bruno@bruno-XPS-8300:/tmp$ gcc -pedantic -Wall -Wextra r.c
bruno@bruno-XPS-8300:/tmp$ cat f
123
qsd wxc
123 456
11111111111111111111111111111111111111111111111111
bruno@bruno-XPS-8300:/tmp$ ./a.out f
read 1 longs
123
read 3 strings
'qsd wxc'
'123 456'
'11111111111111111111111111111111111111111111111111'
bruno@bruno-XPS-8300:/tmp$
注意 11111111111111111111111111111111111111111111111111111 对于 long 而言太长,因此它被存储为字符串
在 valgrind 下执行:
bruno@bruno-XPS-8300:/tmp$ valgrind ./a.out f
==10003== Memcheck, a memory error detector
==10003== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==10003== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==10003== Command: ./a.out f
==10003==
read 1 longs
123
read 3 strings
'qsd wxc'
'123 456'
'11111111111111111111111111111111111111111111111111'
==10003==
==10003== HEAP SUMMARY:
==10003== in use at exit: 0 bytes in 0 blocks
==10003== total heap usage: 13 allocs, 13 frees, 5,915 bytes allocated
==10003==
==10003== All heap blocks were freed -- no leaks are possible
==10003==
==10003== For counts of detected and suppressed errors, rerun with: -v
==10003== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
bruno@bruno-XPS-8300:/tmp$
如果您不想保存 long 而是保存 int ,则当 strtol 指示有效的 long 时,请对其进行比较强制转换为 int 以检测是否有 int 溢出的值,因此请替换
if ((errno == 0) &&
(*lineptr != 0) && (*lineptr != '\n') &&
((*endptr == 0) || (*endptr == '\n'))) {
作者
if ((errno == 0) &&
(*lineptr != 0) && (*lineptr != '\n') &&
((*endptr == 0) || (*endptr == '\n')) &&
(v == ((int) v)) {
为了允许管理任意数量的数字/字符串,我使用了动态数组来保存它们