0

私のアプリケーションには、データベースからデータをエクスポートする機能があります。IonicZIPライブラリを使用してデータを含むzipファイルを作成します。

このプロセスは、それぞれ1,000行のページでデータを取得することによって機能します。取得されたデータには、データの行ごとに2つの画像(JPEG)が含まれています。「エクスポート」は、HTMLテーブルを含むHTMLファイルで構成されます。この表には、各行の重要な情報と画像へのリンクが含まれています。各画像はJPEGファイルとしてZIPファイルに保存されます。記述されたHTMLには、適切な画像ファイルにリンクするアンカータグが含まれています。

すべてが機能しますが、最近、OutOfMemoryException多数の行をエクスポートするときにがスローされることがわかりました(問題を見つけた場合は24,000を超えます)。私のコードを見ると、明らかなリークは見られません(または、これを投稿しませんか?;))

エクスポートされるデータを出力するメソッドは次のとおりです。

private void OutputReads( StreamWriter writer, ZipFile zipFile, BackgroundWorker worker, ExportArgs args ) {
    int ReadCount = Math.Min( args.ReadMatches, args.ResultsLimit );

    writer.WriteLine( "<h2>Matching Reads:</h2>" );
    writer.WriteLine( "<p>Number in Database: {0}</p>", args.ReadMatches.ToString( "#,##0" ) );
    writer.WriteLine( "<p>Number in Report:   {0}</p>",      ReadCount  .ToString( "#,##0" ) );
    writer.WriteLine();

    if ( args.ReadMatches == 0 ) {
        return;
    }

    writer.WriteLine( "<table border=\"1\" cellspacing=\"0\" bordercolordark=\"black\" bordercolorlight=\"black\">" );
    writer.WriteLine( "<tr>" );
    writer.WriteLine( "<th width=\"110\"><b>Plate</b></th>" );
    writer.WriteLine( "<th width=\"60\"><b>State</b></th>" );
    writer.WriteLine( "<th width=\"200\"><b>Date / Time</b></th>" );
    writer.WriteLine( "<th width=\"142\"><b>Latitude</b?</th> " );
    writer.WriteLine( "<th width=\"142\"><b>Longitude</b?</th> " );
    writer.WriteLine( "<th width=\"125\"><b>Alarm Class</b></th>" );
    writer.WriteLine( "<th width=\"150\"><b>Notes</b></th>" );
    writer.WriteLine( "<th width=\"150\"><b>Officer Notes</b></th>" );
    writer.WriteLine( "<th width=\"150\"><b>Images</b></th>" );
    writer.WriteLine( "</tr>" );

    int noPages = ReadCount / args.PageSize + ( ReadCount % args.PageSize == 0 ? 0 : 1 );

    for ( int pageNo = 0, count = 0; pageNo < noPages; pageNo++ ) {
        if ( worker.CancellationPending ) {
            return;
        }

        ReadViewModel[] reads = null;

        try {
            reads = DataInterface.GetReads( args.LocaleCode, args.Plate, 
                                            args.StartDate, args.EndDate, 
                                            args.AlarmClasses, args.HotListId, 
                                            args.PageSize, pageNo
                                          );

        } catch ( DataAccessException ex ) {
            . . .
        } catch ( ThreadAbortException ) {
            // The thread is stopping.  Stop processing now.

        } catch ( Exception ex ) {
            . . .
        }

        foreach ( ReadViewModel read in reads ) {
            if ( worker.CancellationPending ) {
                return;
            }

            writer.WriteLine( "<tr>" );
            writer.WriteLine( "<td width=\"110\"><p align=\"left\" style=\"text-align:left\">{0}</p></td>"    , read.Plate );
            writer.WriteLine( "<td width=\"60\" ><p align=\"center\" style=\"text-align:center\">{0}</p></td>", read.State );
            writer.WriteLine( "<td width=\"150\"><p align=\"center\" style=\"text-align:center\">{0}</p></td>", read.TimeStamp );
            writer.WriteLine( "<td width=\"125\"><p align=\"center\" style=\"text-align:center\">{0}</p></td>", read.GPSInformation == null ? "&nbsp;" : read.GPSInformation.Position.Latitude.ToString(  "##0.000000" ) );
            writer.WriteLine( "<td width=\"125\"><p align=\"center\" style=\"text-align:center\">{0}</p></td>", read.GPSInformation == null ? "&nbsp;" : read.GPSInformation.Position.Longitude.ToString( "##0.000000" ) );
            writer.WriteLine( "<td width=\"125\"><p align=\"center\" style=\"text-align:center\">{0}</p></td>", read.AlarmClass     == null ? "&nbsp;" : read.AlarmClass );
            writer.WriteLine( "<td width=\"150\"><p align=\"left\" style=\"text-align:left\">{0}</p></td>"    , read.       Notes   == null ? "&nbsp;" : read.       Notes );
            writer.WriteLine( "<td width=\"150\"><p align=\"left\" style=\"text-align:left\">{0}</p></td>"    , read.OfficerNotes   == null ? "&nbsp;" : read.OfficerNotes );

            if ( read.ImageData == null ) {
                try {
                    DataInterface.GetPlateImage( read );
                } catch ( DataAccessException ex ) {
                    . . .
                } catch ( Exception ex ) {
                    . . .
                }
            }

            if ( read.OverviewImages == null ) {
                try {
                    DataInterface.GetOverviewImages( read );
                } catch ( DataAccessException ex ) {
                    . . .
                } catch ( Exception ex ) {
                    . . .
                }
            }

            if ( read.ImageData != null ) {
                string ext = LPRCore.CarSystem.ImageDataAccessor.GetImageFileExtension( read.ImageData );
                writer.Write( "<td width=\"150\"><p align=\"left\" style=\"text-align:left\"><a href=\".\\Images\\{0}.{1}\" target=\"_blank\">BW</a>", read.ID.ToString( "N" ), ext );

                string fileName = string.Format( ".\\Images\\{0}{1}", read.ID.ToString( "N" ), ext );

                if ( !zipFile.ContainsEntry( fileName ) ) {
                    zipFile.AddEntry( fileName, read.ImageData );
                }
            } else {
                writer.Write( "No Plate Image" );
            }

            if ( read.OverviewImages != null && read.OverviewImages.Length > 0 ) {
                for ( int i = 0; i < read.OverviewImages.Length; i++ ) {
                    string ext = LPRCore.CarSystem.ImageDataAccessor.GetImageFileExtension( read.OverviewImages[ i ].ImageData );
                    writer.Write( " - <a href=\".\\Images\\{0}_C{1}{2}\" target=\"_blank\">Color {1}</a>", read.ID.ToString( "N" ), i == 0 ? string.Empty : i.ToString(), ext );

                    string fileName = string.Format( ".\\Images\\{0}_c{1}{2}", read.ID.ToString( "N" ), i == 0 ? string.Empty : i.ToString(), ext );
                    if ( !zipFile.ContainsEntry( fileName ) ) {
                        zipFile.AddEntry( fileName, read.OverviewImages[ i ].ImageData );
                    }
                }
            } else {
                writer.Write( "No Overview Images" );
            }

            writer.WriteLine( "</p></td>" );
            writer.WriteLine( "</tr>" );
            count++;
            worker.ReportProgress( count, args );
        }
    }
    writer.WriteLine( "</table>" );
    writer.WriteLine();
}

