使用c从计算机读取和打印文本文件

专属用户

我想读取我的文档文件夹中的文本文件。我不明白为什么我不能读取它,或者如果它被读取,为什么我不能在我的控制台应用程序上写它。当我运行程序时,它只是卡住了。它什么都不做。

我想阅读的文件:

330400199711111890 W1         ZhejiangJianxin                                   
330411193807234897 W2         ZhejiangJianxinÐãÖÞÇø                             
331122199502289716 W3         ZhejiangçÆÔÆÏØ                                    
330402192503284421 M1         ZhejiangJianxinÄϺþÇø                             
330225198403042936 W4         ZhejiangÏóɽÏØ                                    
330681194109099151 W5         ZhejiangÖîôßÊÐ                                    
330727195612078712 W6         ZhejiangÅÍ°²ÏØ                                    
330921193708179044 M2         Zhejiangá·É½ÏØ                                    
330303195103046912 W7         ZhejiangWenzhouÁúÍåÇø                             
330781197108138752 W8         ZhejiangÀ¼ÏªÊÐ                                    
330127193411280584 M3         Zhejiang´¾°²ÏØ                                    
331001193310027792 W9         ZhejiangTaizhouDowntown                           
331125196503132898 W10        ZhejiangÔƺÍÏØ                                    
331000192003056719 W11        ZhejiangTaizhou                                   
330106194503103959 W12        ZhejiangHangzhouWestlakeDistrict                  
330106194610285524 M4         ZhejiangHangzhouWestlakeDistrict                  
330301198301227758 W13        ZhejiangWenzhouDowntown 

该程序:

#include <stdio.h>
#include <stdlib.h>
#define NAME_LEN 80

// struct with student information. id, name and address
typedef struct
{
    char id[19];
    char code[20];
    char address[50];
} Student;


int main()
{
    Student newStudent;

    FILE *fp;
    fp=fopen("ID500.txt","r");

    char id[20],code[20],address[50];

    while(!feof(fp))
    {
        fscanf(fp,"%s %s %s",id,code,address);
        printf("%s %s %s\n",id,code,address);
    }
    return 0;
}
名义动物

最好将文件名作为程序的命令行参数提供,因为这样更易于测试和使用。

在文件中,每一行似乎都是一个单独的记录。因此,最好读取每一行,然后解析该行中的字段。

考虑以下:

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

#define  MAX_LINE_LEN  500

