Page 1 of 3 1 2 3 LastLast
Results 1 to 15 of 35

Thread: Plaatjes kopieeren in nog aan te maken mappen

  1. #1

    Plaatjes kopieeren in nog aan te maken mappen

    Hallo allemaal,

    Ik loop tegen een probleem aan te hikken.
    Ik heb namelijk een verzameling plaatjes (bijna 200.000 stuks) die in één map staan.
    Als die wordt ingelezen duurt dat heel erg lang, dus zat ik te denken om de bestanden onder te brengen in verschillende mappen.
    Omdat handmatig te doen is natuurlijk een hele klus, dus zat ik er aan te denken om daar een programma voor te maken.

    Zo is het de bedoeling dat het programma elke map aanmaakt, liefst opvolgend, en vervolgens een vastgesteld aantal plaatjes in deze map plaatst.
    Nu ben ik niet echt thuis in deze wereld, dus dacht ik ik gaat eens raad vragen bij de experts.
    Mijn vragen zijn dan dus ook.

    1. is mijn idee uberhaupt wel mogelijk
    2. Hoe pak ik dit aan
    3. Is er ergens op het internet een voorbeeld, want ik heb wel zitten zoeken maar echt ver om ik niet.

    Alvast bedankt

    Willem

  2. #2
    Quote Originally Posted by WillemS View Post
    1. is mijn idee uberhaupt wel mogelijk
    Ja

    Quote Originally Posted by WillemS View Post
    Hallo allemaal,
    2. Hoe pak ik dit aan
    Hangt er vanaf.
    Waar moeten die mappen staan?
    Hoe moeten de mappen heten?
    Hoe bepaal je welke bestanden in welke mappen terechtkomen?

    Wat je nodig hebt:
    - FindFirst/FindNext
    - CreateDir
    - Een functie ombestanden te verplaatsen

    Bart

  3. #3

  4. #4
    mov rax,marcov; push rax marcov's Avatar
    Join Date
    Apr 2004
    Location
    Ehv, Nl
    Posts
    10,357
    Ik doe dit, maar hou het aantal mappen beperkt. Teveel mappen, en scannen van de struktuur gaat ook erg lang duren. Ik houd het op een paar duizend per map. (maar ik heb thumbnails/previews e.d. uit staan)

    Ik heb een struktuur met 550.00 files met relatief weinig files per directory (50-100) en het scannen daarvan duurt 20 minuten. (10 minuten met Aniversary edition en eerder, creator is trager om een of andere reden)

    rvk: je kan het waarschijnlijk in 500 andere talen doen, maar dit is een delphi forum. Dat gezegd, het grote voordeel van het in een wat meer capabele taal (dan batch) te doen, is

    1. dat je het simpel kan aanpassen als je selectie kriterium (of aantal files per dir) varieert of complexer wordt.
    2. unicode clean bent in D2009+ + \\?\ trucjes om directory nesting te vemijden.
    3. je kan het zo schrijven dat je minder vaak door directories heen scanned (cache van de eerste inlees actie). In batch is elke for over een filemask direct weer een directory traversal.

    Als je programma deze datastructuur beheert, hou een cache file op disk met de data.

    Aanpak:
    - forcedirectories is makkelijker dan createdir.
    - scan eerst met findfirst/next en stop alles in een tstringlist
    - maak alle directories aan met forcedirectories.
    - loop over de tstringlist heen, en switch iedere zoveel entries naar de volgende dir (of hoe je het ook wil sorteren, ik doe het op de eerste letters van de file)

  5. #5
    John Kuiper
    Join Date
    Apr 2007
    Location
    Almere
    Posts
    8,747
    IS TStringlist niet gelimiteerd qua grootte?
    Delphi is great. Lazarus is more powerfull

  6. #6
    Quote Originally Posted by jkuiper View Post
    IS TStringlist niet gelimiteerd qua grootte?
    200.000 x 255 karakters is zo'n 51MB. Dat moet wel lukken met een TStringList.

    Maar het kan natuurlijk ook zonder want je kunt ook gewoon tellen tijdens de findfirst/findnext en gelijk daar de movefile doen.

  7. #7
    Een stringlist was gelimiteerd, maar dat lijkt in recentere Delphi's aangepast.

    In System.Classes vind ik nog wel de constante, maar die wordt in de unit niet meer gebruikt:

    Delphi Code:
    1. const
    2.   MaxListSize = MaxInt div 16 deprecated;

    Maar dan nog steeds wordt de capacity opgeslagen in een Integer, dus meer dan 2,1 miljard krijg je er niet in. In elk geval lijkt het me ruim genoeg voor de toepassing.
    1+1=b

  8. #8
    mov rax,marcov; push rax marcov's Avatar
    Join Date
    Apr 2004
    Location
    Ehv, Nl
    Posts
    10,357
    Quote Originally Posted by jkuiper View Post
    IS TStringlist niet gelimiteerd qua grootte?
    Gesorteerde stringlists hebben problemen dat insertion performance wegzakt met al een paar honderdduizend. Ongesorteerde alleen in extreme gevallen.

    200000 is een randgeval denk ik, kan nog net met zelfs gesorteerde tstringlist. Als het iets centraal is dat moet schalen gebruik ik meestal lightcontainer. Die is ook niet unbounded (met de huidige tuning krijgt die dezelfde problemen rond de 6 miljoen, afhankelijk van de belading), en heeft als extra voordeel dat ie ook werkt voor een aantal andere keys van andere valuetypes (het is een generic met een compare functie, voor gedefiniered zijn tdatetime, int etc) en valuetype values. (dus het mag ook een record zijn, niet perse een class)
    Last edited by marcov; 09-Sep-17 at 18:16.

  9. #9
    Dank voor de antwoorden

    Jullie geven aan dat met forcedirectories het gemakkelijker is om eerst alle mappen aan te maken.
    Nu is mijn bescheiden mening (mijn programmeer kennis is niet al te groot) dat men daar createdir voor zou gebruiken.
    Wat is het verschil tussen beide.

    In het weekend zitten zoeken naar find/first/next daar zijn nog al wat voorbeelden van te vinden, daar ben ik wel even zoet mee :-)


    Toch nog een klein vraagje, jullie hebben het over het vullen van een stringlist waar een limiet op zat binnen Delphi.
    Zelf gebruik ik Lazarus, is dat daar ook van op toepassing?

  10. #10
    mov rax,marcov; push rax marcov's Avatar
    Join Date
    Apr 2004
    Location
    Ehv, Nl
    Posts
    10,357
    Forcedirectories is een lusje om createdir heen, dat ook meerdere paths tegelijktertijd kan aanmaken. Ik heb een directory images/ en dan daar de dagen van de maand onder. Als ik dus

    Delphi Code:
    1. for i:=1 to 31
    2.         forcedirectories ('images/'+inttostr(i));

    doe, dan wordt images ook aangemaakt indien nodig

    Gesorteerde tstringlists hebben de zelfde limitatie in Lazarus, maar dat is denk ik voor jou niet relevant, omdat je niet hoeft te sorteren

  11. #11
    Ik weet niet helemaal waarom je een TStringList nodig zou hebben tenzij je de bestanden in een bepaalde volgorde in je subdirectories wilt hebben. Als je gewoon recht toe recht aan de bestanden wilt verplaatsen, ongeacht de naam dan kun je gewoon uit met FindFirst/FindNext.

    Heel simplistisch voorbeeld is dan:
    Delphi Code:
    1. var
    2.   Counter: integer;
    3.   BaseDirectory, TargetDirectory: string;
    4.   SearchRec: TSearchRec;
    5. begin
    6.   BaseDirectory := IncludeTrailingPathDelimiter('C:\Temp');
    7.   TargetDirectory := '';
    8.   Counter := 0;
    9.  
    10.   if FindFirst(BaseDirectory + '*.*', faAnyFile, SearchRec) = 0 then
    11.   begin
    12.  
    13.     repeat
    14.  
    15.       if (SearchRec.Attr and faDirectory) <> faDirectory then // faAnyFile geeft ook directories terug, die willen we niet
    16.       begin
    17.  
    18.         Inc(Counter); // hou een tellen bij per file
    19.  
    20.         if Counter mod 1000 = 1 then // per 1000
    21.         begin
    22.           // we hoeven alleen de directory aan te maken als we op een veelvoud van 1000 zitten
    23.           TargetDirectory := BaseDirectory + Format('%.3d', [Counter div 1000 + 1]);
    24.           if not ForceDirectories(TargetDirectory) then
    25.             raise Exception.CreateFmt('Error creating directory: ''%s''', [TargetDirectory]);
    26.         end;
    27.  
    28.         // de werkelijke verplaatsing
    29.         if not RenameFile(BaseDirectory + SearchRec.Name, TargetDirectory + '\' + SearchRec.Name) then
    30.           raise Exception.CreateFmt('Error moving file: ''%s''', [BaseDirectory + SearchRec.Name]);
    31.  
    32.       end;
    33.  
    34.     until FindNext(SearchRec) <> 0;
    35.  
    36.     FindClose(SearchRec);
    37.  
    38.   end;
    39. end;

    (oeps, heb ik nou teveel laten zien )

  12. #12
    Dank je wel Rik,

    Of je te veel laat zien, ik klaag niet, maar enorm bedankt :-).

    Overigens kwam ik dit tegen op stackoverflow, had alleen zelf de indruk dat dit niet echt geheel compleet was

    Code:
    procedure TForm1.Button3Click(Sender: TObject);
    begin
      ProcessDir(SourceDir);
    end;
    
    procedure TForm1.ProcessDir(const SourceDirName: string);
    
    var
      NoOfFilesFoundInSourceDir, i, NoOfFilesCopiedOK : integer;
      FilesFoundToCopy : TStringList;
      SourceDirectoryAndFileName, SubDirStructure, FinalisedDestDir, FinalisedFileName : string;
    
    begin
      Memo1.Lines.Clear;
      SubDirStructure := '';
      FinalisedDestDir := '';
      NoOfFilesFoundInSourceDir := 0;
      NoOfFilesCopiedOK := 0;
    
      // Ensures the selected source directory is set as the directory to be searched
      // and then fina all the files and directories within, storing as a StringList.
    
      SetCurrentDir(SourceDirName);
      FilesFoundToCopy := FindAllFiles(SourceDirName, '*', True);
      NoOfFilesFoundInSourceDir := FilesFoundToCopy.Count;
    
      try
        for i := 0 to FilesFoundToCopy.Count -1 do
          begin
            Memo1.Lines.Add('File Index : '+IntToStr(i)+' File Name: '+FilesFoundToCopy.Strings[i]);
            SourceDirectoryAndFileName := ChompPathDelim(CleanAndExpandDirectory(FilesFoundToCopy.Strings[i]));
    
        // Determine the source sub-dir structure, from selected dir downwards
    
        SubDirStructure := IncludeTrailingPathDelimiter(ExtractFileDir(SourceDirectoryAndFileName));
    
        // Now concatenate the original sub directory to the destination directory and form the total path, inc filename
        // Note : Only directories containing files will be recreated in destination. Empty dirs are skipped.
        // Zero byte files are copied, though, even if the directory contains just one zero byte file.
    
        FinalisedDestDir := DestDir+SubDirStructure;
        FinalisedFileName := ExtractFileName(FilesFoundToCopy.Strings[i]);
    
        // Now create the destination directory structure, if it is not yet created. If it exists, just copy the file.
    
        if not DirPathExists(FinalisedDestDir) then
          begin
            if not ForceDirectories(FinalisedDestDir) then
              begin
                ShowMessage(FinalisedDestDir+' cannot be created.');
              end;
          end;
    
        // Now copy the files to the destination dir
    
        if not FileUtil.CopyFile(SourceDirectoryAndFileName, FinalisedDestDir+FinalisedFileName, true) then
          begin
            ShowMessage('Failed to copy file : ' + SourceDirectoryAndFileName)
          end
        else
        NoOfFilesCopiedOK := NoOfFilesCopiedOK + 1;
      end;
      finally
        FilesFoundToCopy.free;
      end;
      ShowMessage('Total files copied OK : ' + IntToStr(NoOfFilesCopiedOK));
    end;
    Last edited by GolezTrol; 11-Sep-17 at 18:40.

  13. #13
    Quote Originally Posted by WillemS View Post
    Overigens kwam ik dit tegen op stackoverflow, had alleen zelf de indruk dat dit niet echt geheel compleet was
    Op zich is die code voor waar het bedoeld is wel compleet.

    Het is bedoeld om een complete directory, inclusief alle subdirectories, naar een andere directory te kopieren. Het maakt gebruik van FindAllFiles() om eerst recursive alle files in een stringlist te zetten. Daarna worden al deze files gekopieerd (inclusief het aanmaken van de subdirectories).

    Dat is dus niet helemaal wat jij had beschreven maar voor wat de vraag op stackoverflow was, is de code goed.

  14. #14
    mov rax,marcov; push rax marcov's Avatar
    Join Date
    Apr 2004
    Location
    Ehv, Nl
    Posts
    10,357
    Quote Originally Posted by rvk View Post
    Ik weet niet helemaal waarom je een TStringList nodig zou hebben tenzij je de bestanden in een bepaalde volgorde in je subdirectories wilt hebben. Als je gewoon recht toe recht aan de bestanden wilt verplaatsen, ongeacht de naam dan kun je gewoon uit met FindFirst/FindNext.
    Je modificeert een lijst (rename) terwijl je hem nog leest (findfirst/findnext). ik weet niet hoe veilig dit is (vooral multiplatform en met veel files in directories)

  15. #15
    Quote Originally Posted by marcov View Post
    Je modificeert een lijst (rename) terwijl je hem nog leest (findfirst/findnext). ik weet niet hoe veilig dit is (vooral multiplatform en met veel files in directories)
    Ja, een rename van een file zou inderdaad een geldige reden kunnen zijn om eerst alles in een TStringList te plaatsen.

    Maar we hebben het hier niet over een normale rename maar een move naar een andere directory. En dan maakt het dus niets uit. Op elk platform zal dit gewoon goed gaan. Findnext zal niet in één keer andere files vinden.

Page 1 of 3 1 2 3 LastLast

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •