问题
Does anyone know of any library/code that will enable me to encode and decode .tar formatted data - that I can use in my iPhone project (preferably cocoa)
Thanks in advance
Craig
UPDATE: I've taken a look at the suggested libraries and come to the conclusion that they are making waaaay to much of the problem - so I'm developing the codec myself - it's only a 512byte ASCII header after all - how hard can it be :-)
回答1:
The best library I've found is libarchive
. It is well-designed, well-documented, and fast.
I just created a repository on GitHub that has the tools to build libarchive
and libbz2
as static libraries for iOS 4.2+. (It should be possible to use it to target 3.x, too.)
http://github.com/davepeck/iOS-libarchive/
Others have pointed out that libarchive
is included in the SDK. This is not quite true. The binary libarchive.2.dylib
is included, but the headers are not. The same applies to libbz2
(but, oddly, not to libz
.) This means that libarchive
is considered a private API -- in other words, you can't use it if you intend to ship on the App Store. Hence my repository.
回答2:
In fact, libarchive.dylib is included in the iPhone SDK. You just have to add it. The problem is that somehow Apple did not include the header file archive.h. However, first, you do not need the header files if you know for sure the functions you are going to call exist (though the compiler will whine), second, if you do not want the compiler to complain, you can download the header file for libarchive 2.6 and include it in your program ...
If you want to know know to use libarchive, download its source from the web and study the example given (especially minitar). It is really very straightforward.
回答3:
You might try libxad. This is the library that The Unarchiver, a Mac app, uses.
回答4:
Even better link: http://code.google.com/p/libarchive/downloads/detail?name=libarchive-2.6.2.tar.gz&can=2&q=
Version 2.6.2 is included in the iOS 4.0 and 4.1 SDK's. It's not present in 3.2 (or earlier I assume).
If you download that, run ./configure --prefix=$HOME && make && make install
and you'll find the two header files placed in $HOME/include
回答5:
For libarchive, it works out of the box by just adding "libarchive" to your framework list, but the header is missing. You can copy the headers from the libarchive source. Or if you want to keep it simple, try this:
////////////////////////////////////////////////////////////////////////////////////////////////////
// LibArchive "Header" - ios is missing this header. go figure.
////////////////////////////////////////////////////////////////////////////////////////////////////
// from ftp://ftp8.freebsd.org/pub/FreeBSD/FreeBSD-current/src/lib/libarchive/archive.h.in
#define ARCHIVE_EOF 1 /* Found end of archive. */
#define ARCHIVE_OK 0 /* Operation was successful. */
#define ARCHIVE_RETRY (-10) /* Retry might succeed. */
#define ARCHIVE_WARN (-20) /* Partial success. */
#define ARCHIVE_FAILED (-25) /* Current operation cannot complete. */
#define ARCHIVE_FATAL (-30) /* No more operations are possible. */
struct archive;
struct archive_entry;
int archive_version_number(void);
const char * archive_version_string(void);
int archive_version_stamp(void);
const char * archive_version(void);
int archive_api_version(void);
int archive_api_feature(void);
typedef ssize_t archive_read_callback(struct archive *, void *_client_data, const void **_buffer);
//typedef ssize_t archive_skip_callback(struct archive *, void *_client_data, size_t request);
typedef off_t archive_skip_callback(struct archive *, void *_client_data, off_t request);
typedef ssize_t archive_write_callback(struct archive *, void *_client_data, const void *_buffer, size_t _length);
typedef int archive_open_callback(struct archive *, void *_client_data);
typedef int archive_close_callback(struct archive *, void *_client_data);
struct archive *archive_read_new(void);
int archive_read_support_compression_all(struct archive *);
int archive_read_support_compression_bzip2(struct archive *);
int archive_read_support_compression_compress(struct archive *);
int archive_read_support_compression_gzip(struct archive *);
int archive_read_support_compression_none(struct archive *);
int archive_read_support_compression_program(struct archive *, const char *command);
int archive_read_support_format_all(struct archive *);
int archive_read_support_format_ar(struct archive *);
int archive_read_support_format_cpio(struct archive *);
int archive_read_support_format_empty(struct archive *);
int archive_read_support_format_gnutar(struct archive *);
int archive_read_support_format_iso9660(struct archive *);
int archive_read_support_format_mtree(struct archive *);
int archive_read_support_format_tar(struct archive *);
int archive_read_support_format_zip(struct archive *);
int archive_read_open(struct archive *, void *_client_data, archive_open_callback *, archive_read_callback *, archive_close_callback *);
int archive_read_open2(struct archive *, void *_client_data, archive_open_callback *, archive_read_callback *, archive_skip_callback *, archive_close_callback *);
int archive_read_open_filename(struct archive *, const char *_filename, size_t _block_size);
int archive_read_open_file(struct archive *, const char *_filename, size_t _block_size);
int archive_read_open_memory(struct archive *, void * buff, size_t size);
int archive_read_open_memory2(struct archive *a, void *buff, size_t size, size_t read_size);
int archive_read_open_fd(struct archive *, int _fd, size_t _block_size);
int archive_read_open_FILE(struct archive *, FILE *_file);
int archive_read_next_header(struct archive *, struct archive_entry **);
int64_t archive_read_header_position(struct archive *);
ssize_t archive_read_data(struct archive *, void *, size_t);
int archive_read_data_block(struct archive *a, const void **buff, size_t *size, off_t *offset);
int archive_read_data_skip(struct archive *);
int archive_read_data_into_buffer(struct archive *, void *buffer, ssize_t len);
int archive_read_data_into_fd(struct archive *, int fd);
int archive_read_extract(struct archive *, struct archive_entry *, int flags);
void archive_read_extract_set_progress_callback(struct archive *, void (*_progress_func)(void *), void *_user_data);
void archive_read_extract_set_skip_file(struct archive *, dev_t, ino_t);
int archive_read_close(struct archive *);
int archive_read_finish(struct archive *);
//void archive_read_finish(struct archive *);
struct archive *archive_write_new(void);
int archive_write_set_bytes_per_block(struct archive *, int bytes_per_block);
int archive_write_get_bytes_per_block(struct archive *);
int archive_write_set_bytes_in_last_block(struct archive *, int bytes_in_last_block);
int archive_write_get_bytes_in_last_block(struct archive *);
int archive_write_set_skip_file(struct archive *, dev_t, ino_t);
int archive_write_set_compression_bzip2(struct archive *);
int archive_write_set_compression_compress(struct archive *);
int archive_write_set_compression_gzip(struct archive *);
int archive_write_set_compression_none(struct archive *);
int archive_write_set_compression_program(struct archive *, const char *cmd);
int archive_write_set_format(struct archive *, int format_code);
int archive_write_set_format_by_name(struct archive *, const char *name);
int archive_write_set_format_ar_bsd(struct archive *);
int archive_write_set_format_ar_svr4(struct archive *);
int archive_write_set_format_cpio(struct archive *);
int archive_write_set_format_cpio_newc(struct archive *);
int archive_write_set_format_pax(struct archive *);
int archive_write_set_format_pax_restricted(struct archive *);
int archive_write_set_format_shar(struct archive *);
int archive_write_set_format_shar_dump(struct archive *);
int archive_write_set_format_ustar(struct archive *);
int archive_write_open(struct archive *, void *, archive_open_callback *, archive_write_callback *, archive_close_callback *);
int archive_write_open_fd(struct archive *, int _fd);
int archive_write_open_filename(struct archive *, const char *_file);
int archive_write_open_file(struct archive *, const char *_file);
int archive_write_open_FILE(struct archive *, FILE *);
int archive_write_open_memory(struct archive *, void *_buffer, size_t _buffSize, size_t *_used);
int archive_write_header(struct archive *, struct archive_entry *);
ssize_t archive_write_data(struct archive *, const void *, size_t);
//int archive_write_data(struct archive *, const void *, size_t);
ssize_t archive_write_data_block(struct archive *, const void *, size_t, off_t);
int archive_write_finish_entry(struct archive *);
int archive_write_close(struct archive *);
int archive_write_finish(struct archive *);
//void archive_write_finish(struct archive *);
struct archive *archive_write_disk_new(void);
int archive_write_disk_set_skip_file(struct archive *, dev_t, ino_t);
int archive_write_disk_set_options(struct archive *, int flags);
int archive_write_disk_set_standard_lookup(struct archive *);
int archive_write_disk_set_group_lookup(struct archive *, void *private_data, gid_t (*loookup)(void *, const char *gname, gid_t gid), void (*cleanup)(void *));
int archive_write_disk_set_user_lookup(struct archive *, void *private_data, uid_t (*)(void *, const char *uname, uid_t uid), void (*cleanup)(void *));
int64_t archive_position_compressed(struct archive *);
int64_t archive_position_uncompressed(struct archive *);
const char * archive_compression_name(struct archive *);
int archive_compression(struct archive *);
int archive_errno(struct archive *);
const char * archive_error_string(struct archive *);
const char * archive_format_name(struct archive *);
int archive_format(struct archive *);
void archive_clear_error(struct archive *);
void archive_set_error(struct archive *, int _err, const char *fmt, ...);
void archive_copy_error(struct archive *dest, struct archive *src);
// From ftp://ftp8.freebsd.org/pub/FreeBSD/FreeBSD-current/src/lib/libarchive/archive_entry.h
time_t archive_entry_atime(struct archive_entry *);
long archive_entry_atime_nsec(struct archive_entry *);
time_t archive_entry_ctime(struct archive_entry *);
long archive_entry_ctime_nsec(struct archive_entry *);
dev_t archive_entry_dev(struct archive_entry *);
dev_t archive_entry_devmajor(struct archive_entry *);
dev_t archive_entry_devminor(struct archive_entry *);
mode_t archive_entry_filetype(struct archive_entry *);
void archive_entry_fflags(struct archive_entry *, unsigned long *set, unsigned long *clear);
const char* archive_entry_fflags_text(struct archive_entry *);
gid_t archive_entry_gid(struct archive_entry *);
const char* archive_entry_gname(struct archive_entry *);
const wchar_t* archive_entry_gname_w(struct archive_entry *);
const char* archive_entry_hardlink(struct archive_entry *);
const wchar_t* archive_entry_hardlink_w(struct archive_entry *);
ino_t archive_entry_ino(struct archive_entry *);
mode_t archive_entry_mode(struct archive_entry *);
time_t archive_entry_mtime(struct archive_entry *);
long archive_entry_mtime_nsec(struct archive_entry *);
unsigned int archive_entry_nlink(struct archive_entry *);
const char* archive_entry_pathname(struct archive_entry *);
const wchar_t* archive_entry_pathname_w(struct archive_entry *);
dev_t archive_entry_rdev(struct archive_entry *);
dev_t archive_entry_rdevmajor(struct archive_entry *);
dev_t archive_entry_rdevminor(struct archive_entry *);
int64_t archive_entry_size(struct archive_entry *);
const char* archive_entry_strmode(struct archive_entry *);
const char* archive_entry_symlink(struct archive_entry *);
const wchar_t* archive_entry_symlink_w(struct archive_entry *);
uid_t archive_entry_uid(struct archive_entry *);
const char* archive_entry_uname(struct archive_entry *);
const wchar_t* archive_entry_uname_w(struct archive_entry *);
I only cared about reading so I didn't bother with some of the archive_entry.h mutation functions. Also, a few of the methods are commented out. Those are the alternates for different versions that get #ifdef'd out. Good luck and good bug hunting!
Here's a sample of using it to unpack an archive to a directory on ios:
+ (void)unpackArchive: (NSData*) archiveData
{
int r;
struct archive* a;
struct archive_entry *entry;
const char *entry_path;
NSString *baseDir = [self baseDir];
NSFileHandle* file;
NSError* error;
NSDictionary* result = @{};
NSLog(@"Unpacking %d byte static assets tarball into %@", [archiveData length], baseDir);
if (![[NSFileManager defaultManager] createDirectoryAtPath:baseDir
withIntermediateDirectories:YES
attributes:nil
error:&error])
{
NSLog(@"Create directory error: %@", error);
}
a = archive_read_new();
archive_read_support_format_gnutar(a);
archive_read_support_format_tar(a);
archive_read_support_compression_gzip(a);
r = archive_read_open_memory(a, (void*)[archiveData bytes], [archiveData length]);
if (r != ARCHIVE_OK) {
NSLog(@"ERROR[%d] in archive_read_open_file(): %s", r, archive_error_string(a));
return;
}
for (;;) {
r = archive_read_next_header(a, &entry);
if (r == ARCHIVE_EOF) {
break;
}
if (r != ARCHIVE_OK) {
NSLog(@"ERROR[%d] in archive_read_next_header(): %s", r, archive_error_string(a));
return;
}
entry_path = archive_entry_pathname(entry);
NSString* path = [baseDir stringByAppendingPathComponent: [NSString stringWithUTF8String: entry_path]];
NSLog(@"Tarball Entry: %s", entry_path);
// Create the file and blank it out
[[NSFileManager defaultManager] createFileAtPath: path contents:[[NSMutableData alloc] init] attributes:nil];
// Actually write the file
file = [NSFileHandle fileHandleForWritingAtPath:path];
r = archive_read_data_into_fd(a, [file fileDescriptor]);
if (r != ARCHIVE_OK) {
NSLog(@"ERROR[%d] in archive_read_data_into_fd(): %s", r, archive_error_string(a));
return;
}
[file closeFile];
}
r = archive_read_close(a);
if (r != ARCHIVE_OK) {
NSLog(@"ERROR[%d] in archive_read_close(): %s", r, archive_error_string(a));
return;
}
}
--- Dave
回答6:
libarchive comes preinstalled on iOS.
回答7:
There seem to be two more modern libraries, both of them available as Cocoapods:
- NVHTarGzip: Supports progress reporting, and has both sync and async methods. Doesn't support tar writing.
- tarkit: Supports tar writing, but doesn't have the other nice features.
Both of them are very similar, as they are both based on Light-Untar-for-iOS.
来源:https://stackoverflow.com/questions/1204912/tar-encode-decode-library-for-iphone-ideally-cocoa