【问题标题】:how can i read data from a file then edit it and print it in the same file?如何从文件中读取数据然后对其进行编辑并将其打印在同一个文件中?
【发布时间】:2019-11-19 05:55:54
【问题描述】:

我要做的是从文件中读取此文本:

明天,明天,明天, 日复一日地以这种微小的步伐爬行, 到记录时间的最后一个音节; 我们所有的昨天都照亮了傻瓜 尘土飞扬的死亡之路。出来,出来,简短的蜡烛! 人生不过是一个行走的影子,一个可怜的球员 这让他在舞台上大放异彩 然后就再也听不见了。这是一个故事 由一个白痴讲述,充满声音和愤怒 没有任何意义。

并将其全部更改为大写字母。

如果我从一个文件中读取文本并打印到另一个文件,我可以做到这一点。

#include <stdio.h>
#include <ctype.h>
int main() {
    FILE* input_file = fopen("some_text.txt", "a+");

    char c = fgetc(input_file);
    int charc = 0;
    int alpha = 0;
    while(1){
        if(isalpha(c)){
            alpha = alpha + 1;
        }
        charc = charc + 1;

        fprintf(input_file,"%c",toupper(c));
        c = fgetc(input_file);

        if(feof(input_file)){
            break;
        }
    }
    fprintf(input_file,"\nTotal Characters: %d, Total alphabetical characters: %d",charc,alpha);

    fclose(input_file);

    return 0;
}

【问题讨论】:

  • 你不想用 C 就地编辑文件。(你可以,但你不能改变文件的长度 - 最好是冒险)。而是打开一个文件用于读取和一个用于写入。从您的读取文件中读取,对数据进行任何更改并将其写回您的写入文件。然后删除读取文件,将写入文件移回原来的读取文件名。最好只使用while ((c = fgetc (input_file)) != EOF) { ... }(只需更改toupper(c) 并回写即可,但您必须小心操作文件位置)
  • 个人认为,处理这种情况最好的办法就是获取文件大小,声明一个缓冲区来保存整个文件,打开文件进行读取,使用fread()将整个文件读入立即打开缓冲区,关闭文件,循环遍历缓冲区中的每个字符,执行buffer[i] = toupper(buffer[i]);,然后打开文件进行写入,并通过一次调用 fwrite() 将整个缓冲区写回。
  • @DavidRankin-ReinstateMonica 您的第二条评论绝对是最直接的方法。您应该将其发布为答案...

标签: c


【解决方案1】:

如果你只是想将文件中的所有字符转换为大写并将结果写回同一个文件,直接的方法是打开文件进行读取,获取文件的长度并分配一个缓冲区来保存整个文件并将整个文件读入缓冲区,然后关闭文件。然后循环遍历缓冲区中的每个字符,对每个字符调用 toupper() 并将缓冲区转换为全部大写。然后再次打开文件进行写入,这将截断文件,然后将整个缓冲区写回文件,关闭文件并在完成后释放缓冲区。

将要转换的文件名作为第一个参数的简短示例可能是:

"r"(读取)模式打开文件

...
int main (int argc, char **argv) {

    char *filebuf = NULL;
    long fplen = 0;
    FILE *fp = NULL;

    if (argc < 2) { /* validate argument given for filename */
        fprintf (stderr, "usage: %s filename\n", argv[0]);
        return 1;
    }

    if (!(fp = fopen (argv[1], "r"))) { /* open/validate file open for read */
        perror ("fopen-read");
        return 1;
    }

确定文件长度

    fseek (fp, 0, SEEK_END);            /* seek end of file */
    if ((fplen = ftell (fp)) == -1) {   /* get file length */
        perror ("ftell-length");
        return 1;
    }
    fseek (fp, 0, SEEK_SET);            /* seek beginning */

filebuf分配存储空间

    /* allocate memory for file */
    if (!(filebuf = malloc (fplen * sizeof *filebuf))) {
        perror ("malloc-filebuf");
        return 1;
    }

将整个文件读入filebuf并关闭文件

    /* read file into filebuf */
    if (fread (filebuf, 1, fplen, fp) != (size_t)fplen) {
        perror ("fread-filebuf");
        return 1;
    }
    fclose (fp);                        /* close file after read */

filebuf 转换为大写

    for (long i = 0; i < fplen; i++)    /* convert all chars toupper */
        filebuf[i] = toupper(filebuf[i]);

打开文件以写入"w" 模式并将filebuf 写入文件并关闭

    if (!(fp = fopen (argv[1], "w"))) { /* open/validate file open for write */
        perror ("fopen-write");
        return 1;
    }
    /* write filebuf to file */
    if (fwrite (filebuf, 1, fplen, fp) != (size_t)fplen) {
        perror ("fwrite-filebuf");
        return 1;
    }

    if (fclose (fp) == EOF)             /* validate close-after-write */
        perror ("fclose_after-write");

注意:您始终验证 close-after-write 以捕获与刷新流相关的任何错误,而这些错误在您对 fwrite 的验证中不会被捕获)

免费filebuf内存

    free (filebuf);

简而言之就是这样。总而言之,您可以这样做:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <limits.h>

