Newsgroup: it.comp.os.win.windows7
Titolo: semi [OT] Pulizia batch nomi files e directory

Ciao NG,
 
Ho cercato ma non trovato sicché eccomi qui. Ho un albero 
di directory con relativi file i cui nomi (sia di file che 
directory) hanno caratteri non ascii, tipicamente nomi 
stranieri. Mi servirebbe un software che possa convertire 
tutto in ascii magari approssimando al meno peggio la resa 
in alfabeto latino (esempio, la u con l'umlaut <ü> come 
ue, traslitterazione del russo, etc.).
 
So che potrei farlo con programmi appositi e difatti ho un 
mio piccolo scritpt su ReNamer, ma i casi da considerare 
sono troppi e vedo che non solo mi sfugge sempre qualcosa 
ma peggio di tutto, sbaglio nella conversione (sbaglio io, 
intendo) ed è quasi impossibile tornare indietro nella 
rinomina. E' già il terzo ripristino di backup su 600 GB 
(è il mio archivio musica se non si era capito :D).
 
Insomma, sarebbe meglio non reinventare male la ruota; 
esiste qualcosa che voi conosciate che fa al caso mio?
 
Grazie
 
Apx.
 
 
-- 
- Thanks for introducing me to minimalims.
- It's the least I could do.
 

Archaeopteryx ha scritto:

No, ma un consiglio al volo da uno che ha fatto roba simile
a suo tempo...
 
Ogni volta che rinomini un file, il programma dovrebbe
fare un append in un file di testo di
	ren NomeNuovo NomeVecchio
In questo modo lo rinomini come batch, lo lanci e ripristini
la situazione precedente in un millesimo del tempo che ti ci
vuole per ripristinare l'intero backup.
Se il tuo script è un altro batch, per esempio, quando fa
	ren NomeVecchio NomeNuovo
ci aggiungi sotto una cosa del tipo
	echo ren NomeNuovo NomeVecchio >> ripristina.bat
(sintassi da controllare, non lo faccio da anni)
e ti trovi il batch pronto.
 
Bye, G.

 non lo faccio da anni) e ti trovi il batch pronto.
 
Grazie, per ora ha fallito (lo sapevo in anticipo) perché
i nomi di molti file sono lunghissimi e sommati al path
mettono windows alle corde. Allora dato che sto lavorando
a un programma che mi faccia il tag in automatico,
cercherò di abbreviare i nomi. Dopodiché si riprova...
 
 
-- 
- Ciao, ho visto le tue foto su Facebook
   chiamami al 347******9
- Non ti sembra esagerato darmi subito il
   tuo numero?
- Sono un chirurgo plastico, posso aiutarti.
 

 in automatico, cercherò di abbreviare i nomi. Dopodiché si riprova
 
Abbrevia il path o sposta le cartelle intere nella radice del disco,
poi le rimetti dov'erano.
A rimettere tutto com'era ci metti trenta secondi e ti risparmi la
 rogna
di abbreviare i nomi dei file.
 
Un passo alla volta, fidati :-)
 
Bye, G.
 
 
----Android NewsGroup Reader----
http://usenet.sinaapp.com/
 

 Un passo alla volta, fidati :-)
 
Eh, non è facile. I nomi dell'albero delle directory li
scelsi già allora molto abbreviati perché codificano 
genere, sotto genere, sotto-sotto genere e (credeteci) 
sotto-sotto-sotto genere, e il mio vecchio player sullo
smartphone poteva far vedere solo pochi caratteri. Quando
facevo la copia per la SD abbreviavo drasticamente i nomi 
rinominandoli con F_xxxxxx.mp3 (come avrai capito sono 
oltre 99999), tanto con la codifica del path arrivavo 
praticamente al nome dell'album.
 
Il problema è l'originale, perché in quasi tutti i nomi
file sono contenute info che musicbrainz pare non avere.
 
Trattandosi di quei problemi atroci nelle conseguenze, per
ora faccio come l'artificiere che si prende due anni per
studiare l'oggetto prima di metterci le mani.


 studiare l'oggetto prima di metterci le mani.
 
Per curiosità, quanta roba è? Qualche tera, immagino?
 
Bye, G.

> Per curiosità, quanta roba è? Qualche tera, immagino?
 
680 GB, nel frattempo riesco a farmi stampare elenco
ordinato dei nomi "pericolosi", dopo posto qualcosa... per
curiosità!


 
 
advanced renamer portable.
 
spero ti possa aiutare

 ue, traslitterazione del russo, etc.).
 
puoi mettere in piedi uno script o un programmino che faccia quello che
ti serve, l'idea di base per come la vedo io potrebbe essere questa
 
Prima di tutto ti carichi ricorsivamente un elenco delle sottocartelle
 
Sub RecurseFolders(szPath, dicTemp)
  For each subFolder in Folder.SubFolders
    dicTemp.Add subFolder.Path
    RecurseFolder subFolder.Path, dicTemp
  Next
End Sub
 
Fatto quanto sopra ti spazzoli l'elenco e rinomini le sottocartelle
come necessario
 
 For each szPath in dicTemp
   szNewName = NewFolderName(szPath)
   If szNewName <> szPath
     RenameFolder szPath, szNewName
   End If
 Next
 
