Link to home
Start Free TrialLog in
Avatar of glenn masters
glenn masters

asked on

Am I able to merge files up to a defined size although individual files all different sizes

Hi

I have the following  C:\DOWNLOADS\DOWNLOAD of which holds more individual files

Im trying to find someway that I can get it to look through the sub folder DOWNLOAD and then merge the individual files into another sub folder 1,2,3, etc and are all up to 4 gb in size.

I.E
lets say in sub folder DOWNLOAD I have files that are  1gb , 500mb , 200 mb,  300 mb, 2gb ,2.5 gb , 3gb,  3.5 gb,  and what I need to do is to make up to 4gb so merge  files 1gb , 500mb , 200 mb,  300 mb, 2gb  into a new folder called no 1 and then carry on through naming the new folders no2 onwards  again all upto 4 gb in size.

If I have a file thats 2 gb and then next one is 3.5 gb I DO NOT want part of the 3.5 gb file split but just to add to a new folder.

The type of files that I want to merge are video files.

Can I do this and hope it not too confusing.

Thanks
Avatar of Bill Prew
Bill Prew

  1. Are there any subfolders in DOWNLOAD that need to be drilled into, or just the files to be processed?
  2. Where do you want the new folders created (1, 2, 3, ...)?
  3. Are the files to be copied or moved?


»bp
Avatar of glenn masters

ASKER

Q) Are there any subfolders in DOWNLOAD that need to be drilled into, or just the files to be processed?

A) There are no other subfolders in download just loads of individual files


Q)   Where do you want the new folders created (1, 2, 3, ...)?
    Are the files to be copied or moved?

A)  If poss and if it easier I would ideally like the new created folders created as subfolders in a folder on the desktop called " merged downloads". All I need then is the files to be moved and they can be deleted from C:\DOWNLOADS\DOWNLOAD


Hope that helps.

Thanks
Okay, give this a test there.  Adjust the paths near the top for you base and dest folders.

Also, the numbered subfolders (1, 2, 3, ...) will be created under the dest folder, and they must not exist already or errors will occur!

Once it is all working as you expect you can take out the *DEBUG* display if you want (or just comment it out).

Option Explicit

' Global variables
Dim strBaseDir, strDestDir
Dim objFSO, objFile
Dim arrFiles(), i
Dim lngFolderSize, intFolderNumber, strNextDir, intMoveFile

' Define paths to work with
strBaseDir = "B:\EE\EE29124343\base"
strDestDir = "B:\EE\EE29124343\dest"

' Set maximum size of new folders
Const cMaxFolderSize = 500000000

' Define class that will hold file information
Class File
    Public lngSize
    Public strPath
End Class 

' Create file system object
Set objFSO = WScript.CreateObject("Scripting.FileSystemObject")

' Fully resolve paths
strBaseDir = objFSO.GetAbsolutePathname(strBaseDir)
strDestDir = objFSO.GetAbsolutePathname(strDestDir)

