如何更改文件扩展名

问题描述 投票:0回答:4

有类似的问题,但我的问题更具体一些。当我使用 RLE 算法进行编码时,我有一个 C 代码,它接受 file.txt 并返回 file.txt.rle 。我以同样的方式对其进行解码,并希望从 file.txt.rle 写入并返回 file.txt。以下代码是我从 file.txt 转到 file.txt.rle 时使用的代码:

char name[NAME_SIZE];
if(sprintf(name, "%s.rle", argv[1]) >= sizeof(name)){
    fprintf(stderr, "Destination file name is too long\n");
}
while((o_fp = fopen(name, "wb")) == NULL){
    fprintf(stderr, "Can't create the file to be written\n");
      exit(1);
}

如何在解码时将扩展名从 file.txt.rle 更改为 file.txt?完整的代码没有帮助,因为我将在解码编码文件的代码中使用它。

注意:给定的文件始终为 .txt.rle 格式,返回的文件应始终将其转换为 .txt。

c
4个回答
0
投票

您可以简单地执行此操作:

  • strrchr
    查找字符串中最后一个句点在哪里,
  • strlen
    /
    malloc
    分配内存来存储新名称,
  • sprintf
    创建新名称。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/* this function will create a new name, replacing the existing extension
   by the given one.
   returned value should be `free()` after usage

   /!\ warning: 
        * validity of parameters is not tested
        * return of strdup and malloc are not tested.
   */
char *replace_ext(const char *org, const char *new_ext)
{
    char *ext;

    /* copy the original file */
    char *tmp = strdup(org);

    /* find last period in name */
    ext = strrchr(tmp , '.');

    /* if found, replace period with '\0', thus, we have a shorter string */
    if (ext) { *ext = '\0'; }

    /* compute the new name size: size of name w/o ext + size of ext + 1 
       for the final '\0' */
    size_t new_size = strlen(tmp) + strlen(new_ext) + 1;

    /* allocate memory for new name*/
    char *new_name = malloc(new_size);

    /* concatenate the two string */
    sprintf(new_name, "%s%s", tmp, new_ext);

    /* free tmp memory */
    free(tmp);

    /* return the new name */
    return new_name;
}

int main(void)
{
    int i;
    char *tests[] = { "test.ext", "test.two.ext", "test_no_ext", NULL};

    for (i = 0; tests[i]; ++i)
    {
        char *new_name = replace_ext(tests[i], ".foo");
        printf("%s --> %s\n", tests[i], new_name);
        free(new_name);
    }

    return 0;
}

0
投票

这是一个实现。 这里的魔法是由

change_file_name(org, dest, size, ext)
执行的,它检查名称 org 是否以 ext 结尾,在这种情况下,将名称复制到该点。

希望这有帮助。

 /* Changes the name of the sys input file. */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>


bool change_file_name(const char * org, char * dest, size_t max_length, const char * file_ext)
{
    bool toret = false;
    const size_t name_length = strlen( org );
    const size_t ext_length = strlen( file_ext );
    const size_t new_name_size = name_length - ext_length;

    if ( name_length > ext_length
      && name_length < max_length
      && strcmp( org + new_name_size, file_ext ) == 0 )
    {
        strncpy( dest, org, name_length - ext_length );
        *( dest + new_name_size ) = 0;
        toret = true;
    }

    return toret;
}

void convert_file(const char * org, const char * dest)
{
    printf( "Processing file '%s' into '%s'\n", org, dest );
}

int main(int argc, char *argv[])
{
    const int NAME_SIZE = 1024;
    const char * rle_ext = ".rle";
    char new_name[NAME_SIZE];
    int toret = EXIT_SUCCESS;

    if ( argc == 2 ) {
        if ( change_file_name( argv[ 1 ], new_name, NAME_SIZE, rle_ext ) ) {
            printf( "The new name is: '%s'\n", new_name );
            convert_file( argv[ 1 ], new_name );
        } else {
            toret = EXIT_FAILURE;
            fprintf( stderr,
                     "Name results empty, is not ending in '%s' or is too large: '%s'\n",
                     rle_ext,
                     argv[ 1 ] );
        }
    } else {
        toret = EXIT_FAILURE;
        fprintf( stderr, "Usage: %s <file name>.txt.rle\n", argv[ 0 ] );
    }

    return toret;
}

0
投票

您可以使用 strsep (strtok 的后继者)来标记您的输入文件名并复制您感兴趣的部分并丢弃其余部分。

如果您的输入文件名始终采用 file.txt.rle 形式,则可以使用以下代码。

char *name = malloc(sizeof(char) * NAME_SIZE);
if(sprintf(name, "%s.rle", argv[1]) >= sizeof(name)){
    fprintf(stderr, "Destination file name is too long\n");
}

char *token = NULL;
char *newfilename = malloc(sizeof(char) * (NAME_SIZE-4)); //strlen(".rle") = 4
uint8_t offset = 0;
memset(newfilename, 0, (NAME_SIZE-4));

while ((token = strsep(&name, ".")) != NULL) {
    if(strcmp(token, "rle") == 0) {
        break;
    }
    strncpy(newfilename+offset, token, strlen(token));
    offset += strlen(token);
    newfilename[offset] = '.';
    offset += 1;
}
newfilename[strlen(newfilename)-1] = '\0';

0
投票

我可能会使用独立函数来完成类似的事情。 在 to_rle() 的情况下,我会避免需要释放的 malloc 指针。 特别是因为它是一个函数调用。降低复杂性,保持简单,使用堆栈。

我还允许新的“ext”参数带或不带“.”

要获取原始数据,请传递相同的“ext”参数。 如果它已被删除,只需将文件名原封不动地恢复即可。 否则,删除添加的扩展。

这是特定情况的,但只需很少的想象力,您就可以使用相同的技术来更改正常的文件扩展名。一句建议:并非所有扩展名都是三个字符,因此您仍然需要一个缓冲区,以防万一。

使用示例:

char *p="filename.txt";

添加扩展名:

p = to_rle(p,"rle");
printf("%s\n",p);

结果:

文件名.txt.rle

现在,删除“.rle”:

p = to_txt(p,"rle");
printf("%s\n",p);

结果:

文件名.txt

char *to_rle(char *str, char *ext)
{
  static char buf[512]={0};  //use stack, avoid malloc

  strcpy(buf,str);           //fname to larger buffer            

  if((strstr(ext,"."))==NULL)//accept ext arg with or without '.'
      strcat(buf,".");

  strcat(buf,ext);           //append extension

  return buf;  

}


char *to_txt(char *str, char *ext)
{
  char *p,*s; 

  if((strstr(str,ext))==NULL) //'.rle' already removed
      return str;

  p=s=str;                    //point to str

  p+=strlen(str);             //push p to EOS

  while((*p!='.')&&(p>s))     //backup to dot
          p--;
  *p=0;                       //terminate 

   return str;
}
© www.soinside.com 2019 - 2024. All rights reserved.