【问题标题】:Append a text to a beginning of a file in C does not work将文本附加到 C 中文件的开头不起作用
【发布时间】:2021-05-30 15:31:10
【问题描述】:

所以伪代码是:

现有文件 = 读取文件的全部内容。

String newcontent = "Blah Blah This is first line" + 现有

f.write(newcontent);

实际代码是

void Prepend(char *string, char *file_name)
{   

    char buf[100];
    FILE *fp1, *fp2;
    Append(string, "temp_file");
    
    fp1 = fopen(file_name, "a+");
    fp2 = fopen("temp_file", "a+");
    
    if (!fp1 && !fp2) {
        printf("Unable to open/"
               "detect file(s)\n");
        exit(1);
    }
 
    fprintf(fp2, "\n");
 

    while (!feof(fp1)) {
        fgets(buf, sizeof(buf), fp1);
    }
 
    rewind(fp2);
 

    while (!feof(fp2)) {
        fgets(buf, sizeof(buf), fp2);
    }
      fclose(fp1);
      fclose(fp2);
      remove(temp_file);
}

/*-----------------------------------------------------------------------------*/

void Append(char *string, char *file_name)

{   

    FILE *file = fopen(file_name, "a");
    
    if(file==NULL)
    {
        printf("Error opening file.");
    }
    else 
    {
    
        fputs(string, file);    
        
    }
    
    fclose(file);
}

我知道fseek 和其他指针相关的东西可能有一种方法,但我认为使用“简单方法”并创建一个新的临时文件并正确删除它会更好更快之后。

好吧,它也不起作用。

【问题讨论】:

  • 请注意,if (!fp1 && !fp2) 只有在两个文件都无法打开时才为真。如果其中一个(或两个)文件无法打开,请使用if (fp1 == NULL || fp2 == NULL)(或!fp1 等,如果您愿意,我不会,但我可能是少数)使测试为真。
  • 如果您以追加模式打开文件,所有写入都将发生在文件末尾(并且文件不会被截断)。只有当文件为空或不存在时才会在开始时写入数据。
  • @JonathanLeffler 是的,我知道。但这就是这里的目的。我正在创建一个名为temp_file 的不存在文件并将用户的输入字符串写入他。然后,我将原始文件的内容附加到这个字符串中,这就是我在原始数据之前“添加”用户字符串的方式。
  • 否;您正在打开一个现有文件 temp_file 或创建一个文件(如果它不存在)。您不知道该文件不存在;你只是希望它不存在。您可以使用"w""w+" 模式来创建空文件或截断现有文件。现在,如果一切正常,temp_file 不存在可能是正确的。

标签: c file text append prepend


【解决方案1】:

由于您使用的是临时文件,因此不需要辅助缓冲区,只需附加文本,然后将旧文件内容移动到新文件中即可。

一些你应该注意的事情,

  • if (!fp1 && !fp2) 仅在两个文件都无法打开时才为真,最好单独检查结果,以便我们知道失败的地方。您可以将&& 替换为||,但除非您重新检查文件指针值,否则它失败的原因会很模糊。
  • 看来您从未将数据从fp1 写入fp2 我只看到对 fgets() 的调用,您将fp1 读入buf 然后您将fp2 读入buf,什么都不做两次都有数据。如果文件大于 100 字节,您最终会在 buf 中存储最后 100 字节或更少的数据。
  • 这不一定是最糟糕的事情,但最好只打开具有所需权限的文件。打开一个只需要在“a+”模式下读取的文件有点奇怪
  • 在创建新文件之前,最好先检查一下该名称的文件是否不存在。您最好在系统的临时目录或程序的专用 tmp 目录中创建文件。为其名称使用唯一的字符串也是一个好主意。可能类似于“[my prog]-[original file name]-[.tmp]”而不是这样的通用名称。

一个应该工作的方法的简短示例,带有错误检查(不一定是最好的错误检查,但可以让您了解可能发生错误的位置):

#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>

