【问题标题】:ext4: Splitting and Concatenating File in situext4:原位拆分和连接文件
【发布时间】:2018-01-05 08:06:42
【问题描述】:

假设我在一个大磁盘上有一个大文件,这个文件几乎完全填满了磁盘。例如10TB 磁盘,差不多 10TB 文件,比如 3GB 是免费的。还有,我没有其他的

我想将该文件分成 N 份,但对于简单的情况,分成两半是可以的。由于所需的解决方案可能是特定于 FS 的,因此我使用的是 ext4 文件系统。

我知道https://www.gnu.org/software/coreutils/manual/coreutils.html#split-invocation

显然,我在设备上没有足够的可用空间来通过复制创建拆分。

是否有可能以某种方式将文件 A(~10TB)拆分为两个文件 B 和 C,因此这些(B 和 C)只是对文件 A 原始数据的新“引用”。

即B具有相同的起点(A_start = B_start),但长度较小,而C,从B_start+B_length开始,C_length = A_length-B_length。

操作后文件 A 可能存在也可能不存在于 FS 中。 另外,如果只有在某些扇区/块边界(即只有 4096 字节的光栅)才有可能存在这样的约束/限制,我会很好。

同样的问题适用于相反的情况:

在一个 10TB 的硬盘上拥有两个几乎 5TB 的文件:仅通过调整“inode 引用”将它们连接成一个接近 10TB 大小的文件。

对不起,如果命名不是那么精确,我希望我想达到什么目的很清楚。

【问题讨论】:

    标签: file split concatenation ext4


    【解决方案1】:

    首先,目前没有保证可移植的方式来做你想做的事 - 任何解决方案都将是特定于平台的,因为做你想做的事需要你的底层文件系统支持稀疏文件。

    如果底层文件系统创建稀疏文件(为清楚起见,省略了正确的标题和错误检查),这样的代码可以将文件分成两半:

    // 1MB chunks (use a power of two)
    #define CHUNKSIZE ( 1024L * 1024L )
    int main( int argc, char **argv )
    {
        int origFD = open( argv[ 1 ], O_RDWR );
        int newFD = open( argv[ 2 ], O_WRONLY | O_CREAT | O_TRUNC, 0644 );
    
        // get the size of the input file
        struct stat sb;
        fstat( origFD, &sb );
    
        // get a CHUNKSIZE-aligned offset near the middle of the file
        off_t startOffset = ( sb.st_size / 2L ) & ~( CHUNKSIZE - 1L );
    
        // get the largest CHUNKSIZE-aligned offset in the file
        off_t readOffset = sb.st_size & ~( CHUNKSIZE - 1L );
    
        // might have to malloc() if it doesn't fit on the stack
        char *ioBuffer[ CHUNKSIZE ];
    
        while ( readOffset >= startOffset )
        {
            // write the data to the end of the file - the underlying
            // filesystem had better create a sparse file or this can
            // fill up the disk on the first pwrite() call
            ssize_t bytesRead = pread(
                origFD, ioBuffer, CHUNKSIZE, readOffset );
    
            ssize_t bytesWritten = pwrite(
                newFD, ioBuffer, byteRead, readOffset - startOffset );
    
            // cut the end off the input file - this had better free up
            // disk space
            ftruncate( origFD, readOffset );
            readOffset -= CHUNKSIZE;
        }
    
        free( ioBuffer );
        close( origFD );
        close( newFD );
        return( 0 );
    }
    

    还有其他方法。在 Solaris 系统上,您可以使用 use fcntl() with the F_FREESPC command,而在支持 FALLOC_FL_PUNCH_HOLE 的 Linux 系统上,您可以在将数据复制到另一个文件后使用 the fallocate() function 从文件中删除任意块。在这样的系统上,您不仅可以使用ftruncate() 切断原始文件的结尾。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-26
      • 2011-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多