C语言 如果文件已经存在,则在文件名后附加数字

mum43rcc  于 2023-10-16  发布在  其他
关注(0)|答案(2)|浏览(127)

我试图写一个函数,将追加一个数字到一个文件名,如果该文件已经存在之前,我创建新的文件。这是用于客户端和服务器之间的文件传输。
例如,如果客户端发送一个文件名为“Example.txt”,但服务器已经有一个名为“Example.txt”的文件,我想将文件名更改为“Example-1.txt”,如果已经存在,则将数字增加到“Example-2.txt”,并继续下去,直到文件名不存在。
如果文件名是“Ex.x.x.x.x.x.txt”或“Ex.--1.txt”,并将其分别更改为“Ex.x.x.x.x.x-1.txt”和“Ex.--2.txt”,它也应该起作用。
我试过使用strtok()方法,但代码变得又长又乱。我试着在网上搜索,我没有找到任何关于这个问题。我觉得我在试图重新发明轮子,当有一个更好的方法来解决这个问题。
编辑-这是我想出来的。一个问题,我可以看到它是在一定程度上,当数字追加太大,将有一个segfault,因为我硬编码额外的内存分配给文件路径。

void check_if_file_exists(char **filepath, const char *filename, const char *directory)
{
    struct stat file_status;

    if (stat(*filepath, &file_status) == 0)
    {
        char *final_filepath, *new_filepath, *filename_extension;
        size_t filepath_size;
        int append;

        filepath_size = strlen(filename) + strlen(directory) + 64;
        append = 1;

        final_filepath = safe_malloc(filepath_size);
        new_filepath = safe_malloc(filepath_size);

        strcpy(new_filepath, directory);

        filename_extension = strrchr(filename, '.');

        strncat(new_filepath, filename, filename_extension - filename);
        strcat(new_filepath, "-%d");
        if (filename_extension != NULL)
        {
            strcat(new_filepath, filename_extension);
        }

        do
        {
            sprintf(final_filepath, new_filepath, append++);

        } while (stat(final_filepath, &file_status) == 0);

        *filepath = final_filepath;

        free(new_filepath);
    }
}

void *safe_malloc(size_t size)
{
    void *ptr = malloc(size);

    if (!ptr && size > 0)
    {
        perror("Malloc failed\n");
        exit(EXIT_FAILURE);
    }

    return ptr;
}
eanckbw9

eanckbw91#

读者们...在DV'ing之前,请检查时间戳并编辑OP问题和答案的修订版本。问题中的代码出现在这个答案发布后的几个小时。(或者,继续DV,如果你必须的话。
这是一个可行的原型。

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

int nextName( char *cp ) {
    char *sufx = strrchr( cp, '.' );
    char *sp, hold[16] = {0}; // enough for ".txt" or ".html"

    if( sufx )
        strcpy( hold, sp = sufx );
    else
        sp = cp + strlen( cp );

    int i = 0;

    do {
        struct stat sbuf;
        if( stat( cp, &sbuf ) != 0 && errno == ENOENT )
            return 1;

printf( "%s exists... Moving on\n", cp ); // debugging

        sprintf( sp, "-%02d%s ", i, hold );
    } while( ++i < 100 );

    return 0;
}

int main( void ) {
    char str[ 32 ] = "Example.txt";

    puts( str );
    if( !nextName( str ) ) {
        /* Handle case where no higher version number is possible */
    }
    puts( str );

    return 0;
}

在当前目录中创建两个文件,“Example.txt”和“Example-00.txt”。这将检测它们的存在并修改文件名,直到它发现“Example-01.txt”当前不存在。等等......
即使文件名没有扩展名,这也应该起作用。
例如:“foobar”和“foobar-01”.
注意:包含所需路径的缓冲区必须更大,以便额外的3个字符可以“添加/添加”到文件名。
如果多个进程可能正在向同一个目录写入数据,则存在一个固有的竞争条件。
(You可以简单地将其更改为使用每个文件的000->999版本。适应您的需求)。

编辑:

考虑到路径可能是“this.dir/filename”,上述需要通过以下方式进行改进:

/* Scan right to left examining only the filename part of a path. */
char *fndExt( char *cp ) {
    char *p = cp + strlen(cp) - 1;
    for( ; p >= cp && *p != '/' && *p != '\\'; p-- )
        if( *p == '.' )
            return p;
    return NULL;
}

int nextName( char *cp ) {
    char *sp = fndExt( cp, '.' );
    char hold[16] = {0}; // enough for ".txt" or ".html"

    if( sp )
        strcpy( hold, sp );
    else
        sp = cp + strlen( cp );

    int i = 0;

    do {
        /* same as above */

可能需要一个更大的hold[]缓冲区来处理从名称结尾开始超过30个字符的超长文件名。或者,findExt()可以修改为只查找'.'文件名末尾的4-5个字符,并假定这是文件的扩展名。这在很大程度上取决于背景。名为“巴先生”的文件是一个带扩展名的名字吗?

yb3bgrhw

yb3bgrhw2#

以下是解决这个问题的一种方法:

#ifdef __linux__ 
    #include <unistd.h>
    #define FILE_EXIST(name)  (access((name),0) != -1)
#else
    #include  <io.h> 
    #define FILE_EXIST(name)  (_access((name),0) != -1)
#endif

char szOutFileName[100] = "MYFILE.txt";
int tries = 0;

    /* Where FILE_EXIST(char *name) is some method that tells if a filename exists or not.
    ** (Many ways to do).*/
    while(FILE_EXIST(szOutFileName)) /* Loop breaks when we achieve a unique name...*/
        sprintf(szOutFileName, "MYFILE%d.txt", tries++); /* tweak name with increment*/

相关问题