Mattia Bergomi
Mattia Bergomi

Reputation: 35

ZIP a folder of files into multiple "stand-alone" ZIP files of maximum size

I have the following problem: I'm writing a Powershell script that, after generating a lot of PDF files (each in a separate subfolder of a main folder), needs to zip them.

Here is the difficulty/problem:

The destination where those ZIP files need to be unzipped (a Moodle website) has a filesize limit of 50MB, hence I need to generate multiple ZIP files of this maximum size. Each ZIP file, however, needs to be "standalone", i.e. it must be unzipped by itself (automatically by the website), without requiring the presence of the other files.

Here below is what I've tried so far:

Can somebody suggest me a way to achieve my goal, i.e. to separate those files into individual ZIP files of size no larger than 50MB (of course the ZIP will be in general smaller than 50MB, since the PDF files have arbitary size, but all < 50MB for sure)? The result should look like:

"Result1.zip" [49MB] , "Result2.zip" [47MB] , ... , Result16.zip [48MB], Result17.zip[7MB]

Thank you very much for any suggestion! :)

Upvotes: 1

Views: 2815

Answers (1)

Minkulai
Minkulai

Reputation: 124

I believe you look for something like this:

$filesFolderPath = "Path of where the PDFs are"
$archivePath = "Path to where the archive will be"

$files = Get-ChildItem -Path $filesFolderPath -Recurse
foreach ($file in $files) {
    $fileName = $file.Name
    $filePath = $file.FullName
    Compress-Archive -Path $filePath -DestinationPath "$($archivePath)\$($fileName).zip"
}

This script will basically get the list of the files (assuming you only have PDFs in the location) and will archive each one. If you want to be sure it only archives the PDFs please change this line:

$files = Get-ChildItem -Path $filesFolderPath -Recurse | Where-Object { $_.Extension -eq ".pdf" }

UPDATE (changed the script to allow archive of multiple files if their combined size isn't over 50GB):

$filesFolderPath = "Path of where the PDFs are"
$archivePath = "Path to where the archive will be"

$files = Get-ChildItem -Path $filesFolderPath -Recurse | Where-Object { $_.Extension -eq ".pdf" }
$filesToArchive = @()
$archiveSize = 0
$counter = 0

foreach ($file in $files) {
    $fileSize = [Math]::Round(($file.Length / 1MB), 2)
    
    # Check if the combined size of the files to be archived exceeds 50 MB
    if (($archiveSize + $fileSize) -gt 49) {
        # Create the archive if the combined size exceeds 50 MB
        $counter++
        Compress-Archive -Path $filesToArchive.FullName -DestinationPath "$($archivePath)\Archive-$counter.zip"
        $filesToArchive = @()
        $archiveSize = 0
    }

    # Add the file to the list of files to be archived
    $filesToArchive += $file
    $archiveSize += $fileSize
}

# Create the final archive if there are any remaining files to be archived
if ($filesToArchive.Count -gt 0) {
    $counter++
    Compress-Archive -Path $filesToArchive.FullName -DestinationPath "$($archivePath)\Archive-$counter.zip"
}

UPDATE 2 (added the warning and archiving of a single file if exceeds the 50MB size). All you have to do in with this update is to replace the foreach statement with the below code.

foreach ($file in $files) {
    $fileSize = [Math]::Round(($file.Length / 1MB), 2)
    
    # Check if the file is bigger than 49MB to archive it separately and write a warning
    if ($fileSize -gt 49) {
        $counter++
        Compress-Archive -Path $file.FullName -DestinationPath "$($archivePath)\Archive-$counter.zip"
        Write-Warning "The archive number '$($counter)' has a single file bigger than 50MB"
    } else {
            # Check if the combined size of the files to be archived exceeds 50 MB
        if (($archiveSize + $fileSize) -gt 49) {
            # Create the archive if the combined size exceeds 50 MB
            $counter++
            Compress-Archive -Path $filesToArchive.FullName -DestinationPath "$($archivePath)\Archive-$counter.zip"
            $filesToArchive = @()
            $archiveSize = 0
        }

        # Add the file to the list of files to be archived
        $filesToArchive += $file
        $archiveSize += $fileSize
    }
}

Upvotes: 1

Related Questions