概述
classTarFile(object):"""The TarFile Class provides an interface to tar archives."""debug= 0 #May be set from 0 (no msgs) to 3 (all msgs)
dereference= False #If true, add content of linked file to the
#tar file, else the link.
ignore_zeros= False #If true, skips empty or invalid blocks and
#continues processing.
errorlevel= 1 #If 0, fatal errors only appear in debug
#messages (if debug >= 0). If > 0, errors
#are passed to the caller as exceptions.
format= DEFAULT_FORMAT #The format to use when creating an archive.
encoding= ENCODING #Encoding for 8-bit character strings.
errors= None #Error handler for unicode conversion.
tarinfo= TarInfo #The default TarInfo class to use.
fileobject= ExFileObject #The default ExFileObject class to use.
def __init__(self, name=None, mode="r", fileobj=None, format=None,
tarinfo=None, dereference=None, ignore_zeros=None, encoding=None,
errors=None, pax_headers=None, debug=None, errorlevel=None):"""Open an (uncompressed) tar archive `name'. `mode' is either 'r' to
read from an existing archive, 'a' to append data to an existing
file or 'w' to create a new file overwriting an existing one. `mode'
defaults to 'r'.
If `fileobj' is given, it is used for reading or writing data. If it
can be determined, `mode' is overridden by `fileobj's mode.
`fileobj' is not closed, when TarFile is closed."""modes= {"r": "rb", "a": "r+b", "w": "wb"}if mode not inmodes:raise ValueError("mode must be 'r', 'a' or 'w'")
self.mode=mode
self._mode=modes[mode]if notfileobj:if self.mode == "a" and notos.path.exists(name):#Create nonexistent files in append mode.
self.mode = "w"self._mode= "wb"fileobj=bltn_open(name, self._mode)
self._extfileobj=Falseelse:if name is None and hasattr(fileobj, "name"):
name=fileobj.nameif hasattr(fileobj, "mode"):
self._mode=fileobj.mode
self._extfileobj=True
self.name= os.path.abspath(name) if name elseNone
self.fileobj=fileobj#Init attributes.
if format is notNone:
self.format=formatif tarinfo is notNone:
self.tarinfo=tarinfoif dereference is notNone:
self.dereference=dereferenceif ignore_zeros is notNone:
self.ignore_zeros=ignore_zerosif encoding is notNone:
self.encoding=encodingif errors is notNone:
self.errors=errorselif mode == "r":
self.errors= "utf-8"
else:
self.errors= "strict"
if pax_headers is not None and self.format ==PAX_FORMAT:
self.pax_headers=pax_headerselse:
self.pax_headers={}if debug is notNone:
self.debug=debugif errorlevel is notNone:
self.errorlevel=errorlevel#Init datastructures.
self.closed =False
self.members= [] #list of members as TarInfo objects
self._loaded = False #flag if all members have been read
self.offset =self.fileobj.tell()#current position in the archive file
self.inodes = {} #dictionary caching the inodes of
#archive members already added
try:if self.mode == "r":
self.firstmember=None
self.firstmember=self.next()if self.mode == "a":#Move to the end of the archive,
#before the first empty block.
whileTrue:
self.fileobj.seek(self.offset)try:
tarinfo=self.tarinfo.fromtarfile(self)
self.members.append(tarinfo)exceptEOFHeaderError:
self.fileobj.seek(self.offset)break
exceptHeaderError, e:raiseReadError(str(e))if self.mode in "aw":
self._loaded=Trueifself.pax_headers:
buf=self.tarinfo.create_pax_global_header(self.pax_headers.copy())
self.fileobj.write(buf)
self.offset+=len(buf)except:if notself._extfileobj:
self.fileobj.close()
self.closed=Trueraise
def_getposix(self):return self.format ==USTAR_FORMATdef_setposix(self, value):importwarnings
warnings.warn("use the format attribute instead", DeprecationWarning,2)ifvalue:
self.format=USTAR_FORMATelse:
self.format=GNU_FORMAT
posix=property(_getposix, _setposix)#--------------------------------------------------------------------------
#Below are the classmethods which act as alternate constructors to the
#TarFile class. The open() method is the only one that is needed for
#public use; it is the "super"-constructor and is able to select an
#adequate "sub"-constructor for a particular compression using the mapping
#from OPEN_METH.
# #This concept allows one to subclass TarFile without losing the comfort of
#the super-constructor. A sub-constructor is registered and made available
#by adding it to the mapping in OPEN_METH.
@classmethoddef open(cls, name=None, mode="r", fileobj=None, bufsize=RECORDSIZE, **kwargs):"""Open a tar archive for reading, writing or appending. Return
an appropriate TarFile class.
mode:
'r' or 'r:*' open for reading with transparent compression
'r:' open for reading exclusively uncompressed
'r:gz' open for reading with gzip compression
'r:bz2' open for reading with bzip2 compression
'a' or 'a:' open for appending, creating the file if necessary
'w' or 'w:' open for writing without compression
'w:gz' open for writing with gzip compression
'w:bz2' open for writing with bzip2 compression
'r|*' open a stream of tar blocks with transparent compression
'r|' open an uncompressed stream of tar blocks for reading
'r|gz' open a gzip compressed stream of tar blocks
'r|bz2' open a bzip2 compressed stream of tar blocks
'w|' open an uncompressed stream for writing
'w|gz' open a gzip compressed stream for writing
'w|bz2' open a bzip2 compressed stream for writing"""
if not name and notfileobj:raise ValueError("nothing to open")if mode in ("r", "r:*"):#Find out which *open() is appropriate for opening the file.
for comptype incls.OPEN_METH:
func=getattr(cls, cls.OPEN_METH[comptype])if fileobj is notNone:
saved_pos=fileobj.tell()try:return func(name, "r", fileobj, **kwargs)except(ReadError, CompressionError), e:if fileobj is notNone:
fileobj.seek(saved_pos)continue
raise ReadError("file could not be opened successfully")elif ":" inmode:
filemode, comptype= mode.split(":", 1)
filemode= filemode or "r"comptype= comptype or "tar"
#Select the *open() function according to
#given compression.
if comptype incls.OPEN_METH:
func=getattr(cls, cls.OPEN_METH[comptype])else:raise CompressionError("unknown compression type %r" %comptype)return func(name, filemode, fileobj, **kwargs)elif "|" inmode:
filemode, comptype= mode.split("|", 1)
filemode= filemode or "r"comptype= comptype or "tar"
if filemode not in ("r", "w"):raise ValueError("mode must be 'r' or 'w'")
stream=_Stream(name, filemode, comptype, fileobj, bufsize)try:
t= cls(name, filemode, stream, **kwargs)except:
stream.close()raiset._extfileobj=Falsereturntelif mode in ("a", "w"):return cls.taropen(name, mode, fileobj, **kwargs)raise ValueError("undiscernible mode")
@classmethoddef taropen(cls, name, mode="r", fileobj=None, **kwargs):"""Open uncompressed tar archive name for reading or writing."""
if mode not in ("r", "a", "w"):raise ValueError("mode must be 'r', 'a' or 'w'")return cls(name, mode, fileobj, **kwargs)
@classmethoddef gzopen(cls, name, mode="r", fileobj=None, compresslevel=9, **kwargs):"""Open gzip compressed tar archive name for reading or writing.
Appending is not allowed."""
if mode not in ("r", "w"):raise ValueError("mode must be 'r' or 'w'")try:importgzip
gzip.GzipFileexcept(ImportError, AttributeError):raise CompressionError("gzip module is not available")try:
fileobj=gzip.GzipFile(name, mode, compresslevel, fileobj)exceptOSError:if fileobj is not None and mode == 'r':raise ReadError("not a gzip file")raise
try:
t= cls.taropen(name, mode, fileobj, **kwargs)exceptIOError:
fileobj.close()if mode == 'r':raise ReadError("not a gzip file")raise
except:
fileobj.close()raiset._extfileobj=Falsereturnt
@classmethoddef bz2open(cls, name, mode="r", fileobj=None, compresslevel=9, **kwargs):"""Open bzip2 compressed tar archive name for reading or writing.
Appending is not allowed."""
if mode not in ("r", "w"):raise ValueError("mode must be 'r' or 'w'.")try:importbz2exceptImportError:raise CompressionError("bz2 module is not available")if fileobj is notNone:
fileobj=_BZ2Proxy(fileobj, mode)else:
fileobj= bz2.BZ2File(name, mode, compresslevel=compresslevel)try:
t= cls.taropen(name, mode, fileobj, **kwargs)except(IOError, EOFError):
fileobj.close()if mode == 'r':raise ReadError("not a bzip2 file")raise
except:
fileobj.close()raiset._extfileobj=Falsereturnt#All *open() methods are registered here.
OPEN_METH ={"tar": "taropen", #uncompressed tar
"gz": "gzopen", #gzip compressed tar
"bz2": "bz2open" #bzip2 compressed tar
}#--------------------------------------------------------------------------
#The public methods which TarFile provides:
defclose(self):"""Close the TarFile. In write-mode, two finishing zero blocks are
appended to the archive."""
ifself.closed:return
if self.mode in "aw":
self.fileobj.write(NUL* (BLOCKSIZE * 2))
self.offset+= (BLOCKSIZE * 2)#fill up the end with zero-blocks
#(like option -b20 for tar does)
blocks, remainder =divmod(self.offset, RECORDSIZE)if remainder >0:
self.fileobj.write(NUL* (RECORDSIZE -remainder))if notself._extfileobj:
self.fileobj.close()
self.closed=Truedefgetmember(self, name):"""Return a TarInfo object for member `name'. If `name' can not be
found in the archive, KeyError is raised. If a member occurs more
than once in the archive, its last occurrence is assumed to be the
most up-to-date version."""tarinfo=self._getmember(name)if tarinfo isNone:raise KeyError("filename %r not found" %name)returntarinfodefgetmembers(self):"""Return the members of the archive as a list of TarInfo objects. The
list has the same order as the members in the archive."""self._check()if not self._loaded: #if we want to obtain a list of
self._load() #all members, we first have to
#scan the whole archive.
returnself.membersdefgetnames(self):"""Return the members of the archive as a list of their names. It has
the same order as the list returned by getmembers()."""
return [tarinfo.name for tarinfo inself.getmembers()]def gettarinfo(self, name=None, arcname=None, fileobj=None):"""Create a TarInfo object for either the file `name' or the file
object `fileobj' (using os.fstat on its file descriptor). You can
modify some of the TarInfo's attributes before you add it using
addfile(). If given, `arcname' specifies an alternative name for the
file in the archive."""self._check("aw")#When fileobj is given, replace name by
#fileobj's real name.
if fileobj is notNone:
name=fileobj.name#Building the name of the member in the archive.
#Backward slashes are converted to forward slashes,
#Absolute paths are turned to relative paths.
if arcname isNone:
arcname=name
drv, arcname=os.path.splitdrive(arcname)
arcname= arcname.replace(os.sep, "/")
arcname= arcname.lstrip("/")#Now, fill the TarInfo object with
#information specific for the file.
tarinfo =self.tarinfo()
tarinfo.tarfile=self#Use os.stat or os.lstat, depending on platform
#and if symlinks shall be resolved.
if fileobj isNone:if hasattr(os, "lstat") and notself.dereference:
statres=os.lstat(name)else:
statres=os.stat(name)else:
statres=os.fstat(fileobj.fileno())
linkname= ""stmd=statres.st_modeifstat.S_ISREG(stmd):
inode=(statres.st_ino, statres.st_dev)if not self.dereference and statres.st_nlink > 1 and
inodein self.inodes and arcname !=self.inodes[inode]:#Is it a hardlink to an already
#archived file?
type =LNKTYPE
linkname=self.inodes[inode]else:#The inode is added only if its valid.
#For win32 it is always 0.
type =REGTYPEifinode[0]:
self.inodes[inode]=arcnameelifstat.S_ISDIR(stmd):
type=DIRTYPEelifstat.S_ISFIFO(stmd):
type=FIFOTYPEelifstat.S_ISLNK(stmd):
type=SYMTYPE
linkname=os.readlink(name)elifstat.S_ISCHR(stmd):
type=CHRTYPEelifstat.S_ISBLK(stmd):
type=BLKTYPEelse:returnNone#Fill the TarInfo object with all
#information we can get.
tarinfo.name =arcname
tarinfo.mode=stmd
tarinfo.uid=statres.st_uid
tarinfo.gid=statres.st_gidif type ==REGTYPE:
tarinfo.size=statres.st_sizeelse:
tarinfo.size=0L
tarinfo.mtime=statres.st_mtime
tarinfo.type=type
tarinfo.linkname=linknameifpwd:try:
tarinfo.uname=pwd.getpwuid(tarinfo.uid)[0]exceptKeyError:pass
ifgrp:try:
tarinfo.gname=grp.getgrgid(tarinfo.gid)[0]exceptKeyError:pass
if type in(CHRTYPE, BLKTYPE):if hasattr(os, "major") and hasattr(os, "minor"):
tarinfo.devmajor=os.major(statres.st_rdev)
tarinfo.devminor=os.minor(statres.st_rdev)returntarinfodef list(self, verbose=True):"""Print a table of contents to sys.stdout. If `verbose' is False, only
the names of the members are printed. If it is True, an `ls -l'-like
output is produced."""self._check()for tarinfo inself:ifverbose:printfilemode(tarinfo.mode),print "%s/%s" % (tarinfo.uname ortarinfo.uid,
tarinfo.gnameortarinfo.gid),if tarinfo.ischr() ortarinfo.isblk():print "%10s" % ("%d,%d"%(tarinfo.devmajor, tarinfo.devminor)),else:print "%10d" %tarinfo.size,print "%d-%02d-%02d %02d:%02d:%02d"% time.localtime(tarinfo.mtime)[:6],print tarinfo.name + ("/" if tarinfo.isdir() else ""),ifverbose:iftarinfo.issym():print "->", tarinfo.linkname,iftarinfo.islnk():print "link to", tarinfo.linkname,print
def add(self, name, arcname=None, recursive=True, exclude=None, filter=None):"""Add the file `name' to the archive. `name' may be any type of file
(directory, fifo, symbolic link, etc.). If given, `arcname'
specifies an alternative name for the file in the archive.
Directories are added recursively by default. This can be avoided by
setting `recursive' to False. `exclude' is a function that should
return True for each filename to be excluded. `filter' is a function
that expects a TarInfo object argument and returns the changed
TarInfo object, if it returns None the TarInfo object will be
excluded from the archive."""self._check("aw")if arcname isNone:
arcname=name#Exclude pathnames.
if exclude is notNone:importwarnings
warnings.warn("use the filter argument instead",
DeprecationWarning,2)ifexclude(name):
self._dbg(2, "tarfile: Excluded %r" %name)return
#Skip if somebody tries to archive the archive...
if self.name is not None and os.path.abspath(name) ==self.name:
self._dbg(2, "tarfile: Skipped %r" %name)returnself._dbg(1, name)#Create a TarInfo object from the file.
tarinfo =self.gettarinfo(name, arcname)if tarinfo isNone:
self._dbg(1, "tarfile: Unsupported type %r" %name)return
#Change or exclude the TarInfo object.
if filter is notNone:
tarinfo=filter(tarinfo)if tarinfo isNone:
self._dbg(2, "tarfile: Excluded %r" %name)return
#Append the tar header and data to the archive.
iftarinfo.isreg():
with bltn_open(name,"rb") as f:
self.addfile(tarinfo, f)eliftarinfo.isdir():
self.addfile(tarinfo)ifrecursive:for f inos.listdir(name):
self.add(os.path.join(name, f), os.path.join(arcname, f),
recursive, exclude, filter)else:
self.addfile(tarinfo)def addfile(self, tarinfo, fileobj=None):"""Add the TarInfo object `tarinfo' to the archive. If `fileobj' is
given, tarinfo.size bytes are read from it and added to the archive.
You can create TarInfo objects using gettarinfo().
On Windows platforms, `fileobj' should always be opened with mode
'rb' to avoid irritation about the file size."""self._check("aw")
tarinfo=copy.copy(tarinfo)
buf=tarinfo.tobuf(self.format, self.encoding, self.errors)
self.fileobj.write(buf)
self.offset+=len(buf)#If there's data to follow, append it.
if fileobj is notNone:
copyfileobj(fileobj, self.fileobj, tarinfo.size)
blocks, remainder=divmod(tarinfo.size, BLOCKSIZE)if remainder >0:
self.fileobj.write(NUL* (BLOCKSIZE -remainder))
blocks+= 1self.offset+= blocks *BLOCKSIZE
self.members.append(tarinfo)def extractall(self, path=".", members=None):"""Extract all members from the archive to the current working
directory and set owner, modification time and permissions on
directories afterwards. `path' specifies a different directory
to extract to. `members' is optional and must be a subset of the
list returned by getmembers()."""directories=[]if members isNone:
members=selffor tarinfo inmembers:iftarinfo.isdir():#Extract directories with a safe mode.
directories.append(tarinfo)
tarinfo=copy.copy(tarinfo)
tarinfo.mode= 0700self.extract(tarinfo, path)#Reverse sort directories.
directories.sort(key=operator.attrgetter('name'))
directories.reverse()#Set correct owner, mtime and filemode on directories.
for tarinfo indirectories:
dirpath=os.path.join(path, tarinfo.name)try:
self.chown(tarinfo, dirpath)
self.utime(tarinfo, dirpath)
self.chmod(tarinfo, dirpath)exceptExtractError, e:if self.errorlevel > 1:raise
else:
self._dbg(1, "tarfile: %s" %e)def extract(self, member, path=""):"""Extract a member from the archive to the current working directory,
using its full name. Its file information is extracted as accurately
as possible. `member' may be a filename or a TarInfo object. You can
specify a different directory using `path'."""self._check("r")ifisinstance(member, basestring):
tarinfo=self.getmember(member)else:
tarinfo=member#Prepare the link target for makelink().
iftarinfo.islnk():
tarinfo._link_target=os.path.join(path, tarinfo.linkname)try:
self._extract_member(tarinfo, os.path.join(path, tarinfo.name))exceptEnvironmentError, e:if self.errorlevel >0:raise
else:if e.filename isNone:
self._dbg(1, "tarfile: %s" %e.strerror)else:
self._dbg(1, "tarfile: %s %r" %(e.strerror, e.filename))exceptExtractError, e:if self.errorlevel > 1:raise
else:
self._dbg(1, "tarfile: %s" %e)defextractfile(self, member):"""Extract a member from the archive as a file object. `member' may be
a filename or a TarInfo object. If `member' is a regular file, a
file-like object is returned. If `member' is a link, a file-like
object is constructed from the link's target. If `member' is none of
the above, None is returned.
The file-like object is read-only and provides the following
methods: read(), readline(), readlines(), seek() and tell()"""self._check("r")ifisinstance(member, basestring):
tarinfo=self.getmember(member)else:
tarinfo=memberiftarinfo.isreg():returnself.fileobject(self, tarinfo)elif tarinfo.type not inSUPPORTED_TYPES:#If a member's type is unknown, it is treated as a
#regular file.
returnself.fileobject(self, tarinfo)elif tarinfo.islnk() ortarinfo.issym():ifisinstance(self.fileobj, _Stream):#A small but ugly workaround for the case that someone tries
#to extract a (sym)link as a file-object from a non-seekable
#stream of tar blocks.
raise StreamError("cannot extract (sym)link as file object")else:#A (sym)link's file object is its target's file object.
returnself.extractfile(self._find_link_target(tarinfo))else:#If there's no data associated with the member (directory, chrdev,
#blkdev, etc.), return None instead of a file object.
returnNonedef_extract_member(self, tarinfo, targetpath):"""Extract the TarInfo object tarinfo to a physical
file called targetpath."""
#Fetch the TarInfo object for the given name
#and build the destination pathname, replacing
#forward slashes to platform specific separators.
targetpath = targetpath.rstrip("/")
targetpath= targetpath.replace("/", os.sep)#Create all upper directories.
upperdirs =os.path.dirname(targetpath)if upperdirs and notos.path.exists(upperdirs):#Create directories that are not part of the archive with
#default permissions.
os.makedirs(upperdirs)if tarinfo.islnk() ortarinfo.issym():
self._dbg(1, "%s -> %s" %(tarinfo.name, tarinfo.linkname))else:
self._dbg(1, tarinfo.name)iftarinfo.isreg():
self.makefile(tarinfo, targetpath)eliftarinfo.isdir():
self.makedir(tarinfo, targetpath)eliftarinfo.isfifo():
self.makefifo(tarinfo, targetpath)elif tarinfo.ischr() ortarinfo.isblk():
self.makedev(tarinfo, targetpath)elif tarinfo.islnk() ortarinfo.issym():
self.makelink(tarinfo, targetpath)elif tarinfo.type not inSUPPORTED_TYPES:
self.makeunknown(tarinfo, targetpath)else:
self.makefile(tarinfo, targetpath)
self.chown(tarinfo, targetpath)if nottarinfo.issym():
self.chmod(tarinfo, targetpath)
self.utime(tarinfo, targetpath)#--------------------------------------------------------------------------
#Below are the different file methods. They are called via
#_extract_member() when extract() is called. They can be replaced in a
#subclass to implement other functionality.
defmakedir(self, tarinfo, targetpath):"""Make a directory called targetpath."""
try:#Use a safe mode for the directory, the real mode is set
#later in _extract_member().
os.mkdir(targetpath, 0700)exceptEnvironmentError, e:if e.errno !=errno.EEXIST:raise
defmakefile(self, tarinfo, targetpath):"""Make a file called targetpath."""source=self.extractfile(tarinfo)try:
with bltn_open(targetpath,"wb") as target:
copyfileobj(source, target)finally:
source.close()defmakeunknown(self, tarinfo, targetpath):"""Make a file from a TarInfo object with an unknown type
at targetpath."""self.makefile(tarinfo, targetpath)
self._dbg(1, "tarfile: Unknown file type %r,""extracted as regular file." %tarinfo.type)defmakefifo(self, tarinfo, targetpath):"""Make a fifo called targetpath."""
if hasattr(os, "mkfifo"):
os.mkfifo(targetpath)else:raise ExtractError("fifo not supported by system")defmakedev(self, tarinfo, targetpath):"""Make a character or block device called targetpath."""
if not hasattr(os, "mknod") or not hasattr(os, "makedev"):raise ExtractError("special devices not supported by system")
mode=tarinfo.modeiftarinfo.isblk():
mode|=stat.S_IFBLKelse:
mode|=stat.S_IFCHR
os.mknod(targetpath, mode,
os.makedev(tarinfo.devmajor, tarinfo.devminor))defmakelink(self, tarinfo, targetpath):"""Make a (symbolic) link called targetpath. If it cannot be created
(platform limitation), we try to make a copy of the referenced file
instead of a link."""
if hasattr(os, "symlink") and hasattr(os, "link"):#For systems that support symbolic and hard links.
iftarinfo.issym():ifos.path.lexists(targetpath):
os.unlink(targetpath)
os.symlink(tarinfo.linkname, targetpath)else:#See extract().
ifos.path.exists(tarinfo._link_target):ifos.path.lexists(targetpath):
os.unlink(targetpath)
os.link(tarinfo._link_target, targetpath)else:
self._extract_member(self._find_link_target(tarinfo), targetpath)else:try:
self._extract_member(self._find_link_target(tarinfo), targetpath)exceptKeyError:raise ExtractError("unable to resolve link inside archive")defchown(self, tarinfo, targetpath):"""Set owner of targetpath according to tarinfo."""
if pwd and hasattr(os, "geteuid") and os.geteuid() ==0:#We have to be root to do so.
try:
g= grp.getgrnam(tarinfo.gname)[2]exceptKeyError:
g=tarinfo.gidtry:
u= pwd.getpwnam(tarinfo.uname)[2]exceptKeyError:
u=tarinfo.uidtry:if tarinfo.issym() and hasattr(os, "lchown"):
os.lchown(targetpath, u, g)else:if sys.platform != "os2emx":
os.chown(targetpath, u, g)exceptEnvironmentError, e:raise ExtractError("could not change owner")defchmod(self, tarinfo, targetpath):"""Set file permissions of targetpath according to tarinfo."""
if hasattr(os, 'chmod'):try:
os.chmod(targetpath, tarinfo.mode)exceptEnvironmentError, e:raise ExtractError("could not change mode")defutime(self, tarinfo, targetpath):"""Set modification time of targetpath according to tarinfo."""
if not hasattr(os, 'utime'):return
try:
os.utime(targetpath, (tarinfo.mtime, tarinfo.mtime))exceptEnvironmentError, e:raise ExtractError("could not change modification time")#--------------------------------------------------------------------------
defnext(self):"""Return the next member of the archive as a TarInfo object, when
TarFile is opened for reading. Return None if there is no more
available."""self._check("ra")if self.firstmember is notNone:
m=self.firstmember
self.firstmember=Nonereturnm#Read the next block.
self.fileobj.seek(self.offset)
tarinfo=NonewhileTrue:try:
tarinfo=self.tarinfo.fromtarfile(self)exceptEOFHeaderError, e:ifself.ignore_zeros:
self._dbg(2, "0x%X: %s" %(self.offset, e))
self.offset+=BLOCKSIZEcontinue
exceptInvalidHeaderError, e:ifself.ignore_zeros:
self._dbg(2, "0x%X: %s" %(self.offset, e))
self.offset+=BLOCKSIZEcontinue
elif self.offset ==0:raiseReadError(str(e))exceptEmptyHeaderError:if self.offset ==0:raise ReadError("empty file")exceptTruncatedHeaderError, e:if self.offset ==0:raiseReadError(str(e))exceptSubsequentHeaderError, e:raiseReadError(str(e))break
if tarinfo is notNone:
self.members.append(tarinfo)else:
self._loaded=Truereturntarinfo#--------------------------------------------------------------------------
#Little helper methods:
def _getmember(self, name, tarinfo=None, normalize=False):"""Find an archive member by name from bottom to top.
If tarinfo is given, it is used as the starting point."""
#Ensure that all members have been loaded.
members =self.getmembers()#Limit the member search list up to tarinfo.
if tarinfo is notNone:
members=members[:members.index(tarinfo)]ifnormalize:
name=os.path.normpath(name)for member inreversed(members):ifnormalize:
member_name=os.path.normpath(member.name)else:
member_name=member.nameif name ==member_name:returnmemberdef_load(self):"""Read through the entire archive file and look for readable
members."""
whileTrue:
tarinfo=self.next()if tarinfo isNone:breakself._loaded=Truedef _check(self, mode=None):"""Check if TarFile is still open, and if the operation's mode
corresponds to TarFile's mode."""
ifself.closed:raise IOError("%s is closed" % self.__class__.__name__)if mode is not None and self.mode not inmode:raise IOError("bad operation for mode %r" %self.mode)def_find_link_target(self, tarinfo):"""Find the target member of a symlink or hardlink member in the
archive."""
iftarinfo.issym():#Always search the entire archive.
linkname = "/".join(filter(None, (os.path.dirname(tarinfo.name), tarinfo.linkname)))
limit=Noneelse:#Search the archive before the link, because a hard link is
#just a reference to an already archived file.
linkname =tarinfo.linkname
limit=tarinfo
member= self._getmember(linkname, tarinfo=limit, normalize=True)if member isNone:raise KeyError("linkname %r not found" %linkname)returnmemberdef __iter__(self):"""Provide an iterator object."""
ifself._loaded:returniter(self.members)else:returnTarIter(self)def_dbg(self, level, msg):"""Write debugging output to sys.stderr."""
if level <=self.debug:print >>sys.stderr, msgdef __enter__(self):
self._check()returnselfdef __exit__(self, type, value, traceback):if type isNone:
self.close()else:#An exception occurred. We must not call close() because
#it would try to write end-of-archive blocks and padding.
if notself._extfileobj:
self.fileobj.close()
self.closed=True#class TarFile
TarFile
TarFile 源码
最后
以上就是积极滑板为你收集整理的python settings模块_Python学习之路10——Python常用模块的全部内容,希望文章能够帮你解决python settings模块_Python学习之路10——Python常用模块所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复