逐行写入文本文件 c

Posted

技术标签:

【中文标题】逐行写入文本文件 c【英文标题】:Write into text file line by line c 【发布时间】:2021-12-30 04:51:59 【问题描述】:

我编写了一个用户空间程序来逐行读取内核设备,不知何故,每次读取都会覆盖数据。你能告诉我如何修复我的代码吗?

代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/mman.h>
 

#define BUFFER_LENGTH 256

int main()



  int  ret,fd;
  char buffer[BUFFER_LENGTH];
  FILE * fPtr;
  unsigned int i=0;

  if((fd = open("/dev/show_log_device_dev", O_RDWR)) == -1)
    perror("Failed to open the file");
  
  //printf("/dev/show_log_device_dev opened.\n");
  //fflush(stdout);

  fPtr = fopen("log.txt", "w+");

  int bytesRead = 0;

  while (bytesRead < sizeof(buffer)) 
    int ret = read(fd, buffer + bytesRead, sizeof(buffer) - bytesRead);
    if (ret == 0)
        break;
    if (ret == -1)   
      perror("Failed to read the message from the device.");
      return errno;
      /* Handle error */
    
    bytesRead += ret; 
    printf("read from /dev/show_log_device_dev. %s\n",buffer);

  
  if(lseek(fPtr,0,SEEK_SET)!=0) 
    fprintf(fPtr,"%s",buffer);
  

  fclose(fPtr);

我希望输出文件“log.txt”包含写入缓冲区的所有行,每个读取行在行之间跳过行。请告诉我正确的方法,而不是我上面写的 fprintf 尝试。

谢谢。

【问题讨论】:

为什么是lseek()?你有没有确保buffer 是一个正确的以 0 结尾的字符串? 我没有验证缓冲区是否为 0 终止...此外,我使用 lseek 查找文件的末尾并写入它,至少这就是我虽然写作的原因。我需要逐行写入该文件的正确方法,即将buffer 写入下一行第一个可用位置的文件中。我不知道该怎么做。 试试这里的解决方案 ***.com/questions/2029103/…>. 您正在寻找文件的开头...(还有lseek() 用于文件描述符,而不是FILE 指针。如何编译?) 用户空间代码看起来很合理。除了lseek 打电话给FILE*。 “情况太不同了,我不是试图从文件中读取,而是从设备中读取。” - 从设备读取不应与从文本文件读取不同......除非您的设备非常特殊。在最后一种情况下,您需要提供您设备的代码,否则我们无法为您提供帮助。 【参考方案1】:
char buffer[BUFFER_LENGTH];
while()
...read(fd, buffer + bytesRead, sizeof(buffer) - bytesRead);

这条线是个大问题。基本上这试图将整个文件存储到buffer。但是buffer 的大小很小(256 字节)。

如果文件太大,read 将在第一遍中将 256 存储到buffer。在循环的第二遍中,read 将尝试向同一个缓冲区添加另外 256 个字节。

相反,您必须读取小块并在循环内回写。

fPtr = fopen("log.txt", "w+");

这将以读/写模式打开日志文件,但您只需要写入即可。由于这是一个日志文件,请考虑使用"a" 选项附加到日志文件。

fprintf(fout, "%s", buffer);

当您读取缓冲区时,它可能不会以空值终止。请改用fwrite,或者在使用fprintf 之前确保buffer 为空终止

#define BUFFER_LENGTH 256
int main()

    int fd = open("/dev/show_log_device_dev", O_RDONLY);
    if(fd == -1)
     perror("open failed"); return 0; 

    FILE* fout = fopen("log.txt", "w"); //or "a" to create new file
    if(fout == NULL)
     close(fd); perror("fopen failed, log.txt is busy!"); return 0; 

    while (1) 
    
        char buffer[BUFFER_LENGTH];
        int ret = read(fd, buffer, sizeof(buffer));
        if (ret == 0)
            break;
        if (ret == -1) 
        
            perror("Failed to read the message from the device.");
            return errno;
        
        fwrite(buffer, 1, ret, fout);
        //fprintf(fout, "%s", buffer);
    

    fclose(fout);
    close(fd);
    return 0;

注意,lseek(fPtr,0,SEEK_SET) 是错误的,没有必要。此方法除了从open 获得的文件描述符。但是fPtrFILE*句柄从fopen获取的。

如果可能,请考虑对输入和输出使用标准 c 函数 FILE*/fopen。这样你就可以使用同一组函数fopen,fread,fwrite,fclose,fseek,ftell。你只需要一个头文件:

#include <stdio.h>

int main()

    FILE* fin = fopen("/dev/show_log_device_dev", "r");
    if (!fin)
     perror("input error"); return 0; 

    FILE* fout = fopen("log.txt", "w"); //or "a" to append to log
    if (!fout) 
    fclose(fin); perror("output error, log.txt is busy!"); return 0; 

    while (1)
    
        char buffer[256];
        int ret = fread(buffer, 1, sizeof(buffer), fin);
        if (ret == 0)
            break;
        fwrite(buffer, 1, ret, fout);
    

    fclose(fout);
    fclose(fin);
    return 0;

【讨论】:

感谢您的解决方案和详细解释! 答案不应该仅仅参考 cmets 以获取有关为什么出错的信息。它应该解释。评论是短暂的,随时可能消失。 @EricPostpischil 我的回答与 cmets 无关。我只备份了lseek cmets。失败的lseek 尝试不会改变程序的输出。无论如何,更新了答案。 更新,地址fopen输入法。将输出更改为"w",如果需要追加,您可以更改为"a"

以上是关于逐行写入文本文件 c的主要内容,如果未能解决你的问题,请参考以下文章

delphi中怎么逐行读取文本文件的数据并将每行分别写入指定的不同编辑框

C++文件读写操作逐字符读取文本和逐行读取文本

使用 Ruby 逐行读取、编辑和写入文本文件

Python逐行读取txt文本,按符合分割词并逐行写入txt

python 插入文本 详见问题补充

nodejs 文本逐行读写功能的实现