2011-06-26 15 views
16

मुझे फ्लाई पर lzma संपीड़न और डिकंप्रेशन करने की आवश्यकता है। मुझे Qt में qnetworkmanager के माध्यम से एक बड़ी फ़ाइल प्राप्त हो रही है और मुझे डेटा स्ट्रीम डाउनलोड होने के कारण इसे डिकंप्रेस करने की आवश्यकता है।सी ++ lzma संपीड़न और भागों द्वारा बड़ी धारा का डिकंप्रेशन

जब मुझे डेटा स्ट्रीम का हिस्सा मिलता है तो मुझे इसे डिकंप्रेस करने की आवश्यकता होती है, फ़ाइल में संलग्न होता है और प्रक्रिया के दौरान किसी भी प्रयुक्त स्मृति को मुक्त करने की आवश्यकता होती है। इसे करने का बेहतरीन तरीका क्या है?

अब मैं xz-utils, शुद्ध सी एपीआई के साथ प्रयास कर रहा हूं, शायद कोई बेहतर तरीका सुझा सकता है?

कोड निम्नलिखित

this उदाहरण के आधार पर

UPD2:

extern "C" void *lz_alloc(void *opaque, size_t nmemb, size_t size) 
{ 
void *p = NULL; 
try{ 
    p = new char [size]; 
} 
catch(std::bad_alloc &ba) 
{ 
    p = NULL; 
} 
return p; 
} 

extern "C" void lz_free(void *opaque, void *ptr) 
{ 
delete [] (char*)ptr; 
} 


QByteArray lzCompress(QByteArray data) 
{ 
QByteArray arr; 
lzma_check check = LZMA_CHECK_CRC64; 
lzma_stream strm = LZMA_STREAM_INIT; /* alloc and init lzma_stream struct */ 
lzma_allocator al; 
al.alloc = lz_alloc; 
al.free = lz_free; 
strm.allocator = &al; 
byte *in_buf; 
byte out_buf [OUT_BUF_MAX]; 
size_t in_len; /* length of useful data in in_buf */ 
size_t out_len; /* length of useful data in out_buf */ 
lzma_ret ret_xz; 

/* initialize xz encoder */ 
ret_xz = lzma_easy_encoder (&strm, 9 | LZMA_PRESET_EXTREME, check); 
if (ret_xz != LZMA_OK) { 
    return QByteArray(); 
} 

in_len = data.size(); 
in_buf = (byte*)data.data(); 
strm.next_in = in_buf; 
strm.avail_in = in_len; 

do { 
    strm.next_out = out_buf; 
    strm.avail_out = OUT_BUF_MAX; 
    ret_xz = lzma_code (&strm, LZMA_FINISH); 

    out_len = OUT_BUF_MAX - strm.avail_out; 
    arr.append((char*)out_buf, out_len); 
    out_buf[0] = 0; 
} while (strm.avail_out == 0); 
lzma_end (&strm); 
return arr; 
} 

मैं sleeped कुछ ही घंटों है, और अब मैं और अधिक स्पष्ट रूप में सोच, मेरे गलत कोड तय है, यह अद्यतन (यह सिर्फ के रूप में व्यवहार है qCompress काम करता है)

UPD3:

विसंपीड़न कोड (व्यवहार की तरह qUncompress)

QByteArray lzUncompress(QByteArray data) 
{ 
lzma_stream strm = LZMA_STREAM_INIT; /* alloc and init lzma_stream struct */ 
const uint32_t flags = LZMA_TELL_UNSUPPORTED_CHECK | LZMA_CONCATENATED; 
const uint64_t memory_limit = UINT64_MAX; /* no memory limit */ 
byte *in_buf; 
uint8_t out_buf [OUT_BUF_MAX]; 
size_t in_len; /* length of useful data in in_buf */ 
size_t out_len; /* length of useful data in out_buf */ 
lzma_ret ret_xz; 
QByteArray arr; 

ret_xz = lzma_stream_decoder (&strm, memory_limit, flags); 
if (ret_xz != LZMA_OK) { 
    return QByteArray(); 
} 

in_len = data.size(); 
in_buf = (byte*)data.data(); 

strm.next_in = in_buf; 
strm.avail_in = in_len; 
do { 
    strm.next_out = out_buf; 
    strm.avail_out = OUT_BUF_MAX; 
    ret_xz = lzma_code (&strm, LZMA_FINISH); 

    out_len = OUT_BUF_MAX - strm.avail_out; 
    arr.append((char*)out_buf, out_len); 
    out_buf[0] = 0; 
} while (strm.avail_out == 0); 
lzma_end (&strm); 
return arr; 
} 

