1
votes

Recherche de milliers de fichiers dans un répertoire à l'aide d'une liste CSV

J'utilise Powershell 5.0 et j'ai un fichier .CSV avec une liste siebelid que je veux rechercher (environ: 5000) et je veux rechercher dans chaque dossier et sous-dossier sur un serveur pour tout fichier contenant cet élément de liste (siebelid) dans le nom de fichier. ie nom de fichier: 32444167.pdf ou 32444167.pdf.metadata.properties.xml

Exemple de fichier CSV:

$PDFExtension = '.pdf'
$XMLExtension = '.pdf.metadata.properties.xml'
$source = 'C:\Temp\CSVtoXML'
$destination = 'C:\Temp\FindFiles\'                                                           #' 
$strGetDate = get-date -UFormat “%Y-%m-%d %H:%M:%S”
$log = $destination + "FileCopyLog.txt"

$FileList = import-csv “C:\Temp\FindFiles\test.csv” -Delimiter "," -Header 'siebelId', 'companyCode', 'receivedDate'
$GetFiles = @(Get-ChildItem -path $source -Recurse -File -include *.xml, *.pdf ) | select -First 100000

ForEach ($item in $FileList){
 $siebelId = $($item.siebelId) + $PDFExtension
 $XMLFile = $($item.siebelId) + $XMLExtension

 $FilterFiles = @($GetFiles) | Where-Object {$_.name -eq $siebelId -or $_.name -eq $XMLFile} #|  Out-File $destination"FileCopyLog.csv"
 #write-host "Filtered Files: " $FilterFiles

 ForEach ($file in $FilterFiles){

   $fileBase = $file.BaseName
   $fileExt = $file.Extension

   write-host "file: " $fileBase$fileExt

   If (-not ([string]::IsNullOrEmpty($file))) {
       if(!(Test-Path -Path $Destination$fileBase$fileExt)) {
            copy-item $file -destination $destination   # Copies files
            write-host "File: [" $file "] has Been Copied! to " $Destination `n`r -ForegroundColor yellow
            $strGetDate = get-date -UFormat “%Y-%m-%d %H:%M:%S”
            $LogValue = $strGetDate + ': ' + "Source: [" + $file + "] Destination: " + $Destination
            Add-Content -Path $log -Value $LogValue
       } else
       {
            write-host "File: [" $file "] already exsits in destination folder" `n`r -ForegroundColor yellow
            $strGetDate = get-date -UFormat “%Y-%m-%d %H:%M:%S”
            $LogValue = $strGetDate + ': ' + "File: [" + $file + "] already exsits in destination folder! "
            Add-Content -Path $log -Value $LogValue 
       }

   }else{
       write-host "No File was copied!" `n`r -ForegroundColor red
   }
 }
}

write-host 'Script has completed' -ForegroundColor green


Je filtre sur * .PDF code> et * .XML . Ensuite, je veux copier les fichiers trouvés dans un dossier de destination sur le même serveur. Le problème est que j'ai des centaines de milliers de fichiers dans le dossier et les sous-dossiers. Le code que j'ai écrit semble prendre beaucoup de temps à s'exécuter jusqu'à plusieurs jours. Je ne suis pas un expert et je crois que je n'ai pas écrit le script Powershell le plus efficace. Toute aide serait appréciée.

Fondamentalement, le code fonctionne mais il est extrêmement lent lors du traitement dans un dossier contenant des centaines de milliers de fichiers. Il semble efficace d'appeler le Get-Childitem chaque fois que j'obtiens un nouvel élément de la liste.

32444167,ACME,4/15/2013
27721071,ACME,4/15/2013
27721072,ACME,4/15/2013

Le résultat attendu que je recherche est d'avoir ce processus dans quelques heures plutôt que plusieurs jours.


0 commentaires

3 Réponses :


0
votes

Essayez :

$(Get-ChildItem -path $source -Recurse -File -Filter *.xml
  Get-ChildItem -path $source -Recurse -File -Filter *.pdf)


2 commentaires

Merci pour les commentaires. La correspondance et le filtrage ci-dessus fonctionnent bien lorsque le nom de base est le même que le SiebelID dans le fichier .CSV, mais lorsque j'ai un fichier avec un nom de base de .pdf.metadata.propteries.xml, ce n'est pas le cas. J'ai besoin de comprendre comment analyser le nom de base et le faire correspondre à mon fichier d'importation.


@ user1003713 Je crois que vous vouliez répondre à mon commentaire. Je cherchais uniquement sur .pdf, donc je modifierai ma réponse pour ceci, Ma réponse est celle commençant par Au lieu de boucler les fichiers, filtrez-les.



1
votes

Au lieu de boucler les fichiers, filtrez-les.

Modifié pour utiliser ".pdf.metadata.properties.xml" au lieu de XML, et corrigez ceux-ci en envoyant ".pdf.metadata.properties" du "Basename" des fichiers que nous avons trouvés

modifier

Ajoutez également plus de votre script pour réduire le temps nécessaire au processus de copie, en générant une liste de fichiers de destination puis filtrer les fichiers que nous copierons par fi


$Exts =@('.pdf','.pdf.metadata.properties.xml')

$source = 'C:\Temp\CSVtoXML'
$destination = 'C:\Temp\FindFiles\'                                                           #' 
$strGetDate = get-date -UFormat “%Y-%m-%d %H:%M:%S”
$log = "$($destination)FileCopyLog.txt"

$SiebelIDFile="$($destination)test.csv"
$SiebelIDImport = import-csv $SiebelIDFile -Delimiter "," -Header 'siebelId', 'companyCode', 'receivedDate'

$SRC_Matched_Exts = $(  $Exts | % { Get-ChildItem -path $source -Recurse -File -Filter $_  } )