A questo punto riparti con la ricorsione ma gestisci i files, ossia
spazzoli tutti i files di una cartella e li rinomini come necessario,
quindi vai in ricorsione su tutte le sottocartelle
 
Sub RecurseFiles(szPath)
  For each szFile in szPath.Files
    szNewName = NewFileName(szFile)
    If szNewName <> szFile
      RenameFile szFile, szNewName
    End If
  Next
  For each subFolder in szPath.SubFolders
    RecurseFiles subFolder.Path
  Next
End Sub
 
per quanto riguarda il rename, ti puoi creare una funzione (vedi
sopra) che, date determinate regole di conversione (es. "ù" -> "u")
generi un nuovo nome e poi procedi al rename solo se il nome originale
ed il nuovo sono diversi
 
 

Grazie a tutti come sempre... nel frattempo il programmino 
che avevo iniziato a scrivere sta dando i primi vagiti 
quindi spero bene.
 
E poi non sapevo che nei batch si potessero avere 
subroutines, grazie anche a ObiWan


 subroutines, grazie anche a ObiWan
 
call :label
 
:D
 
ad ogni modo, personalmente (ma probabilmente è solo un discorso di
preferenze), per una cosa del genere utilizzerei vbscript, d'altronde
c'è nativamente, per cui... :) ad occhio e croce uno script del genere
potrebbe essere qualcosa come quello sotto (NON TESTATO !!!), considera
che lo script sotto NON fa una mazza dato che va impostato il codice
della funzione "GetNewName()" che, dato il nome di un file o di una
cartella, ne ritorna uno "ripulito" e che dovrai impostare tu, allo
scopo, tirati giù 
https://www.vbsedit.com/
 ed usalo per editare il
codice di cui sotto ;-)
 
 
' globali
Dim fso, arg
 
' inizializza
Set fso = CreateObject("Scripting.FileSystemObject")
Set arg = WScript.Arguments
 
' bootstrap
WScript.Quit main(arg.Count, arg)
 
' main tipo "C"
Function main(argc, argv)
  Dim i, rc, err
  Dim dicFolders
  Dim fld
 
  ' inizializza
  err = 0
 
  ' carica l'elenco iniziale delle cartelle  
  Set dicFolders = CreateObject("Scripting.Dictionary")
  For i=0 to argc-1
    rc = LoadFolderList(argv(i), dicFolders)
    err = err + rc
  Next
  If err > 0 Then
    ' errore su caricamento elenco
  End If
 
  ' rinomina come necessario
  rc = RenameFolder(dicFolders)
  if rc <> 0 Then
    ' errore su rename
    'printf "Errore..."
    'main = 1234
    'Exit Function
  End If
 
  ' ricarica l'elenco delle cartelle DOPO il rename
  Set dicFolders = CreateObject("Scripting.Dictionary")
  For i=0 to argc-1
    rc = LoadFolderList(argv(i), dicFolders)
    err = err + rc
  Next
  If err > 0 Then
    ' errore su caricamento elenco
  End If
 
  ' elabora i files
  rc = ProcessFiles(dicFolders)
  if rc <> 0 Then
    ' errore su rename
    'printf "Errore..."
    'main = 1235
    'Exit Function
  End If
 
 
 
  main = err
End Function
 
 
' ====================================================
' elaborazione sottocartelle
' ====================================================
 
' carica la lista delle sottocartelle
Function LoadFolderList(sRootPath, dicFolders)
  Dim sPath
  Dim fld, sfd
 
  ' controlli
  If Not fso.FolderExists(sRootPath) Then
    printf "ERR: folder " & sRootPath & " doesn't exist."
    LoadFolderList = 1
    Exit Function
  End If
  sPath = fso.GetFolder(sRootPath).Path
 
  ' carica le sottocartelle in dicFolders
  LoadFolderList = RecursePath(sPath, dicFolders)
End Function
 
' esegue la ricorsione sulle sottocartelle
Function RecursePath(sPath, dicFolders)
  Dim fld, sfd
 
  Set fld = fso.GetFolder(sPath)
  For Each sfd In fld.SubFolders
    RecursePath sfd.Path, dicFolders
  Next
  ' la "root" per ultima !!!
  dicfolders.Add "F" & dicfolders.Count, fld.Path
  RecursePath = 0    
End Function
 
' rinomina (se necessario) le cartelle
Function RenameFolders(dicFolders)
  Dim sPath
  Dim rc, ret
 
  ret = 0
  For Each sPath In dicFolders.Items
    rc = RenameFolder(sPath)
    ret = ret + rc
  Next
  RenameFolders = ret
End Function
 
' rinomina (se necessario) una cartella
Function RenameFolder(sPath)
  Dim fld, rc
  Dim sPath, sOldName, sNewName
 
  On Error Resume Next
  err.Clear
  rc = 0
  Set fld = fso.GetFolder(sPath)
  sPath = fld.ParentFolder
  sOldName = fld.Name
  sNewName = GetNewName(sOldName)
  If sNewName <> sName Then
    fld.Move fld.Path, sPath & "\" & sNewName
  End If
  If err.number <> 0 Then
    perror "ProcessFolder(" & sPath & ")"
    rc = 1
  End If
 
  RenameFolder = rc  