UPD4:

बुनियादी धारा विसंपीड़न वर्ग, कोड सिर्फ संपीड़न हटाने XZ धारा मक्खी पर http सर्वर से डाउनलोड के बाद, मैं वास्तव में क्या जरूरत है:

class lz_stream_decompressor : public QObject 
{ 
Q_OBJECT 
public: 
lz_stream_decompressor(QNetworkReply *r, QNetworkAccessManager *q, const QString &str, unsigned long sz): flags(LZMA_TELL_UNSUPPORTED_CHECK | LZMA_CONCATENATED), memory_limit(UINT64_MAX), state(0), total_upd_size(sz) 
{ 
    repl = r; 
    qnm = q; 
    path = str; 
    strm.next_in = NULL; 
    strm.avail_in = 0; 
    strm.total_in = 0; 
    strm.next_out = NULL; 
    strm.avail_out = 0; 
    strm.total_out = 0; 
    strm.allocator = NULL; 
    strm.internal = NULL; 
    strm.reserved_ptr1 = NULL; 
    strm.reserved_ptr2 = NULL; 
    strm.reserved_ptr3 = NULL; 
    strm.reserved_ptr4 = NULL; 
    strm.reserved_int1 = 0; 
    strm.reserved_int2 = 0; 
    strm.reserved_int3 = 0; 
    strm.reserved_int4 = 0; 
    strm.reserved_enum1 = LZMA_RESERVED_ENUM; 
    strm.reserved_enum2 = LZMA_RESERVED_ENUM; 
    ret_xz = lzma_stream_decoder (&strm, memory_limit, flags); 
    if (ret_xz != LZMA_OK) 
    { 
     state = -1; 
     repl->abort(); 
    } 
    else 
    { 
     connect(repl, SIGNAL(downloadProgress(qint64,qint64)), SLOT(handle_new_data(qint64,qint64))); 
     connect(q, SIGNAL(finished(QNetworkReply*)), SLOT(compressed_file_request_finished(QNetworkReply*))); 
     QFile(path).rename(path + ".tmp"); 
    } 
} 
~lz_stream_decompressor() 
{ 
/*  if(repl) 
     delete repl; */ 
    lzma_end (&strm); 
} 
const short get_state() 
{ 
    return state; 
} 
signals: 
void finished(); 

public slots: 
void handle_new_data(qint64 bytesReceived, qint64 bytesTotal); 
void compressed_file_request_finished(QNetworkReply*); 
private: 
QNetworkReply *repl; 
QNetworkAccessManager *qnm; 
lzma_stream strm; 
const uint32_t flags; 
const uint64_t memory_limit; /* no memory limit */ 
short state; 
byte *in_buf; 
byte out_buf [OUT_BUF_MAX]; 
size_t in_len; /* length of useful data in in_buf */ 
size_t out_len; /* length of useful data in out_buf */ 
lzma_ret ret_xz; 
QString path; 
unsigned long &total_upd_size; 
}; 

और प्रतीति:

void lz_stream_decompressor::handle_new_data(qint64 bytesReceived, qint64 bytesTotal) 
{ 
if(repl->error() != QNetworkReply::NoError) 
{//TODO: handle error here 
    QFile(path).remove(); 
    QFile(path + ".tmp").rename(path); 
    return; 
} 
total_upd_size -= repl->bytesAvailable(); 
QByteArray data = repl->readAll(); 
in_len = data.size(); 
in_buf = (byte*)data.data(); 
strm.next_in = in_buf; 
strm.avail_in = in_len; 

do { 
    strm.next_out = out_buf; 
    strm.avail_out = OUT_BUF_MAX; 
    ret_xz = lzma_code (&strm, LZMA_RUN); 
    out_len = OUT_BUF_MAX - strm.avail_out; 
    QFile file(path); 
    if(file.open(QIODevice::WriteOnly | QIODevice::Append)) 
    { 
     file.write(QByteArray((char*)out_buf, (int)out_len)); 
     file.close(); 
    } 
    out_buf[0] = 0; 
} while (strm.avail_out == 0); 
} 