' Make sure the folders exists, exit if not
If Not objFSO.FolderExists(strBaseDir) Then
    WScript.Echo "*ERROR* Folder does not exist: """ & strBaseDir & """."
    WScript.Quit
End If
If Not objFSO.FolderExists(strDestDir) Then
    WScript.Echo "*ERROR* Folder does not exist: """ & strDestDir & """."
    WScript.Quit
 End If
 
' Initialize array index variable
i = -1

' Load info for each file into array (using File class)
For Each objFile In objFSO.GetFolder(strBaseDir).Files
    ' Don't include any files with size greater than max allowed in a folder
    If objFile.Size > cMaxFolderSize Then
        WScript.Echo "*WARNING* Skipping file: """ & objFile.Path & """, size:""" & objFile.Size & """ exceeds maximum folder size:""" & cMaxFolderSize & """."
    Else
        ' Add another element to the array of type File class
        i = i + 1
        ReDim Preserve arrFiles(i)
        Set arrFiles(i) = New File

        ' Store the size and full path to the file
        arrFiles(i).strPath = objFile.Path
        arrFiles(i).lngSize = objFile.Size
    End If
Next

' If no files found then exit
If i = -1 Then
    WScript.Echo "*WARNING* No files found to process."
    WScript.Quit
End If

' Sort the files arrary by size in descending order
SortArray arrFiles

' Process all files moving to new subfolders until done
intFolderNumber = 0
Do
    ' Start a new destination folder and create it (MUST NOT ALREADY EXIST)
    lngFolderSize = cMaxFolderSize
    intFolderNumber = intFolderNumber + 1
    strNextDir = strDestDir & "\" & intFolderNumber & "\"
    objFSO.CreateFolder strNextDir

    ' Move files to dest folder until full
    Do
        ' Look for the largest file left that will fit in remaining space
        intMoveFile = GetFileToMove(arrFiles, lngFolderSize)

        ' If we found another file to move then move it
        If intMoveFile <> -1 Then
            Wscript.Echo "*DEBUG* Dest:[" & intFolderNumber & "], Available:[" & lngFolderSize & "], File:[" & arrFiles(intMoveFile).strPath & "], Size:[" & arrFiles(intMoveFile).lngSize & "]."
            objFSO.MoveFile arrFiles(intMoveFile).strPath, strNextDir
            lngFolderSize = lngFolderSize - arrFiles(intMoveFile).lngSize
            arrFiles(intMoveFile).lngSize = -1
        End If
    Loop Until intMoveFile = -1

Loop Until AllFilesMoved(arrFiles)

Function GetFileToMove(ByRef arrArray(), lngSize)
    ' Find next largest file to move that fits, -1 if none found
    Dim i
    GetFileToMove = -1
    For i = LBound(arrArray) To UBound(arrArray)
        If arrArray(i).lngSize <> -1 And arrArray(i).lngSize <= lngSize Then
            GetFileToMove = i
            Exit Function
        End If
    Next
End Function

Function AllFilesMoved(ByRef arrArray())
    ' See if all files have been moved
    Dim i
    AllFilesMoved = True
    For i = LBound(arrArray) To UBound(arrArray)
        If arrArray(i).lngSize <> -1 Then
            AllFilesMoved = False
            Exit Function
        End If
    Next
End Function

Sub SortArray(ByRef arrArray())
    ' Sort array of files by size, descending order (simple bubble sort)
    Dim i, j, intTemp
    For i = LBound(arrArray) to UBound(arrArray)
        For j = LBound(arrArray) to UBound(arrArray) - 1
            If arrArray(j).lngSize < arrArray(j + 1).lngSize Then
                Set intTemp = arrArray(j + 1)
                Set arrArray(j + 1) = arrArray(j)
                Set arrArray(j) = intTemp
                Set intTemp = Nothing
            End If
        Next
    Next
End Sub

Open in new window


»bp
im 90% there. A couple of amendments I need and failed to mention originally  SORRY...

It creating new folders and moving data but the files that im moving I need them to move down in order they are listed in  when moving into new folder.
If you look at the attachment I need it to start at the top and work its way down the list until it gets to the 4gb limit and then starts a new folder,

If it comes to like 3.5 gb and then next folder is too big to make it upto 4gb then start a new folder if that makes sense.
Also if poss can it add a .exe file that I have in the  original download everytime a new folder created and it be part of the 4gb allowance per folder.

Ive tried deleting the debug display by deleting line shown below but still get it come up. Dont think I deleted enough.

Wscript.Echo "*DEBUG* Dest:[" & intFolderNumber & "], Available:[" & lngFolderSize & "], File:[" & arrFiles(intMoveFile).strPath & "], Size:[" & arrFiles(intMoveFile).lngSize & "]."

Open in new window

Thanks
Untitled.png
So are you saying you want to process the files in name order?  I currently process in size order.  My approach optimizes the "fit" into the new folders, but it sounds like you don't care about that perhaps?


»bp
Yes that's right if I can do that   Thanks

As said if like 3gb in file and next one too big start new folder.
So if the files and sizes were as below, and your limit is 4gb, how do you want those broken out?

file1.avi, 3gb
file2.avi, 3gb
file3.avi, 3gb
file4.avi, 3gb
file5.avi, .5gb
file6.avi, .5gb
file7.avi, .5gb


»bp
No individual files will be over 2gb in size  and taking into account files as listed below but I would need it broken down like below

file1.avi, 1gb
file2.avi, 500mb
file3.avi, 2gb
file4.avi, 1.5gb
file5.avi, .1.8gb
file6.avi, .1.6gb
file7.avi,  2.0gb



Broken down like this
Player size is 170KB


SUBFOLDER 1

player.exe 170kb
file1.avi, 1gb
file2.avi, 500mb
file3.avi, 2 gb

That would make the file size 3.67gb and looking at file no4 the size is 1.5 gb and so it would make it too big so I need then to start a new folder with the player  and then move folders upto as near as  4gb as poss. again and repeat all the way down.

SUBFOLDER 2

player.exe 500mb
file3.avi, 1 gb
file4.avi, 1.5gb

Then folder 5 would make it too big and thus need to again create a new folder and get as near as poss to 4gb. If each individual folder is under 4gb that is no a problem.
 


and so on with player on every new folder if poss

Hope that makes sense
Why is file 3 in two folders?

The question I'm trying to answer but don't think you have is are the files split up in the name order, and so if some of the dest folders end up less full than they could be, that's okay?

So for example, how would these be broken out (ignore the player.exe size for the moment)?

file1.avi, 1.9gb
file2.avi, 1.9gb
file3.avi, 1.9gb
file4.avi, 1.9gb
file5.avi, 1.9gb
file5.avi, .2gb
file6.avi, .2gb
file7.avi, .2gb
file8.avi, .2gb
file9.avi, .2gb


»bp
Why is file 3 in two folders?   slip of the finger apologies :-)

Yes all the files have a individual name in order and yes it OK if  some destination folders are less full.

Taking into account what you put it would be like this


disk 1
file1.avi, 1.9gb
file2.avi, 1.9gb

disk 2
file3.avi, 1.9gb
file4.avi, 1.9gb

disk 3
file5.avi, 1.9gb
file5.avi, .2gb

disk 4
file6.avi, .2gb
file7.avi, .2gb

disk 5
file8.avi, .2gb
file9.avi, .2gb

Hope thats what you mean. apologies if not...
Wouldn't file8 and file9 go into disk 4, since they are only .2gb big?


»bp
ASKER CERTIFIED SOLUTION
Avatar of Bill Prew
Bill Prew

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Looking good and just need to confirm 2 things unless it me...

1) am I right in saying replace this

 Wscript.Echo "*DEBUG* Dest:[" & intFolderNumber & "], Available:[" & lngFolderSize & "], File:[" & arrFiles(intMoveFile).strPath & "], Size:[" & arrFiles(intMoveFile).lngSize & "]."
            objFSO.MoveFile arrFiles(intMoveFile).strPath, strNextDir
            lngFolderSize = lngFolderSize - arrFiles(intMoveFile).lngSize
            arrFiles(intMoveFile).lngSize = -1

Open in new window


with this
' Wscript.Echo "*DEBUG* Dest:[" & intFolderNumber & "], Available:[" & lngFolderSize & "], File:[" & arrFiles(intMoveFile).strPath & "], Size:[" & arrFiles(intMoveFile).lngSize & "]."

Open in new window


to get rid of debug message?

and

2) where it says
Const cMaxFolderSize = 500000000

Open in new window

thats the size I need in bytes, Im right in saying that 1000000 is 1 GB and lets say 7000000 is 7gb ? so I i wanted max 7gb folders i change to 7000000
You only want to comment the singlet line involved to remove the *DEBUG*, so:

Wscript.Echo "*DEBUG* Dest:[" & intFolderNumber & "], Available:[" & lngFolderSize & "], File:[" & arrFiles(intMoveFile).strPath & "], Size:[" & arrFiles(intMoveFile).lngSize & "]."

Open in new window

becomes:

Wscript.Echo "*DEBUG* Dest:[" & intFolderNumber & "], Available:[" & lngFolderSize & "], File:[" & arrFiles(intMoveFile).strPath & "], Size:[" & arrFiles(intMoveFile).lngSize & "]."

Open in new window

As far as the constant, it needs to be in bytes, and here is a starting point:

1GB = 1024*3 bytes = 1,073,741,824 bytes


»bp
As always a great help.

Many Thanks
Welcome.


»bp