# Presto we can filter the list using the Siebel IDs


$Results = $SRC_Matched_Exts | ? { $( $($_.basename) -replace '.pdf.metadata.properties','' ) -in $($SiebelIDImport.SiebelID) }

# Confirm results by outputting first 1000
$Results | select -first 100 | FT -property BaseName, FullName -Auto 

# Get Destination Files to compare:
$Dst_Matched_Exts = $(  $Exts | % { Get-ChildItem -path $Destiation -Recurse -File -Filter $_  } )

# Filter to only the Source files notin the destination:
$Src_Files_MissingFromDst = $Results | ? { $_.basename -notin $( $Dst_Matched_Exts.basename ) }
$Src_Files_AlreadyInDs = $Results | ? { $_.basename -notin $Src_Files_MissingFromDst.basename }


# Output some of the Files we won't Copy because they already exist in dst:
Write-host "
 Output some of the Files we won't Copy because they already exist in dst:

$($Src_Files_AlreadyInDst | select -first 100 | FT -property BaseName, FullName -Auto | Out-String)" -ForegroundColor red

# Output some of the Files we will Copy:
Write-host "
 Output some of the Files we will Copy:

$Src_Files_MissingFromDst | select -first 100 | FT -property BaseName, FullName -Auto | Out-String )" -ForegroundColor yellow

$Count=0
# Loop Files and Copy them to Destination:
$Src_Files_MissingFromDst | %{
  $Count+=1
  copy-item $($_.Fullname) -destination $destination   # Copies files
  Add-Content -Path $log -Value "$(Get-Date -UFormat `"%Y-%m-%d %H:%M:%S`")`: Source File # $Count: [$($file)] Destination: $Destination"
  # Update the copy progress every 10 files
  IF ( ! [bool]( $Count % 10 ) -or $Count -eq $($Src_Files_MissingFromDst.count)  ) {
    Write-Progress -Activity "======== Copying to $Destination" -Status "## $([math]::round( $(($Count/$($Src_Files_MissingFromDst.count))*100), 1))% Complete!" -PercentComplete $([math]::round( $(($Count/$($Src_Files_MissingFromDst.count))*100), 1))
    write-host "File # $Count: [ $file ] has Been Copied to  $Destination " -ForegroundColor Green
  }

}

vous pouvez maintenant écrire votre copie / déplacement de fichier en fonction de la collection de fichiers correspondants - et il serait logique d'utiliser un processus parallèle pour accélérer cela.

Les boucles sont toujours plus lentes que le filtrage par des instructions de sélection, l'utilisation du filtre en ligne sur la commande est presque toujours un meilleur chemin que le filtrage des résultats car le filtrage se produit au niveau du niveau inférieur lors de la collecte des données.


7 commentaires

Avec le $ XMLExtension = '.pdf.metadata.properties.xml' existant, vérifier uniquement $ _. BaseName ne fonctionnera pas.


@LotPings Vous avez raison, je n'ai utilisé que * .pdf en écrivant ceci dans le train, je pourrais réparer avec un remplacement quand j'en ai le temps.


Merci! J'exécute ceci maintenant et je vous ferai savoir comment cela se passe.


@ user1003713 De rien. Je viens de remarquer que la sortie des 100 premiers fichiers à copier / ne pas copier ne fonctionnera pas correctement car j'ai laissé | Out-String J'ai modifié ce code maintenant. Tout autre problème me fait savoir que j'ai écrit ceci sur mon téléphone pendant mon trajet et mes moments de repos afin que je puisse avoir des choses stupides comme celles qui pourraient être résolues rapidement.


A très bien fonctionné! Il a fallu le temps de traitement de quelques jours à 1 heure ou moins. Merci de votre aide. J'ai cependant eu un problème pour faire fonctionner le code Progress. Je ne sais pas ce qui ne fonctionnait pas là-bas, mais tous les autres fonctionnaient très bien.


@ user1003713 Heureux de vous aider, j'ai probablement fait quelque chose de stupide lors de la création de la boucle de processus à la dernière minute, et je déteste le parce qu'ils ralentissent énormément le traitement, c'est pourquoi j'ai essayé de l'appeler moins fréquemment, j'ai probablement fait une erreur dans la logique ou la syntaxe du chapeau, mais laissez-le de côté, c'était juste un épanouissement.


@ user1003713 Ahh, je l'ai scopé, j'ai eu le test logique pour trouver quand le compte était divisible par 10 faux. Il doit être IF (! [Bool] ($ Count% 10) -or $ Count -eq $ ($ Src_Files_MissingFromDst.count)) { au lieu de IF ([bool] ((! $ Count% 10) -or ($ Count -eq $ ($ Src_Files_MissingFromDst.count))) { - On dirait que liek n'était qu'un gros doigté sur mon téléphone. Je l'ai également corrigé dans la réponse ci-dessus au cas où vous ou d'autres souhaiteriez l'utiliser.



0
votes

Comme le siebelID semble avoir 8 chiffres, vous pouvez l'utiliser pour sélectionner des fichiers.

Je ne suis pas sûr de ce qui est le plus efficace:

  • explorer l'arborescence deux fois (pour chaque extension) ou
  • une seule fois en utilisant un objet Where et une expression régulière qui en une seule fois extrait le numéro et vérifie la présence dans $Filelist

La sortie doit être réduite au strict nécessaire pour accélérer le traitement.

Le script suivant supprime également la redondance lors de la création de $LogValue

< pre> XXX

Une version légèrement adaptée pour rechercher dans mon dossier de test avec des scripts SO stockés qui ont également un numéro à 8 chiffres donne ce FileCopyLog.txt

< pré> XXX


0 commentaires