如何在C中从文本文件中删除特定行?

如何在C中从文本文件中删除特定行?,c,C,例如: 乔治50 40 石灰30 20 凯伦1060 输入名称:石灰 然后文本文件将是: 乔治50 40 凯伦1060 试试这个: /* C Program Delete a specific Line from a Text File */ #include <stdio.h> int main() { FILE *fileptr1, *fileptr2; char filename[40]; char ch; int delete_line,

例如:

乔治50 40
石灰30 20
凯伦1060

输入名称:石灰

然后文本文件将是:

乔治50 40
凯伦1060

试试这个:

 /* C Program Delete a specific Line from a Text File
 */
#include <stdio.h>

int main()
{
    FILE *fileptr1, *fileptr2;
    char filename[40];
    char ch;
    int delete_line, temp = 1;

    printf("Enter file name: ");
    scanf("%s", filename);
    //open file in read mode
    fileptr1 = fopen(filename, "r");
    ch = getc(fileptr1);
   while (ch != EOF)
    {
        printf("%c", ch);
        ch = getc(fileptr1);
    }
    //rewind
    rewind(fileptr1);
    printf(" \n Enter line number of the line to be deleted:");
    scanf("%d", &delete_line);
    //open new file in write mode
    fileptr2 = fopen("replica.c", "w");
    ch = 'A';
    while (ch != EOF)
    {
        ch = getc(fileptr1);
        //except the line to be deleted
        if (temp != delete_line)
        {
            //copy all lines in file replica.c
            putc(ch, fileptr2);
        }
        if (ch == '\n')
        {
            temp++;
        }
    }
    fclose(fileptr1);
    fclose(fileptr2);
    remove(filename);
    //rename the file replica.c to original name
    rename("replica.c", filename);
    printf("\n The contents of file after being modified are as follows:\n");
    fileptr1 = fopen(filename, "r");
    ch = getc(fileptr1);
    while (ch != EOF)
    {
        printf("%c", ch);
        ch = getc(fileptr1);
    }
    fclose(fileptr1);
    return 0;
}
/*C程序从文本文件中删除特定行
*/
#包括
int main()
{
文件*fileptr1,*fileptr2;
字符文件名[40];
char ch;
int delete_行,temp=1;
printf(“输入文件名:”);
scanf(“%s”,文件名);
//以读取模式打开文件
fileptr1=fopen(文件名为“r”);
ch=getc(fileptr1);
while(ch!=EOF)
{
printf(“%c”,ch);
ch=getc(fileptr1);
}
//倒带
倒带(fileptr1);
printf(“\n输入要删除行的行号:”);
scanf(“%d”,删除行(&U);
//以写模式打开新文件
fileptr2=fopen(“replica.c”、“w”);
ch='A';
while(ch!=EOF)
{
ch=getc(fileptr1);
//要删除的行除外
如果(温度!=删除线)
{
//复制文件replica.c中的所有行
putc(ch,fileptr2);
}
如果(ch='\n')
{
temp++;
}
}
fclose(fileptr1);
fclose(fileptr2);
删除(文件名);
//将文件replica.c重命名为原始名称
重命名(“replica.c”,文件名);
printf(“\n修改后的文件内容如下:\n”);
fileptr1=fopen(文件名为“r”);
ch=getc(fileptr1);
while(ch!=EOF)
{
printf(“%c”,ch);
ch=getc(fileptr1);
}
fclose(fileptr1);
返回0;
}

参考-

有几种方法可以删除一行, 一个简单的方法是打开两个文件,一个输入一个输出

然后逐行复制并跳过要删除的行 完成后,删除旧文件并将新文件重命名为旧名称

fopen()
fgets()
fputs()
rename()
unlink()
编辑:上述解决方案适用于小文件,但由于注释,它不适用于大文件,因此这里有一个替代解决方案(GCC C99),它读取整个文件,查找名称,然后在缓冲区中向前移动该行之后的行

#include <stdio.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdbool.h>

static size_t deleteLine( char*, size_t, const char* );

int main(int argc, char* argv[])
{
  char file[] = "yourfile.txt";

  if ( --argc )
  { 
    struct stat st;
    if ( stat( file, &st ) != -1 )
    {
      // open the file in binary format
      FILE* fp = fopen( file, "rb" );
      if ( fp != NULL )
      {
        // allocate memory to hold file
        char* buffer = malloc( st.st_size ); 

        // read the file into a buffer
        if ( fread(buffer, 1, st.st_size, fp) == st.st_size)
        {
          fclose(fp);

          size_t newSize = deleteLine( buffer, st.st_size, argv[1] );

          fp = fopen( file, "wb" );
          if ( fp != NULL )
          {
            fwrite(buffer, 1, newSize, fp);
            fclose(fp);
          }
          else
          {
            perror(file);
          }
        }
        free(buffer);
      }
      else
      {
        perror(file);
      }
    }
    else
    {
      printf( "did not find %s", file );
    }
  }
  return 0;
}

static size_t deleteLine( char* buffer, size_t size, const char* playerName )
{
  // file format assumed to be as specified in the question i.e. name{space}somevalue{space}someothervalue\n
  // find playerName
  char* p = buffer; 
  bool done = false;
  size_t len = strlen(playerName);
  size_t newSize = 0;
  do
  {
    char* q = strchr( p, *playerName ); // look for first letter in playerName
    if ( q != NULL )
    {
      if ( strncmp( q, playerName, len ) == 0 ) // found name?
      {
        size_t lineSize = 1; // include \n already in line size

        // count number of characters the line has.
        for ( char* line = q; *line != '\n'; ++line) 
        {
          ++lineSize;
        }

        // calculate length left after line by subtracting offsets
        size_t restSize = (size_t)((buffer + size) - (q + lineSize));

        // move block with next line forward
        memmove( q, q + lineSize, restSize );

        // calculate new size
        newSize = size - lineSize;
        done = true;
      }
      else
      {
        p = q + 1; // continue search
      }
    }
    else
    {
      puts( "no such name" );
      done = true;
    }
  }
  while (!done);

  return newSize;
}
#包括
#包括
#包括
#包括
静态大小\u t删除行(字符*,大小\u t,常量字符*);
int main(int argc,char*argv[])
{
char file[]=“yourfile.txt”;
如果(--argc)
{ 
结构统计;
if(stat(file,&st)!=-1)
{
//以二进制格式打开文件
文件*fp=fopen(文件“rb”);
如果(fp!=NULL)
{
//分配内存以保存文件
char*buffer=malloc(st.st\U大小);
//将文件读入缓冲区
如果(fread(缓冲区,1,st.st\U大小,fp)=st.st\U大小)
{
fclose(fp);
size_t newSize=deleteLine(缓冲区,st.st_大小,argv[1]);
fp=fopen(文件“wb”);
如果(fp!=NULL)
{
fwrite(缓冲区,1,新闻大小,fp);
fclose(fp);
}
其他的
{
佩罗尔(档案);
}
}
自由(缓冲);
}
其他的
{
佩罗尔(档案);
}
}
其他的
{
printf(“未找到%s”,文件);
}
}
返回0;
}
静态大小\u t删除行(字符*缓冲区、大小\u t大小、常量字符*播放名称)
{
//文件格式假定为问题中指定的格式,即名称{space}somevalue{space}someothervalue\n
//找到playerName
char*p=缓冲区;
bool done=false;
尺寸长度=strlen(playerName);
大小\u t新闻大小=0;
做
{
char*q=strchr(p,*playerName);//查找playerName中的第一个字母
如果(q!=NULL)
{
if(strncmp(q,playerName,len)==0)//找到的名称?
{
size\u t lineSize=1;//包含\n已在行大小中
//计算该行包含的字符数。
对于(char*line=q;*line!='\n';++line)
{
++线路尺寸;
}
//通过减去偏移量计算线后剩余的长度
size_t restSize=(size_t)((缓冲区+大小)-(q+行大小));
//将块向前移动下一行
memmove(q,q+行大小,restSize);
//计算新尺寸
newSize=大小-行大小;
完成=正确;
}
其他的
{
p=q+1;//继续搜索
}
}
其他的
{
出售(“无该名称”);
完成=正确;
}
}
而(!完成);
返回新闻大小;
}

您不需要创建新文件。您可以使用
r+
打开原始文件,并将其内容存储到数组中(如下所示)。然后,可以使用for循环扫描数组中要跳过的行,并删除该行。然后,您可以使用
fseek(filename,0,SEEK\u SET)
(重置文件的位置指示器)覆盖文件内容,并使用for循环和fprintf将内容从修改的数组复制到文件中。
(但是,使用此方法,您需要在最后一个for循环中输入一个额外的空行,以覆盖原始文件的最后一行。)

如果要在数千行的多个文件上执行此操作?这不是一个很好的解决方案……这是正确的,我的答案是在OPs问题之后进行校准的,即,某类学校任务的文件长度约为10行,在实际问题中,情况会有所不同。你不需要在
main
释放(缓冲区)
?@WoodrowBarlow是的,似乎忘记了这一点。感谢您指出这一点。在现实世界中,您需要首先按照某些标准对行进行排序,并至少生成一个部分索引,即第一个字母,以便在每次搜索之前能够找到该位置。您可以将该概念扩展到索引中更重要的字符,但当您将索引概念限制到极限时,您最终将得到文本文件,该文件以类似数据库的方式按不同的重新定义标准和复杂算法排序。如果您想在不编程数据库的情况下最大限度地提高效率,只需订购b
#include <stdio.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdbool.h>

static size_t deleteLine( char*, size_t, const char* );

int main(int argc, char* argv[])
{
  char file[] = "yourfile.txt";

  if ( --argc )
  { 
    struct stat st;
    if ( stat( file, &st ) != -1 )
    {
      // open the file in binary format
      FILE* fp = fopen( file, "rb" );
      if ( fp != NULL )
      {
        // allocate memory to hold file
        char* buffer = malloc( st.st_size ); 

        // read the file into a buffer
        if ( fread(buffer, 1, st.st_size, fp) == st.st_size)
        {
          fclose(fp);

          size_t newSize = deleteLine( buffer, st.st_size, argv[1] );

          fp = fopen( file, "wb" );
          if ( fp != NULL )
          {
            fwrite(buffer, 1, newSize, fp);
            fclose(fp);
          }
          else
          {
            perror(file);
          }
        }
        free(buffer);
      }
      else
      {
        perror(file);
      }
    }
    else
    {
      printf( "did not find %s", file );
    }
  }
  return 0;
}

static size_t deleteLine( char* buffer, size_t size, const char* playerName )
{
  // file format assumed to be as specified in the question i.e. name{space}somevalue{space}someothervalue\n
  // find playerName
  char* p = buffer; 
  bool done = false;
  size_t len = strlen(playerName);
  size_t newSize = 0;
  do
  {
    char* q = strchr( p, *playerName ); // look for first letter in playerName
    if ( q != NULL )
    {
      if ( strncmp( q, playerName, len ) == 0 ) // found name?
      {
        size_t lineSize = 1; // include \n already in line size

        // count number of characters the line has.
        for ( char* line = q; *line != '\n'; ++line) 
        {
          ++lineSize;
        }

        // calculate length left after line by subtracting offsets
        size_t restSize = (size_t)((buffer + size) - (q + lineSize));

        // move block with next line forward
        memmove( q, q + lineSize, restSize );

        // calculate new size
        newSize = size - lineSize;
        done = true;
      }
      else
      {
        p = q + 1; // continue search
      }
    }
    else
    {
      puts( "no such name" );
      done = true;
    }
  }
  while (!done);

  return newSize;
}