Не могу прочитать файл после записи во временную папку. NET Core - PullRequest
0 голосов
/ 14 февраля 2020

В моем сценарии у меня есть сценарий использования, когда я должен получить сжатый файл, выполнить некоторые проверки и затем найти указанный файл c в архиве, который мне придется обрабатывать через стороннюю библиотеку. У меня возникли проблемы с получением такой библиотеки для чтения файла, хотя. Это то, что я придумал до сих пор:

public async Task ShapeIt(ZipArchive archive)
{
    foreach (var entry in archive.Entries)
    {
        if (Path.GetExtension(entry.FullName).Equals(".shp"))
        {
            var stream = entry.Open();
            using var ms = new MemoryStream();
            await stream.CopyToAsync(ms);
            ms.Position = 0;
            var fileName = Path.GetTempFileName();
            try
            {
                using var fileStream = File.Open(fileName, FileMode.OpenOrCreate, FileAccess.Write, 
                    FileShare.ReadWrite);

                var bytes = new byte[ms.Length];
                ms.Read(bytes, 0, (int)ms.Length);
                fileStream.Write(bytes, 0, bytes.Length);
                fileStream.Flush();
                fileStream.Close();

                var featureSource = new ShapeFileFeatureSource(fileName); // Class from 3rd-party
                featureSource.Open();
                // Do my stuff with the shapefile
            }
            finally
            {
                File.Delete(fileName);
            }
        }
    }
}

Обратите внимание, что я использую «старый способ» копирования потоков, поскольку Stream.CopyTo и Stream.CopyToAsync создавали пустые файлы, явно вызывая fileStream.Close() выглядит как единственный способ вставить байты в файл каким-то образом, но это не моя точка зрения. Независимо от того, после закрытия потока , после вызова featureSource.Open() мое приложение выбрасывает

"The process cannot access the file 'C:\\Users\\me\\AppData\\Local\\Temp\\tmpE926.tmp' because it is
being used by another process."

tmpE926.tmp каждый раз, очевидно, очевидно. Также обратите внимание, что я создаю файл, потому что конструктор для ShapeFileFeatureSource требует не потока, не байтового массива, а пути.

Гораздо более короткая реализация

public async Task ShapeIt(ZipArchive archive)
{
    foreach (var entry in archive.Entries)
    {
        var tempFile = Path.GetTempFileName();
        try
        {
            entry.ExtractToFile(tempFile, true);

            if (Path.GetExtension(entry.FullName).Equals(".shp"))
            {
                var featureSource = new ShapeFileFeatureSource(tempFile);
                featureSource.Open();
                var type = featureSource.GetShapeFileType();
            }
        }
        finally
        {
            File.Delete(tempFile);
        }
    }
}

фактически приведет к той же ошибке. Я, честно говоря, не думаю, что проблема заключается в этой библиотеке, скорее я как-то облажался. У кого-нибудь есть какие-либо идеи или мне следует обратиться в службу поддержки поставщика (без ответа)?

Редактировать: На всякий случай, это такая библиотека Install-Package ThinkGeo.UI.WebApi, но для ее использования необходимо подписаться на оценку, чтобы ее использовать.

Ответы [ 2 ]

1 голос
/ 14 февраля 2020

Я не смог найти пакет для. NET Ядро с такими классами, поэтому я воспроизвел его через. NET Framework Nuget package. Мой ответ в основном демонстрирует, как бороться с потоками. Было бы трудно сказать, что не так с вашим кодом, без доступа к библиотеке у вас есть

using DotSpatial.Data;
using System.IO;
using System.IO.Compression;

namespace ConsoleApp12
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var fs = File.OpenRead(@"C:\Users\jjjjjjjjjjjj\Downloads\1270055001_mb_2011_vic_shape.zip"))
            using (var zipFile = new ZipArchive(fs))
            {
                foreach (var entry in zipFile.Entries)
                {
                    if (entry.FullName.EndsWith(".shp"))
                    {
                        var tempFile = Path.GetTempFileName();
                        try
                        {
                            using (var entryStream = entry.Open())
                            using (var newFileStream = File.OpenWrite(tempFile))
                            {
                                entryStream.CopyTo(newFileStream);
                            }
                            var featureSource = ShapefileFeatureSource.Open(tempFile);
                            var type = featureSource.ShapeType;
                        }
                        finally
                        {
                            File.Delete(tempFile);
                        }
                    }
                }
            }
        }
    }
}

UPD: установленная пробная версия библиотеки ThinkGeo, вместо несанкционированного исключения она дает мне FileNotFoundException с заданным stacktrace

at ThinkGeo.Core.ValidatorHelper.CheckFileIsExist(String pathFilename)
at ThinkGeo.Core.ShapeFileIndex.xh8=(FileAccess readWriteMode)
^^^^^^^^^^^^^^^^^^^^^^^^^ Are we supposed to have index?
at ThinkGeo.Core.ShapeFile.xh8=(FileAccess readWriteMode)
at ThinkGeo.Core.ShapeFileFeatureSource.WjE=()
at ThinkGeo.Core.ShapeFileFeatureSource.OpenCore()
at ThinkGeo.Core.FeatureSource.Open()
at ConsoleApp20.Program.Main(String[] args) in 
C:\Users\jjjjjjjjjjjj\source\repos\ConsoleApp20\ConsoleApp20\Program.cs:line 45

ShapeFileIndex? Поэтому я подумал, что мне нужно покопаться в этом

var featureSource = new ShapeFileFeatureSource(tempFile);
featureSource.RequireIndex = false; // no luck
featureSource.Open();

Я пытался найти любую ссылку на нужный файл idx, он имеет свойство IndexFilePathName, но, к сожалению, мне не повезло. (Также пробовал другую папку, так что это не проблема папки Temp) enter image description here

0 голосов
/ 19 февраля 2020

Этот код трансформировался на пару дней, пока я не обратился в службу технической поддержки, они немного поработали с ним и придумали следующее:

public async Task ProcessFile(IFormFile file)
{
    if (!Path.GetExtension(file.FileName).Equals(".zip"))
        throw new System.Exception("File should be compressed in '.zip' format");

    var filePaths = new List<string>();

    using (var stream = new MemoryStream())
    {
        await file.CopyToAsync(stream);

        using (var archive = new ZipArchive(stream, ZipArchiveMode.Read, false))
        {

            var replaceList = new Dictionary<string, string>();

            foreach (ZipArchiveEntry entry in archive.Entries)
            {
                var tempPath = Path.GetTempFileName();

                string key = Path.GetFileNameWithoutExtension(entry.FullName);

                string value = Path.GetFileNameWithoutExtension(tempPath);

                if (replaceList.ContainsKey(key))
                {
                    value = replaceList[key];
                }
                else
                {
                    replaceList.Add(key, value);
                }

                string unzippedPath = Path.Combine(Path.GetDirectoryName(tempPath), value + Path.GetExtension(entry.FullName));

                entry.ExtractToFile(unzippedPath, true);
                filePaths.Add(unzippedPath);
            }

            foreach (var unzippedPath in filePaths)
            {
                if (Path.GetExtension(unzippedPath).Equals(".shp"))
                {
                    // Successfully doing third-party library stuff
                }
            }

            foreach (var unzippedPath in filePaths)
            {
                if (File.Exists(unzippedPath))
                {
                    File.Delete(unzippedPath);
                }
            }
        }
    }
}

Это работает. Я счастлив.

...