简体   繁体   中英

Can't read file after writing it to temp folder in .NET Core

In my scenario, I have an use case where I must received a compressed file, do some validations and then find a specific file within the archive that I'll have to handle through a third-party library. I'm having some trouble getting such library to read the file though. This is what I came up with so far:

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);
            }
        }
    }
}

Take notice that I'm using the "old way" of copying streams as Stream.CopyTo and Stream.CopyToAsync were creating empty files, explicitly calling fileStream.Close() looks like the only way to get the bytes into the file somehow, but that's beyond my point. Regardless, after closing the stream , upon calling featureSource.Open() my application throws

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

tmpE926.tmp being different every time, obviously. Also take notice that I'm creating a file because the constructor for ShapeFileFeatureSource demands not a stream, not a byte array, but a path.

A much shorter implementation

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);
        }
    }
}

will actually amount to the same error. I honestly don't think the problem lies within this library, but rather I'm the one screwing it up somehow. Does anyone have any ideas or should I contact the vendor's (unresponsive) tech support?

Edit: Just in case, this is such library Install-Package ThinkGeo.UI.WebApi but you have to subscribe to evaluate in order to use it.

I could not find package for .NET Core with such classes, so I reproduced it through .NET Framework Nuget package. My answer mostly demonstrates how to deal with streams. It would be hard to tell what is wrong with your code, without having access to library you have

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: installed trial version of ThinkGeo library, instead of unauthorized exception it gives me FileNotFoundException with given 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 ? So I thought I should dig into this way

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

I tried to find any reference to the idx file it wants, it has property IndexFilePathName , but unfortunately, I am out of luck. (Also tried different folder, so it is not 'Temp' folder issue) 在此处输入图片说明

This code morphed for a couple of days until I reached out to tech support, they tinkered with it a bit and came up with this:

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);
                }
            }
        }
    }
}

It works. I'm happy.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM