compare files - for 3ds max plugin

This topic contains 15 replies, has 2 voices, and was last updated by Profile photo of michael tolika michael tolika 8 months ago.

  • Author
    Posts
  • #32371
    Profile photo of michael tolika
    michael tolika
    Participant

    Hello, friends!
    I was impressed to know that powershell scripts can help me solve some problems for my 3d max plugins.
    Here is an example: There are cases when you download a 3d model with textures that have unicode names.
    If your system Code Page is different from the character set of texture name, then 3d max will see such names like ?????? ???.jpg.
    Here is where powershell can help.

    In 3d max if a texture file has a "?" in the name or in the path, it will say – the file does not exist.

    The only solution I found is to save from 3ds max the path where powershell will search and the name ?????? ???.jpg, then I run powershell code and it compares all the filenames from the directory with the name ?????? ???.jpg and renames the texture wich maches this name.
    At the moment everything works fine, and I get the renamed texture back and I relink it to my max file.
    But there are still some situations that I met during using the plugin:

    #1 when there are 2 ore more files which can match the name ?????? ???.jpg (I don't know at the moment how to solve this problem)
    #2 when absolutely the same file is saved in different subfolders in the specified path with the same unicode name.

    For now I want you to help me with #2.
    In the powershell script that I use, I collect all found textures that match my texture name in 2 arrays:
    `
    if ($item.Name -like $Pattern)
    {
    $ArrTextureList.Add($item)
    $ArrFullPathTextureList.Add($item.FullName)
    `
    }

    If $ArrTextureList.Count != 1 then compare all array items by realName, FileHash and size and print "true" if all items are identical or false in other cases.

    I stopped here and I don't know how to continue.

    `foreach ($texture in $ArrFullPathTextureList)
    {
    Write-Host ($texture)
    Write-Host (Get-FileHash $texture).hash
    }`

  • #32400
    Profile photo of Curtis Smith
    Curtis Smith
    Participant

    Can you give an example of the types of names you are working with? Specifically where you run into the conflict, or are you saying the name of the file literally has 6 question marks followed by a space and three question marks followed by .jpg?

    Probably just showing the results of get-childitem for one of the directories as an example would be the most helpful.

  • #32401
    Profile photo of michael tolika
    michael tolika
    Participant

    of course.

    In 3ds max I have: ????? ?????.jpg
    In the path in different subfolders I have 2 identical files with this name: Копия балка.jpg
    but they have modification date different, however completely the same.

  • #32402
    Profile photo of michael tolika
    michael tolika
    Participant

    I'm using get-childitem

    $items = Get-ChildItem -Force -Recurse -Path $Path | sort @{expression = {$_.FullName.Split('\').Count}} -descending -ErrorAction SilentlyContinue
    foreach ($item in $items)
    {
    if ($item.Name -like $Pattern)
    {
    $ArrTextureList.Add($item)
    $ArrFullPathTextureList.Add($item.FullName)
    }
    }
    foreach ($texture in $ArrFullPathTextureList)
    {
    Write-Host ($texture)
    Write-Host ($texture.name)
    Write-Host (Get-FileHash $texture).hash
    }

  • #32403
    Profile photo of Curtis Smith
    Curtis Smith
    Participant

    So something like this?

    Parent Folder
                 |
                 --SubFolder1
                             |
                             --Копия балка.jpg
                 |
                 --SubFolder2
                             |
                             --Копия балка.jpg
    
  • #32404
    Profile photo of michael tolika
    michael tolika
    Participant

    yes

  • #32405
    Profile photo of Curtis Smith
    Curtis Smith
    Participant

    And the goal is to rename the file under subfolder1, but not under subfolder2?

  • #32406
    Profile photo of michael tolika
    michael tolika
    Participant

    no, no!
    with the renaming everything is done already.
    I need this:

    Compare all array items of $ArrFullPathTextureList by realName, FileHash and size and print "true" if all items are identical or false in other cases.

  • #32407
    Profile photo of michael tolika
    michael tolika
    Participant

    if item1.name == item2.name and Filehash(item1)== FileHash(item2) and Filesize(item1)==Filesize(item2) then Write-Host("true") elseWrite-Host("false")

    I would make it easily in maxscript, but I don't know how to do it in powershell

  • #32408
    Profile photo of Curtis Smith
    Curtis Smith
    Participant

    Ok, first we need to change the second foreach loop to use $ArrTextureList instead of $ArrFullPathTextureList since the full path array only contains the fullname property, not all of the other properties, such as length and name. Then we can reason that we just need to compare each returned file to the first file in the array as the baseline. If the current file is different than the first file then it is different and false should be returned.

    $Pattern = "????? ?????.jpg"
    $ArrTextureList = @()
    $ArrFullPathTextureList = @()
    $items = Get-ChildItem -Force -Recurse -Path $Path | sort @{expression = {$_.FullName.Split('\').Count}} -descending -ErrorAction SilentlyContinue
    foreach ($item in $items)
    {
        if ($item.Name -like $Pattern)
        {
            $ArrTextureList += $item
            $ArrFullPathTextureList += $item.FullName
        }
    }
    foreach ($texture in $ArrTextureList)
    {
        Write-Host ($texture.FullName)
        Write-Host ($texture.name)
        Write-Host (Get-FileHash $texture.FullName).hash
    
        if ($ArrTextureList[0].name -eq $texture.name -and (Get-FileHash ($ArrTextureList[0].FullName)).hash -eq (Get-FileHash ($texture.FullName)).hash -and $ArrTextureList[0].Length -eq $texture.Length)
        {
            Write-Host "true"
        }
        else
        {
            Write-Host "false"
        }
    
    }
    Remove-Variable ArrTextureList
    Remove-Variable ArrFullPathTextureList
    

    Note: edited to facilitate for subfolders. Using FullName for Get-FileHash instead of just the name.

  • #32416
    Profile photo of Curtis Smith
    Curtis Smith
    Participant

    You can also shorten it a bit by moving your filter into the get-childitem cmdlet and only looping through your results once.

    $Pattern = "????? ?????.jpg"
    
    $items = Get-ChildItem -Filter $Pattern -Force -Recurse -Path $Path | sort @{expression = {$_.FullName.Split('\').Count}} -descending -ErrorAction SilentlyContinue
    foreach ($item in $items)
    {
        Write-Host ($item.FullName)
        Write-Host ($item.name)
        Write-Host (Get-FileHash $item.FullName).hash
    
        if ($items[0].name -eq $item.name -and (Get-FileHash ($items[0].FullName)).hash -eq (Get-FileHash ($item.FullName)).hash -and $items[0].Length -eq $item.Length)
        {
            Write-Host "true"
        }
        else
        {
            Write-Host "false"
        }
    }
    

    Results Similar to:

    F:\temp\Powershell\part\New folder\Копия балка.jpg
    Копия балка.jpg
    E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
    true
    F:\temp\Powershell\part\New folder (2)\Копия балка.jpg
    Копия балка.jpg
    E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
    true
    F:\temp\Powershell\part\New folder (3)\Копия балка.jpg
    Копия балка.jpg
    F0E4C2F76C58916EC258F246851BEA091D14D4247A2FC3E18694461B1816E13B
    false
    
  • #32418
    Profile photo of michael tolika
    michael tolika
    Participant

    oh, so nice, Curtis Smith!
    thank you so much. In fact I was thinking to compare every 2 items
    for s=1 to array.count-1 do
    for f=s+1 to array.count do
    ...

    but you're right, it's enough to compare just with the first file. Now it's much clear for me. thank you very very much. I will test the code tomorrow and let you know, because I am not at the computer right now.
    by the way, how to get the file with the shortest path if the files are equal?

  • #32419
    Profile photo of Curtis Smith
    Curtis Smith
    Participant

    The simple answer is use the length of the FullName as your comparison value, but let's talk again about the scenario. In this scenario, there is no shortest path. Both paths are 40 characters.

    Parent Folder
                 |
                 --SubFolder1
                             |
                             --Копия балка.jpg
                 |
                 --SubFolder2
                             |
                             --Копия балка.jpg
    
    "Parent Folder\SubFolder1\Копия балка.jpg".Length
    "Parent Folder\SubFolder2\Копия балка.jpg".Length
    40
    40
    
  • #32420
    Profile photo of michael tolika
    michael tolika
    Participant

    let's say we have 3 identical files, 1 of them is located much deeper in subfolders, but 2 of them have the same folder depth with the same lenght, then we should print the first from these 2

  • #32430
    Profile photo of Curtis Smith
    Curtis Smith
    Participant

    Well, you are already sorting your results by directory depth, but you are sorting them descending, So the longest depth is at the top, you want the shortest depth, so remove the -descending parameter and it will default to ascending. Then you just pick the first element ([0]) of the resulting array of file objects.

    $Pattern = "????? ?????.jpg"
    
    $items = Get-ChildItem -Filter $Pattern -Force -Recurse -Path $Path | sort @{expression = {$_.FullName.Split('\').Count}} -ErrorAction SilentlyContinue
    Write-Host ($items[0].FullName)
    Write-Host ($items[0].name)
    Write-Host (Get-FileHash $items[0].FullName).hash
    

    Results in:

    F:\Temp\Powershell\part\New folder\Копия балка.jpg
    Копия балка.jpg
    E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
    
  • #39933
    Profile photo of michael tolika
    michael tolika
    Participant

    Hey, Curtis, thank you so much for your help.

You must be logged in to reply to this topic.