00001
00002
00003
00004
00005
00006
00007
00008
00009 #include "GZCSVFileWriter.h"
00010
00011 #include <fcntl.h>
00012
00013 using namespace sella::file;
00014
00024 GZCSVFileWriter::GZCSVFileWriter(const std::string & file, char delimiter, char seperator) THROWS(IOException) :
00025 filename(file),
00026
00027 delimiter(delimiter),
00028 seperator(seperator),
00029
00030 descriptor(::open(file.c_str(), O_WRONLY | O_LARGEFILE | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH))
00031 {
00032
00033 if (this->descriptor <= 0) {
00034 THROW(IOException, "failed to open file '%s' for writing", this->filename.c_str());
00035 }
00036 memset(&(this->stream), 0, sizeof(this->stream));
00037 memset(&(this->buffer), 0, sizeof(this->buffer));
00038
00039
00040 if (::deflateInit2(&(this->stream), 9 , Z_DEFLATED, 16 + MAX_WBITS , 9 , Z_DEFAULT_STRATEGY) != Z_OK) {
00041 ::close(this->descriptor);
00042
00043 THROW(IOException, "failed to initilize zlib instance for writing file '%s'", this->filename.c_str());
00044 }
00045 }
00046
00051 GZCSVFileWriter::~GZCSVFileWriter() NO_EXCEPTIONS {
00052 if (this->descriptor != 0) {
00053 ::deflateEnd(&(this->stream));
00054
00055 this->close();
00056 }
00057 }
00058
00066 void GZCSVFileWriter::write(const std::vector<std::string> & data) THROWS(IOException) {
00067 size_t length = 0;
00068
00069
00070 for (auto iter = data.begin(); iter != data.end(); ++iter) {
00071 ssize_t offset = 0;
00072
00073
00074 if (iter != data.begin()) {
00075
00076 if (sizeof(this->delimiter) > (sizeof(this->buffer[1]) - length)) {
00077 this->write(this->buffer[1], length, Z_NO_FLUSH);
00078
00079 length = 0;
00080 }
00081 this->buffer[1][length++] = this->delimiter;
00082 }
00083
00084 do {
00085
00086 if ((iter->length() - offset) > (sizeof(this->buffer[1]) - length)) {
00087 ::memcpy(&(this->buffer[1][length]), &(iter->c_str()[offset]), sizeof(this->buffer[1]) - length);
00088
00089 this->write(this->buffer[1], sizeof(this->buffer[1]), Z_NO_FLUSH);
00090
00091 offset += (sizeof(this->buffer[1]) - length);
00092 length = 0;
00093 } else {
00094 ::memcpy(&(this->buffer[1][length]), &(iter->c_str()[offset]), iter->length() - offset);
00095
00096 length += (iter->length() - offset);
00097 offset += (iter->length() - offset);
00098 }
00099 } while (offset != static_cast<ssize_t>(iter->length()));
00100 }
00101
00102
00103 if (sizeof(this->seperator) > (sizeof(this->buffer[1]) - length)) {
00104 this->write(this->buffer[1], length, Z_NO_FLUSH);
00105
00106 length = 0;
00107 }
00108 this->buffer[1][length++] = this->seperator;
00109
00110 this->write(this->buffer[1], length, Z_NO_FLUSH);
00111 }
00112
00122 void GZCSVFileWriter::write(uint8_t * input, ssize_t length, int flush) THROWS(IOException) {
00123 ssize_t expect;
00124
00125 this->stream.next_in = input;
00126 this->stream.avail_in = length;
00127
00128 do {
00129 this->stream.next_out = this->buffer[0];
00130 this->stream.avail_out = sizeof(this->buffer[0]);
00131
00132
00133 switch (::deflate(&(this->stream), flush)) {
00134 case Z_STREAM_ERROR:
00135 THROW(IOException, "zlib compression failure when writing buffer to compressed file '%s'", this->filename.c_str());
00136 }
00137
00138
00139 if ((expect = (sizeof(this->buffer[0]) - this->stream.avail_out)) > 0) {
00140 while ((length = ::write(this->descriptor, this->buffer[0], sizeof(this->buffer[0]) - this->stream.avail_out)) != expect) {
00141 if (length == -1) {
00142 THROW(IOException, "failure writing buffer to compressed file '%s'", this->filename.c_str());
00143 }
00144 expect -= length;
00145 }
00146 }
00147 } while (this->stream.avail_out == 0);
00148
00149
00150 if (this->stream.avail_in != 0) {
00151 THROW(IOException, "failed to write full buffer to compressed file '%s'", this->filename.c_str());
00152 }
00153 }
00154
00163 void GZCSVFileWriter::close(const std::string & rename) THROWS(IOException) {
00164 uint8_t buffer[4];
00165
00166
00167 this->write(buffer, 0, Z_FINISH);
00168
00169 ::close(this->descriptor);
00170
00171 if (rename.length() > 0) {
00172 ::rename(this->filename.c_str(), rename.c_str());
00173 }
00174 this->filename.clear();
00175 this->descriptor = 0;
00176 }
00177
00178
00179
00180