我正在使用 Curl 从互联网下载文件。如果文件很大,通过使用 Range 标头,我将其分成 3 个块,然后分别下载它们,从而与同一 URL 建立多个连接。现在的问题是,我如何将这 3 个不同的块重新连接到一个大文件中?在互联网上搜索我发现的所有内容都是使用 fgetc、fgets 等将数据解释为文本文件来合并文本文件。但我的文件主要是视频文件或大 iso 文件,因此是二进制数据。我查看了 fwrite 但我怎么知道哪个大小是一个元素?这只是二进制数据。我很困惑。 写入各个块的 Curl 例程如下:
size_t write_data(void *ptr, size_t sz, size_t nmemb, FILE *stream) { size_t written = fwrite(ptr, sz, nmemb, stream); return written; }
假设我下载了这 3 个块,filepath1.x、filepath2.x、filepath3.x,我如何将它们合并到 output.mp4 中?
既然你无论如何都在使用 shell 实用程序,那么最简单的方法就是使用
cat
。 cat file1.x file2.x file3.x > file.x
。
fopen
但切换为读取二进制文件。文本与二进制只是 Windows 上的一个问题。 POSIX 系统(Unix 和 MacOS)没有区别。
可以选择指定文件访问模式标志“b”以二进制模式打开文件。该标志对 POSIX 系统没有影响,但在 Windows 上它会禁用 ' ' 和 '\x1A'。
如果这只是一个小实用程序,请打印到标准输出并使用 shell 管道将输出重定向到文件。就像
cat
一样。
我们通过分配固定缓冲区来读取每个文件,并在该缓冲区中读取和写入块。我喜欢使用
BUFSIZ
常量,因为它可能与系统的块大小相同,这使得读取更加高效。 4096 也是一个不错的值,4k 是常见的块大小。
fread
和 fwrite
是奇数。我们需要告诉他们读取 X 个 Y 大小的对象,而不是仅仅告诉他们要读取多少。这是“面向记录的文件系统”的延续,当您读取固定大小的对象列表时最有用。由于 C 字符串是 1 字节字符的数组,因此我们要读取 1 字节 N 次。
fread
返回读取的对象数量。我们正在读取 1 字节对象,因此这相当于字节数。我们将该金额写为
fwrite
。如果 BUFSIZ 是 4096 字节,但文件只有 50 字节,我们只会写入 50 字节,而不是 50 字节加上 4046 字节的垃圾。#include <stdio.h>
#include <string.h>
#include<unistd.h>
#include <errno.h>
int main(int argc, char *argv[]) {
// Allocate a buffer for reading.
char buf[BUFSIZ];
// Or FILE *output = fopen(output_file, "wb")
FILE *output = stdout;
// Iterate through the filenames given on the command line.
for( int i = 1; argv[i] != NULL; i++ ) {
// Open the file for binary reading.
char *filename = argv[i];
FILE *f = fopen(filename, "rb");
if( f == NULL ) {
fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno));
}
// Read a BUFSIZ chunk, write it to the output.
size_t bytes_read;
while( (bytes_read = fread(buf, 1, sizeof(buf), f)) > 0 ) {
fwrite(buf, 1, bytes_read, output);
}
// Close the input file.
fclose(f);
}
if( output != stdout ) {
fclose(output);
}
}