End Function
 
' ====================================================
' elaborazione files
' ====================================================
 
' elabora i files
Function ProcessFiles(dicFolders)
  Dim sPathName
  Dim rc, err
 
  err = 0
  For Each sPathName In dicFolders
    rc = ProcessFile(sPathName)
    err = err + rc
  Next
  ProcessFiles = err  
End Function
 
' elabora UN file
Function ProcessFile(sPathName)
  Dim fil, rc
  Dim sPath, sOldName, sNewName
 
  On Error Resume Next
  err.Clear
  rc = 0
 
  Set fil = fso.GetFile(sPathName)
  sPath = fil.ParentFolder
  sOldName = fil.Name
  sNewName = GetNewName(sOldName)
  If sNewName <> sOldName Then
    fil.Move fil.Path, sPath & "\" & sNewName
  End If
  If err.number <> 0 Then
    perror "ProcessFile(" & sPathName & ")"
    rc = 1
  End If
 
  ProcessFile = rc
End Function
 
' ====================================================
' utility
' ====================================================
 
' genera un nuovo nome un file/cartella in base alle regole impostate
Function GetNewName(sName)
  GetNewName = sname
End Function
 
 
' ====================================================
' generiche
' ====================================================
 
' messaggio su console
Sub printf(sTxt)
  On Error Resume Next
  WScript.StdOut.WriteLine sTxt
End Sub
 
' errore su console
Sub perror(sInf)
  Dim sMsg
 
  sMsg = "ERR: 0x" & err.number & " " & err.Description
  If Len(sInf) > 0 Then
    sMsg = sMsg & " :: " & sInf
  End If
  printf sMsg
End Sub
 
 
 
 
 

Non mi ero dimenticato :) Solo adesso ho rimesso mano al
problema e ti ringrazio del tempo già solo per mettere in
piedi lo script. Mi dà un piccolo errore ma anzitutto ora
ho un compilatore vb che non conoscevo, poi è un'occasione
per mettere il naso nel linguaggio, cosa che avevo in
animo da un pezzo.
 
Lo so è quasi necroposting ma non credo se la prenderà
nessuno, ancora grazie :)
 
 
-- 
The man who invented autocorrect is dead.
May he roast in piss.
 

 nessuno, ancora grazie :)
 
Okay, come ho scritto il codice NON era testato, ORA l'ho provato ed in
effetti c'erano diversi errori che, avendolo buttato giù al volo... beh
comunque ora funziona; l'unica cosa che manca è il codice all'interno
della funzione "GetNewName" alla stessa arriva il nome attuale di un
file o di una cartella ed il tipo di oggetto "d" per le cartelle oppure
"f" per i files e la funzione dovrà restituire il nuovo nome (o lo
stesso nel caso in cui il file/cartella NON vada rinominato)
 
 
' dichiarazione variabili obbligatoria !!
Option Explicit
 
' globali
Dim fso, arg
 
' inizializza
Set fso = CreateObject("Scripting.FileSystemObject")
Set arg = WScript.Arguments
 
' bootstrap
WScript.Quit main(arg.Count, arg)
 
' main tipo "C"
Function main(argc, argv)
  Dim i, rc, err
  Dim dicFolders
  Dim fld
 
  ' inizializza
  err = 0
 
  ' carica l'elenco iniziale delle cartelle  
  Set dicFolders = CreateObject("Scripting.Dictionary")
  For i=0 to argc-1
    rc = LoadFolderList(argv(i), dicFolders)
    err = err + rc
  Next
  If err > 0 Then
    ' errore su caricamento elenco
    main = 1
    Exit Function
  End If
 
  ' rinomina come necessario
  rc = RenameFolders(dicFolders)
  if rc <> 0 Then
    ' errore su rename
    main = 2
    Exit Function
  End If
 
  ' ricarica l'elenco delle cartelle DOPO il rename
  Set dicFolders = CreateObject("Scripting.Dictionary")
  For i=0 to argc-1
    rc = LoadFolderList(argv(i), dicFolders)
    err = err + rc
  Next
  If err > 0 Then
    ' errore su caricamento elenco
    main = 3
    Exit Function
  End If
 
  ' elabora i files
  rc = ProcessFiles(dicFolders)
  if rc <> 0 Then
    ' errore su rename
    main = 4
    Exit Function
  End If
 
  main = err
End Function
 
 
' ====================================================
' elaborazione sottocartelle
' ====================================================
 
' carica la lista delle sottocartelle
Function LoadFolderList(sRootPath, dicFolders)
  Dim sPath
  Dim fld, sfd
 
  printf "LoadFolderList(" & sRootPath & ")"
 
  ' controlli
  If Not fso.FolderExists(sRootPath) Then
    printf "ERR: folder " & sRootPath & " doesn't exist."
    LoadFolderList = 1
    Exit Function
  End If
  sPath = fso.GetFolder(sRootPath).Path
 
  ' carica le sottocartelle in dicFolders
  LoadFolderList = RecursePath(sPath, dicFolders)
