public class ARCWriter extends WriterPoolMember implements ARCConstants, java.io.Closeable
ARC files are described here: Arc File Format. This class does version 1 of the ARC file format. It also writes version 1.1 which is version 1 with data stuffed into the body of the first arc record in the file, the arc file meta record itself.
An ARC file is three lines of meta data followed by an optional 'body' and then a couple of '\n' and then: record, '\n', record, '\n', record, etc. If we are writing compressed ARC files, then each of the ARC file records is individually gzipped and concatenated together to make up a single ARC file. In GZIP terms, each ARC record is a GZIP member of a total gzip'd file.
The GZIPping of the ARC file meta data is exceptional. It is GZIPped w/ an extra GZIP header, a special Internet Archive (IA) extra header field (e.g. FEXTRA is set in the GZIP header FLG field and an extra field is appended to the GZIP header). The extra field has little in it but its presence denotes this GZIP as an Internet Archive gzipped ARC. See RFC1952 to learn about the GZIP header structure.
This class then does its GZIPping in the following fashion. Each GZIP member is written w/ a new instance of GZIPOutputStream -- actually ARCWriterGZIPOututStream so we can get access to the underlying stream. The underlying stream stays open across GZIPoutputStream instantiations. For the 'special' GZIPing of the ARC file meta data, we cheat by catching the GZIPOutputStream output into a byte array, manipulating it adding the IA GZIP header, before writing to the stream.
I tried writing a resettable GZIPOutputStream and could make it work w/ the SUN JDK but the IBM JDK threw NPE inside in the deflate.reset -- its zlib native call doesn't seem to like the notion of resetting -- so I gave up on it.
Because of such as the above and troubles with GZIPInputStream, we should write our own GZIP*Streams, ones that resettable and consious of gzip members.
This class will write until we hit >= maxSize. The check is done at record boundary. Records do not span ARC files. We will then close current file and open another and then continue writing.
TESTING: Here is how to test that produced ARC files are good using the alexa ARC c-tools:
% av_procarc hx20040109230030-0.arc.gz | av_ziparc > \
/tmp/hx20040109230030-0.dat.gz
% av_ripdat /tmp/hx20040109230030-0.dat.gz > /tmp/hx20040109230030-0.cdx
Examine the produced cdx file to make sure it makes sense. Search
for 'no-type 0'. If found, then we're opening a gzip record w/o data to
write. This is bad.
You can also do gzip -t FILENAME and it will tell you if the
ARC makes sense to GZIP.
While being written, ARCs have a '.open' suffix appended.
ARCConstants.ArcRecordErrorscountOut, currentBasename, currentTimestamp, DEFAULT_PREFIX, DEFAULT_TEMPLATE, f, out, roundRobinIndex, scratchbuffer, serialNoFormatter, settings, UTF8ACTUAL_LENGTH_KEY, ALEXA_DAT_MIME, ARC_FILE_EXTENSION, ARC_GZIP_EXTRA_FIELD, ARC_MAGIC_NUMBER, ARC_META_CHARSET, CARRIAGE_RETURN_ORD, CHECKSUM_FIELD_KEY, CHECKSUM_HEADER_FIELD_KEY, CODE_HEADER_FIELD_KEY, COMPRESSED_ARC_FILE_EXTENSION, DATE_STRING_KEY, DECLARED_LENGTH_KEY, DEFAULT_ENCODING, DEFAULT_GZIP_HEADER_LENGTH, DEFAULT_MAX_ARC_FILE_SIZE, DEFAULT_MIME, DELIMITER, DNS_MIME, DOT_ARC_FILE_EXTENSION, DOT_COMPRESSED_ARC_FILE_EXTENSION, DOT_COMPRESSED_FILE_EXTENSION, FIELD_COUNT, FILEDESC_SCHEME, FILENAME_FIELD_KEY, FILENAME_HEADER_FIELD_KEY, GZIP_HEADER_BEGIN, HEADER_FIELD_SEPARATOR, HEADER_LENGTH, IP_HEADER_FIELD_KEY, IP_KEY, LEADING_NEWLINES_KEY, LINE_SEPARATOR, LOCATION_HEADER_FIELD_KEY, MAX_HEADER_LINE_LENGTH, MAX_META_LENGTH, MAX_METADATA_LINE_LENGTH, MIME_KEY, MINIMUM_RECORD_LENGTH, NEW_LINE_ORD, OFFSET_FIELD_KEY, OFFSET_HEADER_FIELD_KEY, REQUIRED_VERSION_1_HEADER_FIELDS, STATUSCODE_FIELD_KEY, TOKENIZED_PREFIX, TRAILING_CRUFT_KEY, TRAILING_NEWLINES_KEY, URL_KEYABSOLUTE_OFFSET_KEY, CDX, CDX_FILE, CDX_LINE_BUFFER_SIZE, CRLF, DATE_FIELD_KEY, DEFAULT_DIGEST_METHOD, DUMP, GZIP_DUMP, HEADER, INVALID_SUFFIX, LENGTH_FIELD_KEY, MIMETYPE_FIELD_KEY, NOHEAD, OCCUPIED_SUFFIX, ORIGIN_FIELD_KEY, READER_IDENTIFIER_FIELD_KEY, RECORD_IDENTIFIER_FIELD_KEY, SINGLE_SPACE, TYPE_FIELD_KEY, URL_FIELD_KEY, VERSION_FIELD_KEY| Constructor and Description |
|---|
ARCWriter(java.util.concurrent.atomic.AtomicInteger serialNo,
java.io.PrintStream out,
java.io.File arc,
WriterPoolSettings settings)
Constructor.
|
ARCWriter(java.util.concurrent.atomic.AtomicInteger serialNo,
WriterPoolSettings settings)
Constructor.
|
| Modifier and Type | Method and Description |
|---|---|
protected java.lang.String |
createFile()
Create a new file.
|
java.lang.String |
createMetaline(java.lang.String uri,
java.lang.String hostIP,
java.lang.String timeStamp,
java.lang.String mimetype,
java.lang.String recordLength) |
java.lang.String |
getMetadataHeaderLinesTwoAndThree(java.lang.String version) |
protected java.lang.String |
getMetaLine(java.lang.String uri,
java.lang.String contentType,
java.lang.String hostIP,
long fetchBeginTimeStamp,
long recordLength) |
protected java.lang.String |
validateMetaLine(java.lang.String metaLineStr)
Test that the metadata line is valid before writing.
|
void |
write(java.lang.String uri,
java.lang.String contentType,
java.lang.String hostIP,
long fetchBeginTimeStamp,
long recordLength,
java.io.ByteArrayOutputStream baos)
Deprecated.
use input-stream version directly instead
|
void |
write(java.lang.String uri,
java.lang.String contentType,
java.lang.String hostIP,
long fetchBeginTimeStamp,
long recordLength,
java.io.InputStream in) |
void |
write(java.lang.String uri,
java.lang.String contentType,
java.lang.String hostIP,
long fetchBeginTimeStamp,
long recordLength,
java.io.InputStream in,
boolean enforceLength)
Write a record with the given metadata/content.
|
checkSize, checkWriteable, close, copyFrom, createFile, flush, generateNewBasename, getBaseFilename, getFile, getNextDirectory, getOutputStream, getPosition, isCompressed, isOversize, postWriteRecordTasks, preWriteRecordTasks, write, write, writepublic ARCWriter(java.util.concurrent.atomic.AtomicInteger serialNo,
java.io.PrintStream out,
java.io.File arc,
WriterPoolSettings settings)
throws java.io.IOException
serialNo - used to generate unique file name sequencesout - Where to write.arc - File the out is connected to.cmprs - Compress the content written.metadata - File meta data. Can be null. Is list of File and/or
String objects.a14DigitDate - If null, we'll write current time.java.io.IOExceptionpublic ARCWriter(java.util.concurrent.atomic.AtomicInteger serialNo,
WriterPoolSettings settings)
serialNo - used to generate unique file name sequencessettings - all creation parametersprotected java.lang.String createFile()
throws java.io.IOException
WriterPoolMemberWriterPoolMember.checkSize().createFile in class WriterPoolMemberjava.io.IOExceptionpublic java.lang.String getMetadataHeaderLinesTwoAndThree(java.lang.String version)
public void write(java.lang.String uri,
java.lang.String contentType,
java.lang.String hostIP,
long fetchBeginTimeStamp,
long recordLength,
java.io.ByteArrayOutputStream baos)
throws java.io.IOException
java.io.IOExceptionpublic void write(java.lang.String uri,
java.lang.String contentType,
java.lang.String hostIP,
long fetchBeginTimeStamp,
long recordLength,
java.io.InputStream in)
throws java.io.IOException
java.io.IOExceptionpublic void write(java.lang.String uri,
java.lang.String contentType,
java.lang.String hostIP,
long fetchBeginTimeStamp,
long recordLength,
java.io.InputStream in,
boolean enforceLength)
throws java.io.IOException
uri - URI for metadata-linecontentType - MIME content-type for metadata-linehostIP - IP for metadata-linefetchBeginTimeStamp - timestamp for metadata-linerecordLength - length for metadata-line; also may be enforcedin - source InputStream for record contentenforceLength - whether to enforce the declared length; should be true
unless intentionally writing bad records for testingjava.io.IOExceptionprotected java.lang.String getMetaLine(java.lang.String uri,
java.lang.String contentType,
java.lang.String hostIP,
long fetchBeginTimeStamp,
long recordLength)
throws java.io.IOException
uri - contentType - hostIP - fetchBeginTimeStamp - recordLength - java.io.IOExceptionpublic java.lang.String createMetaline(java.lang.String uri,
java.lang.String hostIP,
java.lang.String timeStamp,
java.lang.String mimetype,
java.lang.String recordLength)
protected java.lang.String validateMetaLine(java.lang.String metaLineStr)
throws java.io.IOException
metaLineStr - java.io.IOExceptionCopyright © 2019 The International Internet Preservation Consortium. All Rights Reserved.