简体   繁体   English

将文件写入 .NET Core 中的临时文件夹后无法读取文件

[英]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.请注意,我正在使用复制流的“旧方法”,因为Stream.CopyToStream.CopyToAsync正在创建空文件,显式调用fileStream.Close()看起来像是以某种方式将字节放入文件的唯一方法,但是这超出了我的意思。 Regardless, after closing the stream , upon calling featureSource.Open() my application throws无论如何,在关闭流后,调用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 being different every time, obviously. tmpE926.tmp都不同,很明显。 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.还要注意,我正在创建一个文件,因为ShapeFileFeatureSource的构造函数需要的不是流,也不是字节数组,而是路径。

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.编辑:以防万一,这是这样的库Install-Package ThinkGeo.UI.WebApi但你必须订阅评估才能使用它。

I could not find package for .NET Core with such classes, so I reproduced it through .NET Framework Nuget package.我找不到带有此类类的 .NET Core 包,因此我通过 .NET Framework Nuget 包复制了它。 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 UPD:安装了 ThinkGeo 库的试用版,而不是未经授权的异常,它给我FileNotFoundException和给定的堆栈跟踪

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 ? 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.我试图找到它想要的 idx 文件的任何引用,它具有属性IndexFilePathName ,但不幸的是,我运气不好。 (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.我很高兴。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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