Unable to unzip archive .NET framework

68 Views Asked by At

I am working on a WPF project on .NET framework so I cant use the latest assembly of System.IO.ZipFile`. The problem seems trivial but it's taking my day away.

I have this task:

public async Task SetupEnvironment(IProgressReporter progressReporter)
{
    string basePath = AppDomain.CurrentDomain.BaseDirectory;
    string pythonExePath = System.IO.Path.Combine(basePath, @"CPython\python-embed\python.exe");

    if (!File.Exists(pythonExePath))
    {
        progressReporter.ReportProgress($"Python environment not found. Setting up environment in {basePath}");
        Thread.Sleep(300);
        string zipFilePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"CPython\python.zip");
        //string extractPath = System.IO.Path.Combine(basePath, @"CPython");
        string extractPath = @"C:\Data\python";

        try
        {
            progressReporter.ReportProgress($"exctraxcting environment ");
            //ZipFile.ExtractToDirectory(zipFilePath, extractPath);
            using (ZipArchive archive = ZipFile.Open(zipFilePath, ZipArchiveMode.Read))
            {
                foreach (ZipArchiveEntry entry in archive.Entries)
                {
                    if (progressReporter != null)
                    {
                        progressReporter.ReportProgress($"exctraxcting {entry.Name}");
                    }

                    entry.ExtractToFile(System.IO.Path.Combine(extractPath, entry.Name), overwrite: true);
                }
            }

            progressReporter.ReportProgress($"Python environment set up successfully.");
            Thread.Sleep(5000);
        }
        catch (Exception ex)
        {
            progressReporter.ReportProgress($"Error setting up Python environment: {ex.Message}");
            MessageBox.Show(ex.ToString());
            Thread.Sleep(5000);
        }
    }
    else
    {
        progressReporter.ReportProgress($"Found existing Python environment in {basePath}");
        Thread.Sleep(5000);
    }
}

The heart of this function is

entry.ExtractToFile(System.IO.Path.Combine(extractPath, entry.Name), overwrite: true);

Regardless which path I use for the output I get the same error on this line of code:

await Task.Run(() => { SetupEnvironment(this); });

The process cannot access the file C:\Data\python\_asyncio.pyd because it is being used by another process. Obviously _asyncio.pyd is part of the archive I am trying to extract

and also

System.UnauthorizedAccessException: Access to the path 'C:\Data\python' is denied.

Googling I found this thread

A process cannot access a File because it is being used by another process

but also trying to change the destination path (with one not included in the source path (as I do in the example)) didn't help

1

There are 1 best solutions below

0
federico On

The problem was that initially some entry.name were empty in the loop. The extract method was crashing trying to access a busy object. Here is the updated function:

public async Task SetupEnvironment3(IProgressReporter progressReporter)
{
    try
    {
        string zipFilePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"CPython\python.zip");
        progressReporter.ReportProgress($"extracting environment");
        string tempExtractPath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), Guid.NewGuid().ToString());
        if (!Directory.Exists(tempExtractPath))
        {
            Directory.CreateDirectory(tempExtractPath);
        }

        using (ZipArchive archive = ZipFile.Open(zipFilePath, ZipArchiveMode.Read))
        {
            foreach (ZipArchiveEntry entry in archive.Entries)
            {
                //string directoryPath = System.IO.Path.GetDirectoryName(entry.FullName);
                Debug.WriteLine(entry.FullName);
                if (string.IsNullOrEmpty(entry.FullName))
                {
                    continue; // Skip entries with empty names
                }

                if (progressReporter != null)
                {
                    progressReporter.ReportProgress($"extracting {entry.FullName}");
                }

                string destinationPath = System.IO.Path.Combine(tempExtractPath, entry.FullName);

                // Handle both files and directories
                if (entry.FullName.EndsWith("/"))
                {
                    // Entry represents a directory
                    Directory.CreateDirectory(destinationPath);
                }
                else
                {
                    // Entry represents a file
                    string directoryPath = System.IO.Path.GetDirectoryName(destinationPath);
                    if (!Directory.Exists(directoryPath))
                    {
                        Directory.CreateDirectory(directoryPath);
                    }
                    entry.ExtractToFile(destinationPath, overwrite: true);
                }

            }
            Process.Start(tempExtractPath);

        }
    }
    catch (Exception ex)
    { Debug.WriteLine(ex); }

}