J'ai un gros problème avec le ciblage gzipstream .Net 3.5. C'est la première fois que je travaille avec gzipstream, mais j'ai modélisé après un certain nombre de tutoriels, y compris here et je suis toujours coincé.GZipStream - écrit n'écrit pas toutes les données compressées même avec flush?
Mon application sérialise une datatable à xml et insère dans une base de données, stockant les données compressées dans un champ varbinary (max) ainsi que la longueur d'origine du tampon non compressé. Ensuite, quand j'en ai besoin, je récupère ces données et les décomprime et recrée le datatable. Le décompresseur est ce qui semble échouer.
EDIT: Malheureusement après avoir changé le GetBuffer à ToArray comme suggéré, mon problème reste. Code mis à jour ci-dessous
Code Compress:
DataTable dt = new DataTable("MyUnit");
//do stuff with dt
//okay... now compress the table
using (MemoryStream xmlstream = new MemoryStream())
{
//instead of stream, use xmlwriter?
System.Xml.XmlWriterSettings settings = new System.Xml.XmlWriterSettings();
settings.Encoding = Encoding.GetEncoding(1252);
settings.Indent = false;
System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create(xmlstream, settings);
try
{
dt.WriteXml(writer);
writer.Flush();
}
catch (ArgumentException)
{
//likely an encoding issue... okay, base64 encode it
var base64 = Convert.ToBase64String(xmlstream.ToArray());
xmlstream.Write(Encoding.GetEncoding(1252).GetBytes(base64), 0, Encoding.GetEncoding(1252).GetBytes(base64).Length);
}
using (MemoryStream zipstream = new MemoryStream())
{
GZipStream zip = new GZipStream(zipstream, CompressionMode.Compress);
log.DebugFormat("Compressing commands...");
zip.Write(xmlstream.GetBuffer(), 0, xmlstream.ToArray().Length);
zip.Flush();
float ratio = (float)zipstream.ToArray().Length/(float)xmlstream.ToArray().Length;
log.InfoFormat("Resulting compressed size is {0:P2} of original", ratio);
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandText = "INSERT INTO tinydup (lastid, command, compressedlength) VALUES (@lastid,@compressed,@length)";
cmd.Connection = db;
cmd.Parameters.Add("@lastid", SqlDbType.Int).Value = lastid;
cmd.Parameters.Add("@compressed", SqlDbType.VarBinary).Value = zipstream.ToArray();
cmd.Parameters.Add("@length", SqlDbType.Int).Value = xmlstream.ToArray().Length;
cmd.ExecuteNonQuery();
}
}
Code Décompresser:
/* This is an encapsulation of what I get from the database
public class DupUnit{
public uint lastid;
public uint complength;
public byte[] compressed;
}*/
//I have already retrieved my list of work to do from the database in a List<Dupunit> dupunits
foreach (DupUnit unit in dupunits)
{
DataSet ds = new DataSet();
//DataTable dt = new DataTable();
//uncompress and extract to original datatable
try
{
using (MemoryStream zipstream = new MemoryStream(unit.compressed))
{
GZipStream zip = new GZipStream(zipstream, CompressionMode.Decompress);
byte[] xmlbits = new byte[unit.complength];
//WHY ARE YOU ALWAYS 0!!!!!!!!
int bytesdecompressed = zip.Read(xmlbits, 0, unit.compressed.Length);
MemoryStream xmlstream = new MemoryStream(xmlbits);
log.DebugFormat("Uncompressed XML against {0} is: {1}", m_source.DSN, Encoding.GetEncoding(1252).GetString(xmlstream.ToArray()));
try{
ds.ReadXml(xmlstream);
}catch(Exception)
{
//it may have been base64 encoded... decode first.
ds.ReadXml(Encoding.GetEncoding(1254).GetString(
Convert.FromBase64String(
Encoding.GetEncoding(1254).GetString(xmlstream.ToArray())))
);
}
xmlstream.Dispose();
}
}
catch (Exception e)
{
log.Error(e);
Thread.Sleep(1000);//sleep a sec!
continue;
}
Notez le commentaire ci-dessus ... bytesdecompressed est toujours 0. Toutes les idées? Est-ce que je le fais mal?
EDIT 2:
C'est donc bizarre. J'ai ajouté le code de débogage suivant à la routine de décompression:
GZipStream zip = new GZipStream(zipstream, CompressionMode.Decompress);
byte[] xmlbits = new byte[unit.complength];
int offset = 0;
while (zip.CanRead && offset < xmlbits.Length)
{
while (zip.Read(xmlbits, offset, 1) == 0) ;
offset++;
}
Lors du débogage, parfois cette boucle compléterait, mais d'autres fois il pendrait. Quand j'arrêterais le débogage, ce serait à l'octet 1600 sur 1616. Je continuerais, mais ça ne bougerait pas du tout.
EDIT 3: Le bogue semble être dans le code de compression. Pour une raison quelconque, il ne sauvegarde pas toutes les données. Lorsque j'essaie de décompresser les données à l'aide d'un mécanisme gzip tiers, je ne reçois qu'une partie des données d'origine.
Je commencerais une prime, mais je ne vois vraiment pas beaucoup de réputation de donner dès maintenant :-(
Excellent commentaire. Je vais faire cet ajustement et voir comment ça se passe. – longofest
Donc, c'était apparemment un problème, mais pas le problème ... mise à jour de la question d'origine maintenant avec le dernier code, mais toujours obtenir 0 pour lire décompressé. – longofest
... mais j'ai eu quelques fois plus que j'ai utilisé le tampon au lieu de toarray ... hmm ... laissez-moi travailler un peu plus ... – longofest