Ну, есть несколько вещей, которыми вы еще не избавились, которые могут вызвать проблему.Во-первых, DataTable
реализует IDisposable
, как и PdfWriter
.
. Для PdfWriter
вам не нужно это как объявление переменной, так как вы на самом деле его не используетев любом случае, вы можете просто обработать это как
using (PdfWriter.GetInstance(pdfDoc, msReport))
{
// ...
}
. Стоит заметить, что вы в настоящее время постоянно воссоздаете шрифты fontH1
и fontH2
внутри цикла for.Я на самом деле не вижу необходимости, они не меняются в течение всего запуска вашей программы, поэтому вы можете объявить их вне вашего цикла как локальные переменные или как часть статического поля внутри вашего класса, создавая PDF.
Другое дело, что вы, кажется, воссоздаете один и тот же объект данных снова и снова, теперь я могу предположить, что для вашего текущего кода это просто фиктивный код, но, как я вижу, он вам не нуженчтобы создать datatable внутри вашего цикла, я скорее думаю, что это может быть аргументом для создания вашего pdf файла (как и имени файла), так что вы можете переписать свой код для создания pdf в его собственном классе (я назвал его PdfModule
но я держу пари, что для него есть намного лучшие названия :)), и реструктурирую ваш код для обработки 1 файла за один раз, например, так:
public class PdfModule
{
private static readonly Font H1Font = new Font(Font.FontFamily.HELVETICA, 6, Font.BOLDITALIC);
private static readonly Font H2Font = new Font(Font.FontFamily.HELVETICA, 6, Font.ITALIC);
public static void CreateFile(string filename, DataTable data)
{
using (var msReport = new FileStream(filename, FileMode.Create, FileAccess.Write))
{
using (var pdfDoc = new Document(PageSize.A5.Rotate(), 10f, 10f, 200f, 40f))
{
using (PdfWriter.GetInstance(pdfDoc, msReport))
{
pdfDoc.Open();
var table = new PdfPTable(data.Columns.Count)
{
WidthPercentage = 100,
HeaderRows = 1
};
for (var k = 0; k < data.Columns.Count; k++)
{
var str =
System.Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(data
.Columns[k].ColumnName.Replace("_", " ").ToLower());
;
var cell = new PdfPCell(new Phrase(str, H1Font))
{
HorizontalAlignment = Element.ALIGN_CENTER,
VerticalAlignment = Element.ALIGN_CENTER
};
table.AddCell(cell);
}
for (var i = 0; i < data.Rows.Count; i++)
{
for (var j = 0; j < data.Columns.Count; j++)
{
var cell =
new PdfPCell(new Phrase(data.Rows[i][j].ToString(), H2Font))
{
VerticalAlignment = Element.ALIGN_CENTER,
HorizontalAlignment = data.Columns[j].DataType == typeof(decimal)
? Element.ALIGN_RIGHT
: Element.ALIGN_LEFT
};
table.AddCell(cell);
}
}
pdfDoc.Add(table);
pdfDoc.Close();
}
}
}
}
}
Это сохранит объявление шрифта как статическоеполя на уровне класса, поэтому инициализируем их только один раз во время выполнения программ, и записываем 1 отдельный файл с 1 одиночным DataTable
строительствомдо документа.Оба посылаются в качестве аргументов.
Чтобы затем использовать этот класс, я написал следующий пример кода, и он, похоже, генерирует 100 000 файлов довольно быстро (не где-то рядом с 5 часами, которые вы упомянули).
Обратите внимание, что у меня нет подробной информации о том, как вы обрабатываете / заполняете данные в вашей реальной программе, но, по крайней мере, это даст вам основную идею о том, как реструктурировать ваш код, и перейдите оттуда
internal class Program
{
private static DataTable CreateDataTable( IEnumerable<object[]> rawData )
{
var datatable = new DataTable();
datatable.Columns.Add("INVOICE_NO");
datatable.Columns.Add("INVOICE_DATE");
datatable.Columns.Add("CODE");
datatable.Columns.Add("SERVICE_DESCRIPTION");
datatable.Columns.Add("QTY", typeof(decimal));
datatable.Columns.Add("UNIT_PRICE", typeof(decimal));
datatable.Columns.Add("GROSS", typeof(decimal));
datatable.Columns.Add("DISCOUNT", typeof(decimal));
datatable.Columns.Add("NET", typeof(decimal));
datatable.Columns.Add("DEDUCTION", typeof(decimal));
datatable.Columns.Add("NET_PAYABLE_WITHOUT_VAT", typeof(decimal));
datatable.Columns.Add("VAT", typeof(decimal));
datatable.Columns.Add("NET_PAYABLE_WITH_VAT", typeof(decimal));
foreach (var row in rawData)
{
datatable.Rows.Add(row);
}
return datatable;
}
public static void Main(string[] args)
{
var rowData = new List<object[]>()
{
new object[] { "CR100005", "25-05-1989", "CPT004", "SERVICE005", 1, 10, 100, 10, 90,
45, 45, 5, 50 },
new object[] { "CR100006", "25-05-1992", "CPT00555", "SERVICE105", 6, 60, 600, 60,
450, 45, 45, 5, 500 }
};
var pdfModule = new PdfModule();
var outDirectory = Path.Combine(Environment.CurrentDirectory, "Output");
if (!Directory.Exists(outDirectory))
{
// well theoretically I should just create the directory and worry about conflicts differently
Directory.CreateDirectory(outDirectory);
}
Console.WriteLine( $"Creating files to {outDirectory}");
var nrOfFiles = 100000;
var stepCount = 1000;
for (var i = 0; i < nrOfFiles; i++)
{
if (i % stepCount == 0)
{
Console.WriteLine($"Creating files {i}-{i+stepCount-1}" );
}
var filename = Path.Combine(outDirectory, $"{i}.pdf");
using (var dataTable = CreateDataTable(rowData))
{
pdfModule.CreateFile(filename, dataTable);
}
}
Console.WriteLine($"Done, created {nrOfFiles} files");
}
}
В остальном я не уверен, что моя среда совпадает с вашей, но она работала согласованно (вызывая уведомления ITextSharp
, что у меня нет действующей лицензии AGPL ^ _ ^), и я ее запускалпод Linux с помощью Rider IDE