End Function
 
' esegue la ricorsione sulle sottocartelle
Function RecursePath(sPath, dicFolders)
  Dim fld, sfd
 
  printf "RecursePath(" & sPath & ")"
 
  Set fld = fso.GetFolder(sPath)
  For Each sfd In fld.SubFolders
    RecursePath sfd.Path, dicFolders
  Next
  ' la "root" per ultima !!!
  dicfolders.Add "F" & dicfolders.Count, fld.Path
  RecursePath = 0    
End Function
 
' rinomina (se necessario) le cartelle
Function RenameFolders(dicFolders)
  Dim sPath
  Dim rc, ret
 
  ret = 0
  For Each sPath In dicFolders.Items
    rc = RenameFolder(sPath)
    ret = ret + rc
  Next
  RenameFolders = ret
End Function
 
' rinomina (se necessario) una cartella
Function RenameFolder(sPathName)
  Dim fld, rc
  Dim sPath, sOldName, sNewName
 
  On Error Resume Next
 
  printf "RenameFolder(" & sPathName & ")"
 
  err.Clear
  rc = 0
  Set fld = fso.GetFolder(sPathName)
  If err.number <> 0 Then
    perror "RenameFolder(" & sPath & ")::GetFolder"
    RenameFolder = 1
    Exit Function  
  End If
 
  sPath = fld.ParentFolder
  sOldName = fld.Name
  sNewName = GetNewName(sOldName)
  If sNewName <> sOldName Then
    fld.Move fld.Path, sPath & "\" & sNewName
  End If
  If err.number <> 0 Then
    perror "RenameFolder(" & sPath & ")::Rename"
    rc = 1
  End If
 
  RenameFolder = rc  
End Function
 
' ====================================================
' elaborazione files
' ====================================================
 
' elabora i files
Function ProcessFiles(dicFolders)
  Dim sPathName
  Dim rc, err
 
  printf "ProcessFiles(" & dicFolders.Count & ")"
 
  err = 0
  For Each sPathName In dicFolders.Items
    rc = ScanFiles(sPathName)
    err = err + rc
  Next
  ProcessFiles = err  
End Function
 
' elabora i files di una cartella
Function ScanFiles(sPathName)
  Dim fld, fil, err, rc
 
  printf "ScanFiles(" & sPathName & ")"    
 
  err = 0
  Set fld = fso.GetFolder(sPathName)
  For Each fil In fld.Files
    rc = ProcessFile(fil.Path)
    err = err + rc
  Next
  ScanFiles = err
End Function
 
' elabora UN file
Function ProcessFile(sPathName)
  Dim fil, rc
  Dim sPath, sOldName, sNewName
 
  On Error Resume Next
  err.Clear
  rc = 0
 
  printf "ProcessFile(" & sPathName & ")"


 rinominato)
 
Dimenticavo, la logica dovrebbe essere abbastanza chiara, in breve lo
script fa una prima passata ricorsiva sulla cartella e sulle varie
sottocartelle e procede con il rename delle stesse, a seguire il codice
ricarica l'elenco cartelle e sottocartelle ed elabora i files contenuti
in ciascuna delle stesse
 
ciao
 
 

 elabora i files contenuti in ciascuna delle stesse
 
Ancora grazie. Ammetto che al momento non riesco a farlo
funzionare ma è un ottimo scheletro di partenza. Anche se
proveniendo dal C/C++ è una strada non in salita, comunque
è sempre un linguaggio da imparare. Prima o poi lo farò
funzionare :D


 imparare. Prima o poi lo farò funzionare :D
 
Puoi sempre buttare giù due righe di "C"; le API di base che ti servono
per spazzolare il filesystem, sono
 
https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findfirstfilea
 
 
https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findnextfilea
 
 
https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findclose
 
 
https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-movefile
 
 
la logica potrebbe essere la seguente:
 
Scorri in modo ricorsivo i files contenuti nella cartella indicata ed
in tutte le sottocartelle (e sotto sotto sotto... insomma, come ho
scritto, ricorsivamente) e li rinomini come necessario
 
Scorri in modo ricorsivo le sottocartelle e le rinomini come necessario
 
fatto :D
 
 

 servono per spazzolare il filesystem, sono
 
quanto segue è un pezzo di codice buttato giù al volo (ma testato e
funzionante) che mostra come elencare ricorsivamente tutti i files
all'interno di un albero di cartelle; come vedi ci vuole poco :D
 
 
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#include <memory.h>
#include <string.h>
 
#include <windows.h>
 
