我想要做的是下载一个包含多个目录的.tar文件,每个目录包含2个文件。问题是我找不到一种方法来读取tar文件而不实际提取文件(使用tar
)。
完美的解决方案就像:
#include <easytar>
Tarfile tar("somefile.tar");
std::string currentFile, currentFileName;
for(int i=0; i<tar.size(); i++){
file = tar.getFileText(i);
currentFileName = tar.getFileName(i);
// do stuff with it
}
我可能不得不自己写这个,但任何想法都会受到赞赏..
答案 0 :(得分:31)
经过一番工作后,我自己想通了。 tar file spec实际上告诉了你需要知道的一切。
首先,每个文件都以512字节的标头开头,因此您可以使用char [512]或char *来表示它,指向较大字符数组中的某个位置(如果您将整个文件加载到一个数组中例子)。
标题如下所示:
location size field
0 100 File name
100 8 File mode
108 8 Owner's numeric user ID
116 8 Group's numeric user ID
124 12 File size in bytes
136 12 Last modification time in numeric Unix time format
148 8 Checksum for header block
156 1 Link indicator (file type)
157 100 Name of linked file
因此,如果您需要文件名,请使用string filename(buffer[0], 100);
抓住它。文件名为空填充,因此您可以检查以确保至少有一个null,如果您想节省空间,则不要使用大小。
现在我们想知道它是文件还是文件夹。 “链接指示符”字段包含此信息,因此:
// Note that we're comparing to ascii numbers, not ints
switch(buffer[156]){
case '0': // intentionally dropping through
case '\0':
// normal file
break;
case '1':
// hard link
break;
case '2':
// symbolic link
break;
case '3':
// device file/special file
break;
case '4':
// block device
break;
case '5':
// directory
break;
case '6':
// named pipe
break;
}
此时,我们已经掌握了有关目录的所有信息,但我们还需要一些普通文件:实际文件内容。
文件的长度可以用两种不同的方式存储,可以是0或空格填充的以空字符结尾的八进制字符串,也可以是“通过设置高位比特表示的base-256编码”。数字字段的最左边的字节“。
数字值使用ASCII数字以八进制数编码,前导零。由于历史原因,应使用最终的NUL或空格字符。因此,尽管保留了12个字节用于存储文件大小,但是只能存储11个八进制数字。这使归档文件的最大文件大小为8千兆字节。为了克服这个限制,2001年的star引入了base-256编码,通过设置数字字段最左边字节的高位来指示。 GNU-tar和BSD-tar遵循了这个想法。此外,1988年第一个POSIX标准之前的tar版本用空格而不是零填充值。
以下是如何读取八进制格式,但我没有为base-256版本编写代码:
// in one function
int size_of_file = octal_string_to_int(&buffer[124], 11);
// elsewhere
int octal_string_to_int(char *current_char, unsigned int size){
unsigned int output = 0;
while(size > 0){
output = output * 8 + *current_char - '0';
current_char++;
size--;
}
return output;
}
好的,现在我们拥有除实际文件内容之外的所有内容。我们所要做的就是从tar文件中获取下一个size
字节的数据,我们将获得文件内容:
// Get to the next block after the header ends
location += 512;
file_contents = new char[size];
memcpy(file_contents, &buffer[location], size);
// Go to the next block by rounding up to 512
// This isn't necessarily the most efficient way to do this,
// but it's the most obvious.
location += (int)ceil(size / 512.0)
答案 1 :(得分:12)
你看过libtar吗?
来自fink包信息:
libtar-1.2-1:Tar文件操作API libtar是一个用于操作POSIX tar文件的C库。它处理 向tar存档添加文件和从tar存档中提取文件。 libtar提供以下功能:
*灵活的API - 您可以操作单个文件或只是 立即提取整个档案 *允许用户指定的read()和write()函数,例如 zlib的gzread()和gzwrite() *支持POSIX 1003.1-1990和GNU tar文件格式。
不是c ++ 本身,但你可以很容易地链接到c ......
答案 2 :(得分:4)
libarchive可以是解析tarball的开源库。 Libarchive可以从存档文件中读取每个文件而无需提取,也可以写入数据以形成新的存档文件。