Tag the file with dontcopy flag and then install it programmatically in CurStepChanged(ssInstall) (or ssPostInstall).
This will work well, only if the file is not huge. Otherwise the installer will unpleasantly hang. For a good user experience with huge files, more complex solution is needed.
#define TheFileName "thefile.txt"
[Files]
Source: "{#TheFileName}"; Flags: dontcopy
[Code]
procedure CurStepChanged(CurStep: TSetupStep);
var
  RootPath: string;
  TempPath: string;
  DestPath: string;
  FindRec: TFindRec;
  Count: Integer;
begin
  if CurStep = ssInstall then
  begin
    Log('Extracting {#TheFileName}...');
    ExtractTemporaryFile('{#TheFileName}');
    TempPath := ExpandConstant('{tmp}\{#TheFileName}');
    RootPath := ExpandConstant('{app}');
    Log(Format('Searching in "%s"...', [RootPath]));
    Count := 0;
    if not FindFirst(RootPath + '\*', FindRec) then
    begin
      Log(Format('"%s" not found.', [RootPath]));
    end
      else
    begin
      try
        repeat
          if (FindRec.Name <> '.') and (FindRec.Name <> '..') and
             (FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY <> 0) then
          begin
            Log(Format('Found "%s".', [FindRec.Name]));
            DestPath := RootPath + '\' + FindRec.Name + '\{#TheFileName}';
            if FileCopy(TempPath, DestPath, False) then
            begin
              Log(Format('The file was installed to "%s".', [DestPath]));
              Inc(Count);
            end
              else
            begin
              Log(Format('Error installing the file to "%s".', [DestPath]));
            end;
          end;
        until not FindNext(FindRec);
      finally
        FindClose(FindRec);
      end;
      if Count = 0 then
      begin
        Log(Format('No subfolder to install file "%s" to was found in "%s".', [
          '{#TheFileName}', RootPath]));
      end
        else
      begin
        Log(Format('File "%s" was installed to %d subfolder(s) of "%s".', [
          '{#TheFileName}', Count, RootPath]));
      end;
    end;
  end;
end;
Alternatively, if you have a fixed set of folders, you can generate entry for each folder in the [Files] section using preprocessor:
[Files]
#define FolderEntry(Name) \
    "Source: ""C:\source\*""; DestDir: ""{app}\" + Name + """; " + \
         "Check: CheckDir('" + Name + "')"
#emit FolderEntry('2023')
#emit FolderEntry('2024')
#emit FolderEntry('2025')
[Code]
function CheckDir(DirName: string): Boolean;
begin
  Result := DirExists(ExpandConstant('{app}') + '\' + DirName);
end;
If you add SaveToFile to the end of the script:
#expr SaveToFile(AddBackslash(SourcePath) + "Preprocessed.iss")
... then you should see in Preprocessed.iss that the code generates a script like this:
[Files]
Source: "C:\source\*"; DestDir: "{app}\2023"; Check: CheckDir('2023')
Source: "C:\source\*"; DestDir: "{app}\2024"; Check: CheckDir('2024')
Source: "C:\source\*"; DestDir: "{app}\2025"; Check: CheckDir('2025')