Управление (создание удаления) огромным количеством временных файлов с помощью C # - PullRequest
0 голосов
/ 07 мая 2019

Я оптимизирую приложение для интенсивного использования диска, которое генерирует много временных файлов, но мне приходится каждый день чистить папки, потому что у нас ограниченное хранилище. Итак, мне интересно, как лучше всего это сделать. Файлы находятся на сетевом диске, доступ к которому осуществляется через виртуальную папку в IIS, поэтому они выглядят как часть собственных папок сайта.

У меня есть онлайн-редактор PDF, использующий Aspose.PDF для .Net. При использовании приложения оно генерирует много временных файлов, но отображает представление только тогда, когда все они созданы. Поэтому я создаю временный файл, используя предложение Parallel.For, ограниченное количеством процессоров, доступных на компьютере.

Первоначально это делалось последовательно, и с учетом того, что для каждой страницы это занимает от 1 до 3 секунд в зависимости от качества страницы (ограничение ограничений не может быть оптимизировано), требуется слишком много времени для завершения. Мне удалось распараллелить операцию, но время все еще слишком велико.

С другой стороны, у меня есть процедура, которая удаляет все файлы старше 24 часов (86400 секунд) в нескольких каталогах. Сначала это делалось при каждом запросе пользователя (загрузка страницы), поэтому он выполнялся несколько раз в течение жизненного цикла страницы, каждый раз удаляя только кучу файлов. Все пулы приложений IIS перерабатываются ежедневно в 00 часов, поэтому сейчас я делаю это с помощью Application_Start, но я боюсь, что это замедлит первый пользовательский запрос, поскольку ему нужно удалить около 45 тысяч файлов (сегодня приложение имеет был использован в течение 7 часов и уже 30 тысяч файлов). Мне интересно, если лучший способ сделать следующее:

-Удалите старые файлы на Session_End (скажем, удалите файлы старше 4 часов)

-Обрать все остальные, если они есть, в Application_End (старше 24 часов).

Кроме того, эти подпрограммы вызываются с помощью асинхронных задач, при условии, что мне не нужно ждать их завершения.

Для удаления я использую System.IO.FileInfo.Delete () в цикле for.

Процесс создания временных файлов

     Parallel.For(0, TotalPages, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }, pageCount =>
                 {
                     using (MemoryStream imageStream = new MemoryStream())
                     {
                         var po = new PageObject();
                         var idx = pageCount + 1;
                         PngDevice p = new PngDevice(); // bajamos un poco la resolución
                         p.RenderingOptions.UseNewImagingEngine = true;
                         p.Process(doc.Pages[idx], imageStream);   //  esta instrucción demora cerca de 1 segundo
                                                                   //System.Drawing.Image image = System.Drawing.Image.FromStream(imageStream);
                                                                   //ScaleImage(image, 1138, 760, path_base + fileMask + "-" + idx + ".png", out height, out Aratio);
                                                                   //image.Dispose();
                         using (System.Drawing.Image image = System.Drawing.Image.FromStream(imageStream))
                         {
//this scales the image and writes it to a disc
                             ScaleImage(image, 1138, 760, path_base + fileMask + "-" + idx + ".png", out height, out Aratio);
                         }

                         if (idx == 1) { fields = CheckFields(doc, idx, "image" + fileMask + "-" + idx + ".png", fields, Convert.ToDouble(Aratio)); }
                         po.pageNumber = idx;
                         po.pageName = "image" + fileMask + "-" + idx + ".png";
                         po.Height = height;
                         po.Ratio = Aratio;
                         lpages.Add(po);
                     }
                 });

Запись файла

protected static void ScaleImage(System.Drawing.Image image, int maxWidth, int maxHeight, string path, out string height, out string Aratio)
        {
            var ratio = (double)maxWidth / image.Width;
            Aratio = ratio.ToString();
            var newWidth = (int)(image.Width * ratio);
            var newHeight = (int)(image.Height * ratio);
            height = newHeight.ToString();
            //var newImage = new Bitmap(newWidth, newHeight);
            using (var newImage = new Bitmap(newWidth, newHeight))
            {
                Graphics.FromImage(newImage).DrawImage(image, 0, 0, newWidth, newHeight);
                using (var bmp = new Bitmap(newImage))
                {
                    bmp.Save(path, ImageFormat.Png);
                }
            }
            //newImage.Dispose();
        }

Процесс очистки (имена переменных на испанском языке)

    private static int _segundos = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["PeriodoLimpiezaTemp"].ToString());

    public static void LimpiarTemporales(string rutaTemporal = "", string mask = "*", int? segundos = null)
    {
        int time = segundos ?? _segundos;

        System.Threading.Tasks.Task.Run(
            () =>
            {
                rutaTemporal = string.IsNullOrEmpty(rutaTemporal) ? Path.GetTempPath() : rutaTemporal;
                var dInfo = new DirectoryInfo(rutaTemporal);
                var files = dInfo.GetFiles(mask);
                foreach (var file in files)
                {
                    var dif = (DateTime.Now - file.CreationTime);
                    if (dif.TotalSeconds >= time )
                    {
                        try
                        { //Intenta el eliminar los temporales. Si no puede sigue de largo.
                            file.Delete();
                        }
                        catch
                        {
                            //do nothing. Just in case some file it's been used by another process. I don't care if any file is left here, the next run may delete it.
                        }
                    }
                };
            });
    }

Где я хочу использовать его в Global.asax

    protected void Session_End()
    {
        int segundos = 14400;
        LimpiarTemporales(segundos);
    }

    protected void Application_End()
    {
        LimpiarTemporales();
    }

Какой лучший подход для создания временных файлов? (Учитывая, что я должен создать их перед рендерингом ...)

А лучший подход к управлению удалением?

Любое предложение приветствуется

...