// scansione ricorsiva dei files
DWORD scanFiles(unsigned char *szPath)
{
  HANDLE            hFind;
  WIN32_FIND_DATA   tData;
  DWORD             dwErr, dwRet;
  unsigned char     *szMask;
 
  // init
  dwErr = dwRet = 0;
  memset(&tData, '\0', sizeof(tData));
  szMask = (unsigned char *)malloc(strlen(szPath) + 3);
  if (NULL == szMask)
  {
    fprintf(stderr, "malloc() failed\n");
    return(errno);
  }
 
  strcpy(szMask, szPath);
  strcat(szMask, "\\*");
 
  // inizia ricerca
  hFind = FindFirstFile(szMask, &tData);
  if (hFind == INVALID_HANDLE_VALUE) 
  {
    dwErr = GetLastError();
    fprintf(stderr, "%s: error 0x%X\n", szPath, dwErr);
    free(szMask);
    return(dwErr);
  }
 
  // ciclo su contenuti
  do
  {
    if (tData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
    {
      // ignora "." e ".."
      if ((0 != strcmp(tData.cFileName, ".")) && 
          (0 != strcmp(tData.cFileName, "..")))
      {
        // sottocartella
        free(szMask);
        szMask = (unsigned char *)malloc(strlen(szPath) + 
                                         strlen(tData.cFileName) + 3);
        if (NULL == szMask)
        {
          fprintf(stderr, "malloc() failed\n");
          FindClose(hFind);
          return(errno);
        }
        sprintf(szMask, "%s\\%s", szPath, tData.cFileName);
        dwErr = scanFiles(szMask);
        // qui andrebbe gestito eventuale errore (dwErr != 0)
      }
    } else {
      // file
      fprintf(stdout, "%s\\%s\n", szPath, tData.cFileName);
    }
  }
  while (FindNextFile(hFind, &tData) != 0);
 
  // controlla esito finale
  dwRet = GetLastError();
  if (ERROR_NO_MORE_FILES != dwRet) 
  {
    fprintf(stderr, "%s: error 0x%X\n", szPath, dwRet);
    dwErr = dwRet;
  }
 
  // termina
  FindClose(hFind);
  free(szMask);
  return(dwErr);
}
 
// main
int main(int argc, char *argv[])
{
  int i, err = 0;
 
  // check argomenti
  if (argc < 2)
  {
    fprintf(stderr, "uso: %s percorso [...percorso]\n", argv[0]);
    return(-1);
  }
 
  // elabora
  for (i=1; i<argc; i++)
  {
    if (0 != scanFiles(argv[i])) err++;
  }
 
  // fine
  return(err);
}
 
 
 

 all'interno di un albero di cartelle; come vedi ci vuole poco :D
 
Ok, avevo due minuti e l'ho riveduto, il codice che segue carica
l'intero elenco di files e sottocartelle in una lista linkata e poi
elabora la lista, da notare che gli elementi sono inseriti in ordine
inverso, per cui avremo qualcosa di questo tipo nella lista linkata
 
      x:\dir1\dir2\dir3\file1.abc
      x:\dir1\dir2\dir3\file2.abc
<DIR> x:\dir1\dir2\dir3
      x:\dir1\dir2\file3.abc
      x:\dir1\dir2\file4.abc
<DIR> x:\dir1\dir2
      x:\dir1\file5.abc
      x:\dir1\file6.abc
<DIR> x:\dir1
 
in questo modo il rename di file/cartelle è semplicissimo, dato che
basta rinominare l'elemento in base al tipo (file o cartella) senza
problemi, basta semplicemente implementare il codice necessario nelle
funzioni procFolder() e procFile() ... ed aggiungere un minimo di
codice per la gestione degli errori, il resto del codice dovrebbe
essere abbastanza chiaro e lineare
 
/*
** elaborazione ricorsiva files e cartelle
*/
 
// standard
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#include <memory.h>
#include <string.h>
 
// windows
#include <windows.h>
 
// dipende da compilatore
#ifndef FALSE
#define BOOL  int
#define FALSE 0
#define TRUE  (!FALSE)
#endif
 
// lista elementi
typedef struct _tag_elements
{
  unsigned char         *szPath;      // percorso
  unsigned char         *szName;      // nome elemento
  BOOL                  bIsFolder;    // tipo elemento
  struct _tag_elements  *pNext;       // elemento successivo
} FLD_ELEM; 
 
// puntatori della lista linkata
FLD_ELEM    *gpRoot = NULL;           // radice lista
FLD_ELEM    *gpLast = NULL;           // ultimo o successivo
 
// inserisce un elemento nella lista
BOOL push_elem(unsigned char *szPath, 
               unsigned char *szName, 
               BOOL bIsFolder)
{
  FLD_ELEM  *pElem;
 
  // alloca e valorizza l'elemento
  pElem = (FLD_ELEM *)calloc(1, sizeof(FLD_ELEM));
  if (NULL == pElem) return(FALSE);
  pElem->szPath = strdup(szPath);
  pElem->szName = strdup(szName);
  pElem->bIsFolder = bIsFolder;
  if ((NULL == pElem->szPath) || (NULL == pElem->szName)) {
    if (NULL != pElem->szPath) free(pElem->szPath);
    if (NULL != pElem->szName) free(pElem->szName);
    free(pElem);
    return(FALSE);
  }
 
  // inserisce in lista
  if (NULL == gpRoot)
  {
    // primo elemento
    gpRoot = gpLast = pElem;
  } else {
    // elementi successivi
    gpLast->pNext = pElem;
    gpLast = pElem;
  }
 
  // tutto ok
  return(TRUE);
}
 
// preleva sequenzialmente elementi dalla lista
FLD_ELEM *get_elem(BOOL bStart)
{
  FLD_ELEM *pElem;
 
  if (bStart) {
    // primo elemento
    pElem = gpRoot;
  } else {
    // elemento successivo
    pElem = gpLast->pNext;
  }
  gpLast = pElem;
  return(pElem);
}
 
// dealloca la lista
void free_elem()
{
  FLD_ELEM  *pElem;
 
  // cicla e rilascia elementi
  pElem = gpRoot;
  while (NULL != pElem)
  {
    gpLast = pElem->pNext;
    free(pElem->szPath);
    free(pElem->szName);
    free(pElem);
    pElem = gpLast;
  }
}
 
// scansione ricorsiva di cartelle/files
DWORD scanFolders(unsigned char *szPath)
{
  HANDLE            hFind;
  WIN32_FIND_DATA   tData;
  DWORD             dwErr, dwRet;
  unsigned char     *szMask;
 
  // init
  dwErr = dwRet = 0;
  memset(&tData, '\0', sizeof(tData));
  szMask = (unsigned char *)malloc(strlen(szPath) + 3);
  if (NULL == szMask)
  {
    fprintf(stderr, "malloc() failed\n");
    return(errno);
  }
 
  strcpy(szMask, szPath);
  strcat(szMask, "\\*");
 
  // inizia ricerca
  hFind = FindFirstFile(szMask, &tData);
  if (INVALID_HANDLE_VALUE == hFind) 
  {
    dwErr = GetLastError();
    fprintf(stderr, "%s: error 0x%X\n", szPath, dwErr);
    free(szMask);
    return(dwErr);
  }
 
  // ciclo su contenuti
  do
  {
    if (tData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
    {
      // ignora "." e ".."
      if ((0 != strcmp(tData.cFileName, ".")) && 
          (0 != strcmp(tData.cFileName, "..")))
      {
        // sottocartella
        free(szMask);
        szMask = (unsigned char *)malloc(strlen(szPath) + 
                                         strlen(tData.cFileName) + 3);
        if (NULL == szMask)
        {
          fprintf(stderr, "malloc() failed\n");
          FindClose(hFind);
          return(errno);
        }
        // prima elabora sottocartelle e poi inserisce in lista
        sprintf(szMask, "%s\\%s", szPath, tData.cFileName);
        dwErr = scanFolders(szMask);
        if (0 != dwErr) {
          fprintf(stderr, "ERR 0x%X %s\n", dwErr, szMask);
        }
        if (!push_elem(szPath, tData.cFileName, TRUE)) {
          fprintf(stderr, "ERR: 0x%X push_elem\n", errno);
        }
      }
    } else {
      // file
      //fprintf(stdout, "%s\\%s\n", szPath, tData.cFileName);
      if (!push_elem(szPath, tData.cFileName, FALSE)) {
        fprintf(stderr, "ERR: 0x%X push_elem\n", errno);
      }
    }
  }
  while (FindNextFile(hFind, &tData) != 0);
 
  // controlla esito finale
  dwRet = GetLastError();
  if (ERROR_NO_MORE_FILES != dwRet) 
  {
    fprintf(stderr, "%s: error 0x%X\n", szPath, dwRet);
    dwErr = dwRet;
  }
 
  // termina
  FindClose(hFind);
  free(szMask);
  return(dwErr);
}
 
// elabora una cartella
DWORD procFolder(FLD_ELEM *pElem)
{
  fprintf(stdout, "<DIR> %s\\%s\n", pElem->szPath, pElem->szName);
  return(0);
}
 
// elabora un file
DWORD procFile(FLD_ELEM *pElem)
{
  fprintf(stdout, "      %s\\%s\n", pElem->szPath, pElem->szName);
  return(0);
}
 
// elabora cartelle/files dalla lista
DWORD procFolders()
{
  FLD_ELEM *pElem;
  DWORD dwErr, dwRet;
 
  pElem = get_elem(TRUE);
  while (NULL != pElem)
  {
    if (pElem->bIsFolder) {
      dwRet = procFolder(pElem);
    } else {
      dwRet = procFile(pElem);
    }
    if (dwRet) dwErr = dwRet;
    pElem = get_elem(FALSE);
  }
  free_elem();
  return(dwErr);
}
 
// main
int main(int argc, char *argv[])
{
  int i, err = 0;
 
  // check argomenti
  if (argc < 2)
  {
    fprintf(stderr, "uso: %s percorso [...percorso]\n", argv[0]);
    return(-1);
  }
 
  // elabora
  for (i=1; i<argc; i++)
  {
    if (0 != scanFolders(argv[i])) err++;
  }
  if (0 != procFolders()) err++;
 
  // fine
  return(err);
}
 
 
 

 cui avremo qualcosa di questo tipo nella lista linkata
 
Io invece devo andare a curare la memoria... Thunderbird
mi cancella in automatico i vecchi post ma mi pare che
quello di partenza abbia parecchi mesi. Siccome mi ritrovo
sempre con quel problema avevo inziato a scriverci una
libreria così che mi potesse risolvere quel problema e poi
potesse essere riutilizzata. Il buffo è che l'ho fatto da
un pezzo e me ne sono dimenticato. Supporta sostituzioni
in stringhe e conversione da unicode in normale ASCII con
tanto di traslitterazione degli alfabeti più comuni, oltre
che a fare il lavoro di rinomina.
 
Come sempre faccio trenta ma non trentuno, avrei voluto
metterla su sourceforge ma il mio inglese è pessimo, non
sono un programmatore quindi avrà bachi e malfunzionamenti
che ora non vedo e alla fine lasciai perdere. Uno di
questi gg la metto su dropbox e posterò il link.


 potesse essere riutilizzata.
 
Scusa ma se non ricordo male, su è possibile impostare le opzioni per
la cancellazione dei vecchi messaggi (tempo) o disabilitare del tutto
la funzione, non vedo perchè ti serva una libreria a parte
 
... o forse mi sfugge qualcosa ?
 
Per quanto riguarda i sorgenti, invece di SF puoi usare github :)
 

 Scusa ma se non ricordo male, su TB è possibile
 
*fixed*
 
 
 

 github :)
 