int main(int argc, char *argv[])
{
    char  line[MAX_LINE_LEN + 1]; /* +1 for the end-of-string '\0' */
    FILE *in;

    if (argc != 2) {
        fprintf(stderr, "\n");
        fprintf(stderr, "Usage: %s FILENAME\n", argv[0]);
        fprintf(stderr, "\n");
        return EXIT_FAILURE;
    }

    in = fopen(argv[1], "r");
    if (!in) {
        fprintf(stderr, "Cannot open %s: %s.\n", argv[1], strerror(errno));
        return EXIT_FAILURE;
    }

    while (fgets(line, sizeof line, in) != NULL) {
        char  id[20], code[20], address[50], dummy;

        if (sscanf(line, " %19s %19s %49s %c", id, code, address, &dummy) == 3) {
            /* The line did consist of three fields, and they are
               now correctly parsed to 'id', 'code', and 'address'. */

            printf("id = '%s'\ncode = '%s'\naddress = '%s'\n\n",
                   id, code, address);

        } else {

            /* We do have a line, but it does not consist of
               exactly three fields. */

            /* Remove the newline character(s) at the end of line. */
            line[strcspn(line, "\r\n")] = '\0';

            fprintf(stderr, "Cannot parse line '%s'.\n", line);

        }
    }

    if (ferror(in)) {
        fprintf(stderr, "Error reading %s.\n", argv[1]);
        return EXIT_FAILURE;
    } else
    if (fclose(in)) {
        fprintf(stderr, "Error closing %s.\n", argv[1]);
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

上面,argc包含命令行参数的数量,程序名称用作第一个(第零个,argv[0])参数。我们需要两个:程序名和要读取的文件名。否则,我们会打印出一条使用消息。

我们尝试打开文件进行阅读。如果fopen()失败,则返回NULL,并将错误存储在 中errnostrerror(errno)产生人类可读的错误消息。

fgets(array, sizeof array, stream)从 中读取一行(除非太长而无法放入arraystream如果成功,它返回一个指向第一个元素的指针array如果失败——例如,没有更多可读——,它返回NULL

请记住,feof(stream)不会检查是否stream有更多数据要读取。它只报告是否stream已经遇到结束因此,不是读取直到feof()返回 true,您应该简单地读取数据直到读取失败,然后检查读取失败的原因。这就是上面的示例程序所做的。

我们想把每一行当作一个单独的记录。因为fscanf()不区分'\n'空格(在转换规范中,也不在隐式跳过空格时),所以 usingfscanf(in, " %19s %19s %49s", ...)不会将解析限制为单行:它们可能在同一行,也可能在不同的行,甚至在之间。为了将我们的解析限制为一行,我们首先使用 读取每一行fgets(),然后尝试解析该行,并且仅使用sscanf(). sscanf()工作方式与 类似fscanf(),但从字符串而不是流中获取输入。)

为了避免缓冲区溢出,我们必须告诉sscanf()我们的缓冲区可以有多长,记住为字符串结束标记 (NUL, '\0')保留一个字符因为id是 20 个字符,我们最多可以使用 19 个字符作为 ID 字符串,因此我们需要使用它%19s来正确地进行转换。

from 的返回值sscanf()是成功转换的次数。通过%c在我们预计在正常情况下会失败的末尾添加一个虚拟字符 ( ) 转换,我们可以检测该行是否包含超过我们预期的内容。这就是为什么该sscanf()模式有四次转换,但如果输入行具有我们预期的格式,我们需要前三个转换成功,第四个,虚拟转换失败。

请注意sscanf(),如果我们接受不同格式的输入,我们可以尝试几种不同的表达式。我喜欢称之为推测性解析您只需要对它们进行排序,以便您首先尝试最复杂的那些,然后接受产生预期成功转换次数的第一个。有关这方面的实际示例,请查看我在另一个答案中使用示例 C 代码,以允许用户在命令行上使用名称=值对指定模拟详细信息。

line[strcspn(line, "\r\n")] = '\0';表达式是一招,真的。strcspn()是一个标准的 C<string.h>函数,它返回第一个字符串参数中的字符数,直到遇到字符串结尾或第二个字符串中的任何字符,以先发生者为准。因此,strcspn(line, "\r\n")产生line直到字符串结尾'\r'、 或'\n'遇到的字符数,以先发生者为准。我们通过使用它作为行缓冲区的索引来修剪字符串的其余部分,并使字符串在那里结束。(请记住,NUL 或'\0'始终以 C 结尾字符串。)

while循环之后,我们检查为什么fgets()返回NULL. 如果ferror()返回 true,则存在真正的读取错误。这些现在非常非常罕见,但不检查它们就像在没有安全装置的情况下拿着武器四处走动:这是一种零回报的不必要风险。

在大多数操作系统中,fclose()如果您以只读方式打开文件甚至不会失败,但在某些情况下可能会出现一些特殊情况。(此外,当您写入流时它可能会失败,因为 C 库可能会缓存数据——将其保存在内部缓冲区中,而不是立即写入,以提高效率——并且仅在您关闭流时才将其写出。像任何写入一样,这可能由于真正的写入错误而失败;例如,如果存储介质已经满了。)

然而,检查ferror()fclose()并让用户知道只需要几行 C 代码我个人非常讨厌不这样做的程序,因为它们确实有可能在没有警告的情况下悄悄丢失用户数据。用户可能认为一切都很好,但是下次他们尝试访问他们的文件时,其中一些文件丢失了……他们通常最终归咎于操作系统,而不是真正的罪魁祸首,是那些失败的坏程序警告用户他们可能检测到的错误。

(最好尽早学会这样做。就像安全性一样,错误检查不是你以后可以真正关注的:你要么设计它,要么它就不可靠。)

另请注意,Linux 手册页项目包含维护良好的 C 库函数列表(以及 POSIX.1、GNU 和 Linux 特定函数)。不要被它的名字所迷惑。每个页面都包含一个符合部分,它告诉您该页面上描述的一个或多个功能符合哪些标准。如果是 C89,那么它几乎适用于您可以想象的所有操作系统。如果是 C99 或任何 POSIX.1 版本,它可能无法在 Windows 或 DOS(或使用古老的 Borland C 编译器)中运行,但在大多数其他操作系统中都可以运行。


因为 OP 显然正在读取非 ASCII 文件,所以我建议尝试使用宽字符和宽字符串的本地化版本的程序:

#include <stdlib.h>
#include <locale.h>
#include <string.h>
#include <wchar.h>
#include <stdio.h>
#include <errno.h>

#define  MAX_WLINE_LEN  500

int main(int argc, char *argv[])
{
    wchar_t  line[MAX_WLINE_LEN + 1]; /* +1 for the end-of-string L'\0' */
    FILE *in;

    if (argc != 2) {
        fprintf(stderr, "\n");
        fprintf(stderr, "Usage: %s FILENAME\n", argv[0]);
        fprintf(stderr, "\n");
        return EXIT_FAILURE;
    }

    if (setlocale(LC_ALL, "") == NULL)
        fprintf(stderr, "Warning: Your C library does not support your currently set locale.\n");

    if (fwide(stdout, 1) < 1)
        fprintf(stderr, "Warning: Your C library does not support wide standard output.\n");

    in = fopen(argv[1], "r");
    if (!in) {
        fprintf(stderr, "Cannot open %s: %s.\n", argv[1], strerror(errno));
        return EXIT_FAILURE;
    }
    if (fwide(in, 1) < 1)
        fprintf(stderr, "Warning: Your C library does not support wide input from %s.\n", argv[1]);

    while (fgetws(line, sizeof line / sizeof line[0], in) != NULL) {
        wchar_t  id[20], code[20], address[50], dummy;

        if (swscanf(line, L" %19ls %19ls %49ls %lc", id, code, address, &dummy) == 3) {
            /* The line did consist of three fields, and they are
               now correctly parsed to 'id', 'code', and 'address'. */

            wprintf(L"id = '%ls', code = '%ls', address = '%ls'\n",
                   id, code, address);

        } else {

            /* We do have a line, but it does not consist of
               exactly three fields. */

            /* Remove the newline character(s) at the end of line. */
            line[wcscspn(line, L"\r\n")] = L'\0';

            fprintf(stderr, "Cannot parse line '%ls'.\n", line);

        }
    }

    if (ferror(in)) {
        fprintf(stderr, "Error reading %s.\n", argv[1]);
        return EXIT_FAILURE;
    } else
    if (fclose(in)) {
        fprintf(stderr, "Error closing %s.\n", argv[1]);
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

上面的代码是纯 C99 代码,应该适用于所有具有符合 C99 或更高版本的标准 C 库的操作系统。(不幸的是,微软不愿意实现一些 C99 特性,即使它“贡献”到 C11,这意味着上面的代码可能需要额外的特定于 Windows 的代码才能在 Windows 上运行。它在 Linux、BSD、和 Mac,但是。)

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何从Android上的计算机读取文本文件

来自分类Dev

如何从本地计算机读取/写入文本文件?

来自分类Dev

如何从Android上的计算机读取文本文件

来自分类Dev

使用plink / putty与Windows本地计算机的文本文件的内容在远程计算机上创建文本文件

来自分类Dev

在Perl中读取和打印文本文件

来自分类Dev

如何逐行读取和打印文本文件的内容?

来自分类Dev

在vi中创建文本文件会更改我的计算机吗?

来自分类Dev

Get-AD计算机与文本文件内容不匹配

来自分类Dev

在vi中创建文本文件会更改我的计算机吗?

来自分类Dev

查找所有带有特定文本文件的计算机

来自分类Dev

在c#中分别读取文本文件和访问文本文件的元素

来自分类Dev

从文本文件(C#)读取和返回数据

来自分类Dev

使用HTML和Javascript从文本文件读取

来自分类Dev

使用 VBA 读取和处理文本文件的问题

来自分类Dev

使用C#读取Excel文件和写入文本文件的速度非常慢

来自分类Dev

如何使用C#打印文本文件

来自分类Dev

搜索和读取文本文件

来自分类Dev

C ++使用向量从文本文件读取和写入数字

来自分类Dev

C ++使用fstream对象读取和写入文本文件时遇到问题

来自分类Dev

如何读取已在使用的文本文件(Windows C ++)

来自分类Dev

使用C#从文本文件读取

来自分类Dev

使用scanf重新读取c中的文本文件

来自分类Dev

使用fscanf在C中逐行读取文本文件

来自分类Dev

使用C程序读取文本文件中的表

来自分类Dev

使用C从文本文件读取输入参数

来自分类Dev

C ++文本文件打印

来自分类Dev

读取文本文件C#

来自分类Dev

读取文本文件错误C

来自分类Dev

C ++逐行读取文本文件

Related 相关文章

热门标签

归档