void lz_stream_decompressor::compressed_file_request_finished(QNetworkReply* repl) 
{ 
if(repl->error() != QNetworkReply::NoError) 
{//TODO: handle error here 
    QFile(path).remove(); 
    QFile(path + ".tmp").rename(path); 
    emit finished(); 
    return; 
} 
total_upd_size -= repl->bytesAvailable(); 
QByteArray data = repl->readAll(); 
in_len = data.size(); 
in_buf = (byte*)data.data(); 
strm.next_in = in_buf; 
strm.avail_in = in_len; 

do { 
    strm.next_out = out_buf; 
    strm.avail_out = OUT_BUF_MAX; 
    ret_xz = lzma_code (&strm, LZMA_FINISH); 
    out_len = OUT_BUF_MAX - strm.avail_out; 
    QFile file(path); 
    if(file.open(QIODevice::WriteOnly | QIODevice::Append)) 
    { 
     file.write(QByteArray((char*)out_buf, (int)out_len)); 
     file.close(); 
    } 
    out_buf[0] = 0; 
} while (strm.avail_out == 0); 
repl->deleteLater(); 
QFile(path + ".tmp").remove(); 
emit finished(); 
} 

यह सब पहले लिंक से उदाहरण के आधार पर, आपको असम्पीडित डेटा के साथ कुछ करने के लिए अपने कोड के साथ टिप्पणी कोड भागों को प्रतिस्थापित करने की आवश्यकता है।

मैं इस कोड

आप भी कनेक्ट करने के लिए "compressed_file_request_finished" स्लॉट qnetworkmanager का संकेत समाप्त करने के लिए असम्पीडित डेटा खत्म करने के लिए जरूरत के लिए किसी भी सुझाव को देखने के लिए चाहते हैं।

UPD5:

तय lzCompress और lzUncompress, लग रहा है ठीक अब handle_new_data में LZMA_FULL_FLUSH उपयोग करने के बारे में सुनिश्चित नहीं यकीन नहीं काम कर की तरह, के रूप में मैं पढ़ यह मैं क्या जरूरत है, लेकिन अभी भी, अब मैं मौजूदा कोड अनुकूल इस का उपयोग करने के लिए ...

UPD6:

/* read/write buffer sizes */ 
#define IN_BUF_MAX 409600 
#define OUT_BUF_MAX 409600 
/* analogous to xz CLI options: -0 to -9 */ 
#define COMPRESSION_LEVEL 7 

/* boolean setting, analogous to xz CLI option: -e */ 
#define COMPRESSION_EXTREME true 
0123:

आप भी कुछ इस तरह की जरूरत है इस कोड के काम के लिए दृश्य सीमा में

UPD7:

अद्यतन कोड, सभी परीक्षण किया है और काम कर रहा, मैं ने पाया है कि liblzma नहीं पूरी तरह से धागा सुरक्षित, मैं filelist की मल्टी-थ्रेडेड संपीड़न की कोशिश की। और यह अक्सर दुर्घटनाग्रस्त हो जाता है।

+1

धन्यवाद! –

+0

क्या आप इसके बजाय LZMA का उपयोग कर ऐसा करने में सक्षम हैं? –

उत्तर

7

इस पृष्ठ पर, आप lzma एसडीके जो अलग अलग भाषाओं में स्रोत कोड और कुछ बाइनरी प्रदान करता है मिलेगा:

  • भेजे संपीड़न हटाने में सी ++ स्रोत कोड का उपयोग करें: http://www.7-zip.org/sdk.html

    आप दो समाधान है प्रवाह

  • अद्यतन और पूर्ण समाधान के बहुत सारे के लिए अपने अनुप्रयोग में एक बाहरी उपकरण के रूप में विकोडक बाइनरी का प्रयोग करें
+0

thx जानकारी के लिए, वर्तमान में मुझे एक और समाधान मिला, मैं qtetworkmanager पर qtetworkmanager के आधार पर xz-utils से cnetworkmanager लिख रहा हूं (xz-utils से कोड उदाहरण मेरे लिए समझना आसान लगता है), मैं यहां कोड पोस्ट करूंगा जब मैंने किया । – sss123next

+0

@Patrice Bernassola कोई सुझाव? – sss123next

+0

क्या आपके पास पोस्ट किए गए कोड के साथ कोई समस्या है? –

संबंधित मुद्दे