arc.tex
来自「Wxpython Implemented on Windows CE, Sou」· TEX 代码 · 共 479 行 · 第 1/2 页
TEX
479 行
if ((it = cat.find(wxZipEntry::GetInternalName(localname))) != cat.end()) {
zip.OpenEntry(*it->second);
// ... now read entry's data
}
\end{verbatim}
To open more than one entry simultaneously you need more than one
underlying stream on the same archive:
\begin{verbatim}
// opening another entry without closing the first requires another
// input stream for the same file
wxFFileInputStream in2(_T("test.zip"));
wxZipInputStream zip2(in2);
if ((it = cat.find(wxZipEntry::GetInternalName(local2))) != cat.end())
zip2.OpenEntry(*it->second);
\end{verbatim}
\subsection{Generic archive programming}\label{wxarcgeneric}
\helpref{Archive formats such as zip}{wxarc}
Also see \helpref{wxFileSystem}{fs} for a higher level interface that
can handle archive files in a generic way.
The specific archive classes, such as the wxZip classes, inherit from
the following abstract classes which can be used to write code that can
handle any of the archive types:
\begin{twocollist}\twocolwidtha{5cm}
\twocolitem{\helpref{wxArchiveInputStream}{wxarchiveinputstream}}{Input stream}
\twocolitem{\helpref{wxArchiveOutputStream}{wxarchiveoutputstream}}{Output stream}
\twocolitem{\helpref{wxArchiveEntry}{wxarchiveentry}}{Holds the meta-data for an
entry (e.g. filename)}
\end{twocollist}
In order to able to write generic code it's necessary to be able to create
instances of the classes without knowing which archive type is being used.
So there is a class factory for each archive type, derived from
\helpref{wxArchiveClassFactory}{wxarchiveclassfactory}, which can create
the other classes.
For example, given {\it wxArchiveClassFactory* factory}, streams and
entries can be created like this:
\begin{verbatim}
// create streams without knowing their type
wxArchiveInputStreamPtr inarc(factory->NewStream(in));
wxArchiveOutputStreamPtr outarc(factory->NewStream(out));
// create an empty entry object
wxArchiveEntryPtr entry(factory->NewEntry());
\end{verbatim}
The \helpref{smart pointer}{wxscopedptr} types {\em wxArchiveInputStreamPtr},
{\em wxArchiveOutputStreamPtr} and {\em wxArchiveEntryPtr} would need to
have already have been defined, which could be done like this:
\begin{verbatim}
#include <wx/ptr_scpd.h>
wxDEFINE_SCOPED_PTR_TYPE(wxArchiveInputStream);
wxDEFINE_SCOPED_PTR_TYPE(wxArchiveOutputStream);
wxDEFINE_SCOPED_PTR_TYPE(wxArchiveEntry);
\end{verbatim}
The class factory itself can either be created explicitly:
\begin{verbatim}
wxArchiveClassFactory *factory = new wxZipClassFactory;
\end{verbatim}
or using wxWidgets' \helpref{RTTI}{runtimeclassoverview}:
\begin{verbatim}
wxArchiveClassFactory *MakeFactory(const wxString& type)
{
wxString name = _T("wx") + type.Left(1).Upper() +
type.Mid(1).Lower() + _T("ClassFactory");
wxObject *pObj = wxCreateDynamicObject(name);
wxArchiveClassFactory *pcf = wxDynamicCast(pObj, wxArchiveClassFactory);
if (!pcf) {
wxLogError(_T("can't handle '%s' archives"), type.c_str());
delete pObj;
}
return pcf;
}
\end{verbatim}
\subsection{Archives on non-seekable streams}\label{wxarcnoseek}
\helpref{Archive formats such as zip}{wxarc}
In general, handling archives on non-seekable streams is done in the same
way as for seekable streams, with a few caveats.
The main limitation is that accessing entries randomly using
\helpref{OpenEntry()}{wxarchiveinputstreamopenentry}
is not possible, the entries can only be accessed sequentially in the order
they are stored within the archive.
For each archive type, there will also be other limitations which will
depend on the order the entries' meta-data is stored within the archive.
These are not too difficult to deal with, and are outlined below.
\wxheading{PutNextEntry and the entry size}
When writing archives, some archive formats store the entry size before
the entry's data (tar has this limitation, zip doesn't). In this case
the entry's size must be passed to
\helpref{PutNextEntry()}{wxarchiveoutputstreamputnextentry} or an error
occurs.
This is only an issue on non-seekable streams, since otherwise the archive
output stream can seek back and fix up the header once the size of the
entry is known.
For generic programming, one way to handle this is to supply the size
whenever it is known, and rely on the error message from the output
stream when the operation is not supported.
\wxheading{GetNextEntry and the weak reference mechanism}
Some archive formats do not store all an entry's meta-data before the
entry's data (zip is an example). In this case, when reading from a
non-seekable stream, \helpref{GetNextEntry()}{wxarchiveinputstreamgetnextentry}
can only return a partially populated \helpref{wxArchiveEntry}{wxarchiveentry}
object - not all the fields are set.
The input stream then keeps a weak reference to the entry object and
updates it when more meta-data becomes available. A weak reference being
one that does not prevent you from deleting the wxArchiveEntry object - the
input stream only attempts to update it if it is still around.
The documentation for each archive entry type gives the details
of what meta-data becomes available and when. For generic programming,
when the worst case must be assumed, you can rely on all the fields
of wxArchiveEntry being fully populated when GetNextEntry() returns,
with the the following exceptions:
\begin{twocollist}\twocolwidtha{3cm}
\twocolitem{\helpref{GetSize()}{wxarchiveentrysize}}{Guaranteed to be
available after the entry has been read to \helpref{Eof()}{wxinputstreameof},
or \helpref{CloseEntry()}{wxarchiveinputstreamcloseentry} has been called}
\twocolitem{\helpref{IsReadOnly()}{wxarchiveentryisreadonly}}{Guaranteed to
be available after the end of the archive has been reached, i.e. after
GetNextEntry() returns NULL and Eof() is true}
\end{twocollist}
This mechanism allows \helpref{CopyEntry()}{wxarchiveoutputstreamcopyentry}
to always fully preserve entries' meta-data. No matter what order order
the meta-data occurs within the archive, the input stream will always
have read it before the output stream must write it.
\wxheading{wxArchiveNotifier}
Notifier objects can be used to get a notification whenever an input
stream updates a \helpref{wxArchiveEntry}{wxarchiveentry} object's data
via the weak reference mechanism.
Consider the following code which renames an entry in an archive.
This is the usual way to modify an entry's meta-data, simply set the
required field before writing it with
\helpref{CopyEntry()}{wxarchiveoutputstreamcopyentry}:
\begin{verbatim}
wxArchiveInputStreamPtr arc(factory->NewStream(in));
wxArchiveOutputStreamPtr outarc(factory->NewStream(out));
wxArchiveEntryPtr entry;
outarc->CopyArchiveMetaData(*arc);
while (entry.reset(arc->GetNextEntry()), entry.get() != NULL) {
if (entry->GetName() == from)
entry->SetName(to);
if (!outarc->CopyEntry(entry.release(), *arc))
break;
}
bool success = arc->Eof() && outarc->Close();
\end{verbatim}
However, for non-seekable streams, this technique cannot be used for
fields such as \helpref{IsReadOnly()}{wxarchiveentryisreadonly},
which are not necessarily set when
\helpref{GetNextEntry()}{wxarchiveinputstreamgetnextentry} returns. In
this case a \helpref{wxArchiveNotifier}{wxarchivenotifier} can be used:
\begin{verbatim}
class MyNotifier : public wxArchiveNotifier
{
public:
void OnEntryUpdated(wxArchiveEntry& entry) { entry.SetIsReadOnly(false); }
};
\end{verbatim}
The meta-data changes are done in your notifier's
\helpref{OnEntryUpdated()}{wxarchivenotifieronentryupdated} method,
then \helpref{SetNotifier()}{wxarchiveentrynotifier} is called before
CopyEntry():
\begin{verbatim}
wxArchiveInputStreamPtr arc(factory->NewStream(in));
wxArchiveOutputStreamPtr outarc(factory->NewStream(out));
wxArchiveEntryPtr entry;
MyNotifier notifier;
outarc->CopyArchiveMetaData(*arc);
while (entry.reset(arc->GetNextEntry()), entry.get() != NULL) {
entry->SetNotifier(notifier);
if (!outarc->CopyEntry(entry.release(), *arc))
break;
}
bool success = arc->Eof() && outarc->Close();
\end{verbatim}
SetNotifier() calls OnEntryUpdated() immediately, then the input
stream calls it again whenever it sets more fields in the entry. Since
OnEntryUpdated() will be called at least once, this technique always
works even when it is not strictly necessary to use it. For example,
changing the entry name can be done this way too and it works on seekable
streams as well as non-seekable.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?