Penso che lo farò, adesso vedo di fare un po' di
rifinitura e mi butto :D


 anzi appena posso aprirò thread di richiesta lumi...
 
Ah ok, non avevo capito; ad ogni modo il codice che ho postato è molto
semplice, un approccio migliore sarebbe probabilmente quello di buttare
giù un sistema multithread, anche se forse sarebbe esagerato :) ad ogni
modo, se volessi provarci, qui di seguito il codice per una coda FIFO
che ho usato in varie occasioni e che evita di usare un "lock" in fase
di inserimento per cui l'inserimento è velocissimo :) e funziona alla
grande anche in multithreading
 
 
 
/*
******************************   Queue.h
*/
 
#ifndef QUEUE_H
#define QUEUE_H
#ifdef __cplusplus
extern "C"
{
#endif
 
#define WIN32_LEAN_AND_MEAN
//#define _WIN32_WINNT 0x0500
 
#include <Windows.h>
 
/* The queue node object */
typedef struct S_QueueNode
{
    struct S_QueueNode  *pNext;             // next element
    LPVOID              pObj;               // payload
} QNODE, *LPQNODE;
 
/* The queue object */
typedef struct S_Queue
{
    CRITICAL_SECTION    csLockBack;         // lock semaphore
    LPQNODE             pFront;             // front node
    LPQNODE             pBack;              // back node
    LPQNODE             pDummy;             // temp node
    LONG                lCount;             // elements
    LONG                lAllocs;            // allocations
} QUEUE, *LPQUEUE;
 
// NOTE: this is a FIFO type queue, not a STACK
BOOL InitQueue(LPQUEUE pQueue);             // Inits a queue
VOID FreeQueue(LPQUEUE pQueue);             // Frees a queue
BOOL Enqueue(LPQUEUE pQueue, LPVOID pObj);  // Enqueues an object
LPVOID Dequeue(LPQUEUE pQueue);             // Dequeues an object
DWORD QueueCount(LPQUEUE pQueue);           // Returns elements count
 
// user macros - use those in your code
#define Q_ALLOCATE  InitQueue
#define Q_DESTROY   FreeQueue
#define Q_COUNT     QueueCount
#define Q_APPEND    Enqueue
#define Q_EXTRACT   Dequeue
 
#ifdef __cplusplus
}
#endif
#endif
 
 
/*
******************************   Queue.c
*/
 