int Prepend(char *string, char *file_name)
{
    FILE *fp1 = NULL, *fp2 = NULL;
    struct stat fs;
    if (stat("temp_file", &fs) == 0) {
        printf("Error, there is already a file named \"temp_file\" in the current working directory\n");
        return -1;
    }
    if ((fp1 = fopen(file_name, "r")) == NULL) {
        printf("Error : %s\n", strerror(errno));
        printf("Failed to Open file %s\n", file_name);
        return -1;
    }
    if ((fp2 = fopen("temp_file", "w")) == NULL {
        printf("Error : %s\n", strerror(errno));
        printf("Unable to create Temporary file\n");
        fclose(fp1);
        return -1;
    }
    if (fputs("Prepended String\n", fp2) == EOF) {
        printf("Failed to write string to file\n");
        fclose(fp1);
        fclose(fp2);
        if (remove("temp_file") != 0)
            printf("Error : %s, while removing temp_file\n", strerror(errno));
        return -1;
    }
    int c;
    while((c = fgetc(fp1)) != EOF) {
        if(fputc(c, fp2) == EOF) {
            printf("Error while transfering data from %s to %s\n", file_name, "temp_file");
            fclose(fp1);
            fclose(fp2);
            if (remove("temp_file") != 0)
                printf("Error : %s, while removing temp_file\n", strerror(errno));

            return -1;
        }
    }
    fclose(fp1);
    if (remove(file_name) != 0) {
        printf("Error : %s, while removing %s\n", strerror(errno), file_name);
        fclose(fp2);
        return -1;
    }


    fclose(fp2);
    if (rename("temp_file", file_name) != 0) {
        printf("Error : %s, while renaming temp_file\n", strerror(errno));
        return -1;
    }
    return 0;
}

fclose() 也可以在错误时返回 EOF,并设置 errno 来指示错误。但是,对流的任何进一步访问(包括对 fclose() 的另一个调用)都会导致未定义的行为。因此您可以打印错误,但您无能为力。

【讨论】:

  • 谢谢。有用。你的代码和我的代码到底有什么不同(除了显而易见的)?我的意思是,从你的角度来看,我哪里做错了?
  • @NoobCoder,程序遇到的第一个大问题是if(!feof()) 位。我假设会创建临时文件并写入您的字符串,但之后没有其他任何事情发生,对吗?最好发布项目的结果,而不是仅仅说“它不起作用”。
  • 你说得对,我下次再做。在fclose 之后检查呢?我不应该这样做吗?因为fclose 可能会失败。在remove 之后?并在remove 之后到unlink 以确保任何地方都没有软链接?
  • 对不起,我的手机很难同时阅读您的代码和评论...但基本上while(!feof()) 在技术上实际上是正确的,您没有对数据做任何事情。该循环将继续执行并覆盖 buf 的内容,直到文件被读取,然后什么都没有写入。
  • 然后你继续对 fp2 做同样的事情,如果你将读取和写入都放在一个 while 循环中,我想它可以工作。是的,这些函数中的任何一个在技术上都可能失败并设置errno,因此您可以检查出了什么问题或将其作为返回值传递。
【解决方案2】:

这里是一个小例子,只使用两个而不是三个文件。

void prepend(const char *filename, const char *str)
{
    // open the orig file (read only)
    FILE *orig = fopen(filename, "r");

    // open tmp file (read / write)
    FILE *tmp = fopen("temp_file", "w+");

    // write string into tmp file (prepend)
    fwrite(str, 1, strlen(str), tmp);

    // file size of orig
    fseek(orig, 0L, SEEK_END);
    long orig_size = ftell(orig);
    rewind(orig); // set pos to 0

    // transfer bytes from orig to tmp (append)
    char *buf = malloc(orig_size);
    fread(buf, 1, orig_size, orig);
    fwrite(buf, 1, orig_size, tmp);
    free(buf);

    // close orig and delete it
    fclose(orig);
    remove(filename);

    // close and rename tmp file as orig
    fclose(tmp);
    rename("temp_file", filename);
}

注意:为了简短起见,不涉及错误检查。

【讨论】:

    猜你喜欢
    • 2021-10-22
    • 1970-01-01
    • 2014-12-17
    • 1970-01-01
    • 2012-07-21
    • 1970-01-01
    • 2013-11-03
    • 2013-06-12
    • 2021-03-05
    相关资源
    最近更新 更多