Zipファイルはディスクなどにフラッシュされておらず、行が処理されるにつれてどんどん大きくなっていくので、おそらく問題だと思います。

zipファイルをディスクにフラッシュしてすべてのイメージを解放してガベージコレクターがそれらを解放する方法はありますか、またはこのライブラリを使用してより少ないメモリを使用してzipファイルを構築する別の方法はありますか?

4

1 に答える 1

0

ここで別の開発者の助けを借りて、これを修正することができました。

DotNetZip ライブラリは、ZipFile.AddEntry型のデリゲートをWriteDelegateパラメーターとして受け取るメソッドのオーバーロードを定義します。デリゲートには、ファイルの名前とStream、ファイルの内容をパラメーターとして書き込む必要がある が渡されます。

コードで次のメソッドを定義しましたGetImageBytes

private void GetImageBytes( string entryName, Stream stream ) {
    Guid imageId;
    Guid.TryParse( Path.GetFileName( entryName ).Substring( 0, 32 ), out imageId );
    using ( BinaryWriter writer = new BinaryWriter( stream ) ) {
        try {
            writer.Write( DataInterface.GetImageData( imageId ) );

        } catch ( DataAccessException ex ) {
            DbMonitor.HandleDatabaseError( ex );

        } catch ( Exception ex ) {
            . . .
        }
    }
}

これを機能させるには、データベース内の画像の ID をファイル名にエンコードする必要がありました。このコードは、ファイル名から ID を解析し、サービス層のメソッドを呼び出してデータベースからイメージ バイトを取得します。最後に、 を作成しBinaryWriter、画像データを に送信しますStream

私のプログラムは、24,000 行以上のデータをエクスポートでき、OutOfMemoryException.

于 2013-03-12T19:19:24.480 に答える