#include <stdio.h>
#include <assert.h>
#include <malloc.h>
 
#include "queue.h"
 
// inline macros
#define MALLOC(o)     malloc(sizeof(o)); InterlockedIncrement(&pQueue->lAllocs)
#define FREE(o)       if (o) { free(o); o=NULL; InterlockedDecrement(&pQueue->lAllocs); }
#define CLEAR(o,s)    memset(o, '\0', s)
 
// spincount for locks
#define Q_SPIN        3989
 
// Inits a queue
BOOL InitQueue(LPQUEUE pQueue)
{
  assert( NULL != pQueue );
  CLEAR(pQueue, sizeof(QUEUE));
  if (!InitializeCriticalSectionAndSpinCount(&pQueue->csLockBack, Q_SPIN)) return(FALSE);
  pQueue->lCount = pQueue->lAllocs = 0;
  pQueue->pBack = pQueue->pFront = pQueue->pDummy  = MALLOC( QNODE );
  pQueue->pDummy->pNext = NULL;
  pQueue->pDummy->pObj = NULL;
  if (!pQueue->pDummy) {
    FreeQueue(pQueue);
    return(FALSE);
  }
  return(TRUE);
}
 
// Frees a queue
VOID FreeQueue(LPQUEUE pQueue)
{
  assert( pQueue->lCount == 0 );
  if (pQueue->pFront != pQueue->pDummy) FREE(pQueue->pFront);
  FREE(pQueue->pDummy);
  assert(pQueue->lAllocs == 0);
  DeleteCriticalSection(&pQueue->csLockBack);
}
 
// Returns the elements in queue
DWORD QueueCount(LPQUEUE pQueue)
{
  DWORD dwCount = 0;
 
  // add 0 to obtain current value
  dwCount =  InterlockedExchangeAdd(&pQueue->lCount, 0);
  return(dwCount);
}
 