int main (int argc, char **argv) {

    char *filebuf = NULL;
    long fplen = 0;
    FILE *fp = NULL;

    if (argc < 2) { /* validate argument given for filename */
        fprintf (stderr, "usage: %s filename\n", argv[0]);
        return 1;
    }

    if (!(fp = fopen (argv[1], "r"))) { /* open/validate file open for read */
        perror ("fopen-read");
        return 1;
    }

    fseek (fp, 0, SEEK_END);            /* seek end of file */
    if ((fplen = ftell (fp)) == -1) {   /* get file length */
        perror ("ftell-length");
        return 1;
    }
    fseek (fp, 0, SEEK_SET);            /* seek beginning */

    /* allocate memory for file */
    if (!(filebuf = malloc (fplen * sizeof *filebuf))) {
        perror ("malloc-filebuf");
        return 1;
    }
    /* read file into filebuf */
    if (fread (filebuf, 1, fplen, fp) != (size_t)fplen) {
        perror ("fread-filebuf");
        return 1;
    }
    fclose (fp);                        /* close file after read */

    for (long i = 0; i < fplen; i++)    /* convert all chars toupper */
        filebuf[i] = toupper(filebuf[i]);

    if (!(fp = fopen (argv[1], "w"))) { /* open/validate file open for write */
        perror ("fopen-write");
        return 1;
    }
    /* write filebuf to file */
    if (fwrite (filebuf, 1, fplen, fp) != (size_t)fplen) {
        perror ("fwrite-filebuf");
        return 1;
    }

    if (fclose (fp) == EOF)             /* validate close-after-write */
        perror ("fclose_after-write");

    free (filebuf);
}

输入文件示例

$ cat dat/cj2upper.txt
This is a tale
Of Captain Jack Sparrow
A Pirate So Brave
On the Seven Seas.

使用示例

$ ./bin/fread_file_toupper dat/cj2upper.txt

生成的输出文件

$ cat dat/cj2upper.txt
THIS IS A TALE
OF CAPTAIN JACK SPARROW
A PIRATE SO BRAVE
ON THE SEVEN SEAS.

检查一下,如果您有任何问题,请告诉我。有不止一种方法可以做到这一点,但这可能是更直接的途径之一。

【讨论】:

  • 请注意,在 Windows 上,与 fseek 报告的内容相比,fread 返回的字节数可能更少(因为每个 CRLF 都转换为 '\n')。
  • @dash-o 是的,好点,但是将明确的 size_t size 参数设置为 1 应该消除多字节字符问题(并且基本上使 toupper() 必须处理件可能是一个问题)。 UTF-16 引入了多种情况。
【解决方案2】:

几乎是的,这里有一些改变让它工作 首先以二进制模式打开文件,这允许您使用 fseek 在文件中移动。 rb+ 表示您可以读/写文件。 如果文件不存在,则添加一些错误处理,始终进行错误处理。 当您写回磁盘时,请确保将其刷新到磁盘,因为 fgetc 等人在缓冲区上工作。 在这种情况下 fputc 更好,因为无论如何你只写一个字符。

#include <stdio.h>
#include <ctype.h>
int main() 
{
  char filename[] = "some_text.txt";
  FILE* input_file = fopen(filename, "rb+"); // open in binary mode
  if ( input_file == NULL ) // some error handling
  {
    perror(filename);
    return -1;
  }

  int c = fgetc(input_file); // return value is int
  int charc = 0;
  int alpha = 0;

  do
  {
    if(isalpha(c))
    {
      alpha = alpha + 1;
    }
    charc = charc + 1;

    // if alpha, then go back one character and rewrite it
    if(isalpha(c)) 
    {
      fseek(input_file, -1, SEEK_CUR);
      fputc(toupper(c),input_file); // use fputc instead of fprintf
      fflush(input_file);
    }
    // read next
    c = fgetc(input_file);
  }
  while (c != EOF);

  // at end of file, add some more
  fprintf(input_file,"\nTotal Characters: %d, Total alphabetical characters: %d",charc,alpha);

  fclose(input_file);
  return 0;
}

【讨论】:

  • 为了提高效率,考虑将更新条件改为'if (islower(c))'。它将避免更新已经是大写的字符。
【解决方案3】:

出于性能原因,假设大多数字符都需要转换,利用 STDIO 是有意义的,它将利用应用程序级缓冲

示例消除错误检查以提高可读性。

main(...)
{
   // Open file
   FILE *fp = ... ;
   const int BUFFER_SIZE = 1024 ;
   char buff[BUFFER_SIZE] ;

   while ( 1 ) {
       // Read
       long loc = ftell(fp) ;
       n = fread(buff, 1, sizeof(buff), fp) ;
       if ( n <= 0 ) break ;

       // Convert
       int do_update = 0 ;
       for (int i=0 ; i<n; i++ ) {
           if ( islower(buff[i] ) {
              buff[i] = toupper(buff[i]) 
              do_update = 1 ;
           } ;
           if(isalpha(c)){
               alpha = alpha + 1;
           }
           charc = charc + 1;
        } ;

        // Update, only if anything changed
        if ( do_update ) {
            long next = ftell(fp) ;
            fseek(fp, loc, SEEK_SET) ;
            fwrite(buff, 1, n, fp) ;
            fseek(fp, next, SEEK_SET) ;
        } ;
   } ;
}

【讨论】:

    猜你喜欢
    • 2013-07-20
    • 1970-01-01
    • 1970-01-01
    • 2022-09-29
    • 1970-01-01
    • 2015-06-28
    • 1970-01-01
    • 1970-01-01
    • 2022-01-11
    相关资源
    最近更新 更多