【问题标题】:How to remove a header from file without creating additional temporary files?如何在不创建额外临时文件的情况下从文件中删除标题?
【发布时间】:2016-11-21 16:17:27
【问题描述】:

我正在为运行 Linux 的嵌入式系统开发一个应用程序。

就我而言,我有一个相当大的文件(与系统的能力相比)作为输入。该文件有一个小标题,其大小仅为几百字节。在我的应用程序中,我需要从文件中删除该标头,以便该文件没有标头并且仅包含相关数据。通常,我会实现如下(伪代码):

char *input_file  = "big_input.bin";
char *tmp_file1 = "header.bin";
char *tmp_file2 = "data.bin";
/* Copy the content of header from input file to tmp_file1 */ 
_copy_header(tmp_file1, input_file); 
/* Copy the data from input file to tmp_file2 */ 
_copy_data(tmp_file2, input_file);
/* Rename temp file to input file */
unlink(input_file);
rename(tmp_file2, input_file);

这种方法的问题在于它创建了一个临时文件tmp_file2,其大小几乎与输入文件一样大(因为标题非常小)。在我的系统中,所有内容都存储在 RAM 上,这是非常有限的。创建大的临时文件会导致内存不足错误。

那么我怎样才能避免创建一个大的临时文件呢?

【问题讨论】:

  • 移动而不是复制。
  • 映射它。记住它。截断它。如果没有足够的内存来映射整个文件,请分段进行。

标签: c linux file


【解决方案1】:

打开同一个文件两次,一次读,一次写。

寻找头部后面的读指针。

从读指针读取并写入写指针。

确保你一次读写的大小不大于标题。

在文件末尾剪掉标题的大小。

【讨论】:

    【解决方案2】:

    假设您事先知道标头的确切大小,应该这样做:

    #define HEADER_SIZE 128
    
    // size the buffer as appropriate for you RAM limits
    char buffer[ 4096 ];
    int fd = open( filename, O_RDWR );
    size_t totalBytes = 0UL;
    for ( ;; )
    {
        ssize_t bytes_read = pread( fd, buffer,
            sizeof( buffer ), totalBytes + HEADER_SIZE );
        if ( bytes_read <= 0L )
        {
            break;
        }
        pwrite( fd, buffer, bytes_read, totalBytes );
        total_bytes += bytes_read;
    }
    
    ftruncate( fd, total_bytes );
    
    close( fd );
    

    您需要添加正确的头文件和一些错误检查。

    【讨论】:

      【解决方案3】:

      在你的情况下,你可以

      • 以读写方式打开文件
      • 从您的偏移量中逐个字符地读取并写入开头,循环直到文件结尾(听起来不太理想,但您在 RAM 驱动器上,这很简单。更快的方法意味着读取更多字节,也许更多实现起来很复杂,并且必须测量速度增益)
      • 最后,您可以使用truncateftruncate 截断文件,如下所述:How to truncate a file in C?

      【讨论】:

      • 逐个字符读取可能不是最有效的方法。
      • 来自可以工作的 RAM 系统。在这个问题中,内存大小至关重要。
      • 头部很小,所以我想他可以有那个长度的读取缓冲区。
      • 或者你可以分配一个“大小合理”的临时缓冲区(比如一页长),一次读写那么多字节。另一种方法(如果支持虚拟内存)是将文件mmap 移动到虚拟地址,使用memmove 移动数据,然后使用munmap 它。
      • 标头很小,我提前知道它的大小。因此,我可以按照@MichaelWalz 的建议读取具有标头长度的缓冲区。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-03-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多