// Enqueues an object
BOOL Enqueue(LPQUEUE pQueue, LPVOID  pObj)
{
  LPQNODE pNode, pBack, pNewBack;
  LONG lContention = 0;
 
  // Alloc a node
  pNode = MALLOC(QNODE);
  if (!pNode) return(FALSE);
  pNode->pNext = NULL;
  pNode->pObj = pObj;
  for(;;) {
    // Read the back
    pBack = InterlockedCompareExchangePointer((LPVOID*)&pQueue->pBack, NULL, NULL );
    // Try and link the new node in
    pNewBack = InterlockedCompareExchangePointer((LPVOID*)&pBack->pNext, pNode, NULL);
    if(!pNewBack) break;
    // Try and advance the back to the new back
    InterlockedCompareExchangePointer((LPVOID*)&pQueue->pBack, pNewBack, pBack);
    lContention++;
  }
  // Try and point the back to the new node
  InterlockedCompareExchangePointer((LPVOID*)&pQueue->pBack, pNode, pBack);
  // update the nodes counter
  InterlockedIncrement(&pQueue->lCount);
 
#ifdef __DEBUG__
  // check and signal lock contentions
  if (lContention ) {
    printf("Enqueue contention: %d\n", lContention);
  }
#endif
 
  return(TRUE);
}
 
/* Dequeues an object */
LPVOID Dequeue(LPQUEUE pQueue)
{
  LPVOID pObj;
  LPQNODE pNext, pFront;
 
  // acquire the lock and set the start ptr
  EnterCriticalSection(&pQueue->csLockBack);
  pFront = pQueue->pFront;
  // Read the next node
  pNext = InterlockedCompareExchangePointer((LPVOID)&pFront->pNext, NULL, NULL);
  if (!pNext) {
    LeaveCriticalSection(&pQueue->csLockBack);
    return(NULL);
  }
  // Get the object, swing the front to the next, unlock
  pObj = pNext->pObj;
  pQueue->pFront = pNext;
  InterlockedDecrement(&pQueue->lCount);
  LeaveCriticalSection(&pQueue->csLockBack);
  // Dump the unwanted node
  if (pFront != pQueue->pDummy) FREE(pFront);
 
  return pObj;
}
 
 
 
 

 funziona alla grande anche in multithreading
 
 
Con questa avrò da studiare mesi... Brutta bestiaccia il
multithreading :D


 multithreading :D
 
Naa, ho scritto diversa roba in MT, una volta che hai afferrato i
concetti di base, non è complicato, devi semplicemente considerare che
NON esistono variabili globali, o meglio, qualsiasi variabile globale
DEVE essere condizionata da un meccanismo di accesso serializzato in
qualche modo, così da evitare problemi; poi per carità ci sono anche
altri problemi, ma il più banale e quello che stoppa un mucchio di
gente è quello; per capirci
 
 
int valore = 0
 
 
* thread 1
 
 valore++;
 
 
* thread 2
 
 valore--;
 
 
* thread 3
 x = valore;
 
 
quanto vale "valore" :) ? (Ok, esempio BANALE, ma credo renda l'idea)
 
 
 
 
 
 
 

 di directory con relativi file i cui nomi (sia di file che
 
Avevo due minuti...
 
@echo off
:
INIT
rem --- controlla parametri
if (%2)==(f) goto PARSE
if (%2)==(d) goto PARSE
:
:PROCESS
rem --- elabora files/cartelle
setlocal
for /f "delims=" %%f in ('dir %1 /s/b') do call %0 "%%f" f
for /f "delims=" %%f in ('dir %1 /s/b/ad') do call %0 "%%f" d
endlocal
goto QUIT
:
:PARSE
rem --- ricava tipo, path e nome
set TYPE=%2
set BASE=%~dp1
set NAME=%~nx1
:
:RENAME
rem --- esegue il rename (se necessario)
echo %TYPE% %BASE% %NAME%
rem ... da implementare come desiderato ...
:
:QUIT
 
 
niente di che, ma potrebbe essere una base
 
 
 


Leggo solo adesso questo thread... Gran bel lavoro!
Io comunque in passato ho risolto elegantemente con Total Commander:
per prima cosa ho fatto la visualizzazione ricorsiva dei file presenti 
nelle cartelle e sotto cartelle (112490 files in 871 Gb)
La mia struttura è molto semplice:
Cartella Primaria -> lettera alfabeto
Sottocartella -> artista
Sotto sotto cartella -> album per data di pubblicazione
eventuali sotto cartelle per album multi CD
titolo del brano con numerazione originale (01-titolo.mp3)
 
sulla visualizzazione di tutti i brani (erano di meno quando l'ho 
fatto, circa 48000) ho applicato il Multi-Rinomina presente in Total 
Commander
impostato così:
https://i.imgur.com/n13TWtR.png
 
 
-- 
<=)O - ByE bYe By TaF® - O(=> *Pls. DFDT*
"Fama di loro il mondo esser non lassa
misericordia e giustizia li sdegna
non ragioniam di lor, ma guarda e passa"