@@ -397,8 +397,9 @@ public ProcessingStatistics ProcessMultipleLevels(
397397 // Use a concurrent queue to manage files/directories to process
398398 ConcurrentQueue < string > filesToProcess = new ( filePathes ) ;
399399
400- // Track files already processed or queued to prevent duplicates
401- HashSet < string > processedFiles = new ( filePathes , StringComparer . OrdinalIgnoreCase ) ;
400+ // Track files already processed, queued, or created as output to prevent duplicates
401+ // This includes both input files and output files generated during processing
402+ HashSet < string > processedOrOutputFiles = new ( filePathes , StringComparer . OrdinalIgnoreCase ) ;
402403 object processedFilesLock = new ( ) ;
403404
404405 // Consume (process) input files
@@ -417,6 +418,9 @@ public ProcessingStatistics ProcessMultipleLevels(
417418 // to avoid race conditions where files are scanned while still being written
418419 ConcurrentBag < string > outputDirectories = new ( ) ;
419420
421+ // Collect output files to mark them as processed (prevents re-processing .jkr.bin files)
422+ ConcurrentBag < string > outputFiles = new ( ) ;
423+
420424 // Use Interlocked to safely disable stage processing after first file
421425 int stageContainerFlag = inputArguments . stageContainer ? 1 : 0 ;
422426 Parallel . ForEach ( currentBatch , parallelOptions , inputFile =>
@@ -439,11 +443,20 @@ public ProcessingStatistics ProcessMultipleLevels(
439443 // Report progress
440444 progressCallback ? . Invoke ( stats . HandledFiles , stats . TotalFiles , inputFile ) ;
441445
442- // Collect output directories for deferred processing
443- // This prevents race conditions where files are scanned while being written
444- if ( inputArguments . recursive && result . OutputPath != null && _fileSystem . DirectoryExists ( result . OutputPath ) )
446+ // Track output for deferred processing
447+ if ( result . OutputPath != null )
445448 {
446- outputDirectories . Add ( result . OutputPath ) ;
449+ if ( inputArguments . recursive && _fileSystem . DirectoryExists ( result . OutputPath ) )
450+ {
451+ // Output is a directory - scan it later for new files
452+ outputDirectories . Add ( result . OutputPath ) ;
453+ }
454+ else if ( _fileSystem . FileExists ( result . OutputPath ) )
455+ {
456+ // Output is a file - mark it as processed to prevent re-queuing
457+ // This prevents .jkr.bin files from being picked up by *.bin pattern
458+ outputFiles . Add ( result . OutputPath ) ;
459+ }
447460 }
448461 }
449462 catch ( ReFrontierException ex )
@@ -455,13 +468,32 @@ public ProcessingStatistics ProcessMultipleLevels(
455468 if ( inputArguments . verbose )
456469 _logger . WriteLine ( $ "Skipping { inputFile } : { ex . Message } ") ;
457470 }
471+ catch ( IOException ex )
472+ {
473+ stats . IncrementError ( ) ;
474+ progressCallback ? . Invoke ( stats . HandledFiles , stats . TotalFiles , inputFile ) ;
475+
476+ // Log file access errors (e.g., file locked by another process)
477+ if ( inputArguments . verbose )
478+ _logger . WriteLine ( $ "Skipping { inputFile } : { ex . Message } ") ;
479+ }
458480 } ) ;
459481
482+ // Mark all output files as processed to prevent them from being re-queued
483+ // This is critical for preventing .jkr.bin files from being picked up by *.bin pattern
484+ lock ( processedFilesLock )
485+ {
486+ foreach ( var outputFile in outputFiles )
487+ {
488+ processedOrOutputFiles . Add ( outputFile ) ;
489+ }
490+ }
491+
460492 // After all files in batch are processed, scan output directories for new files
461493 // This ensures all files are fully written before being added to the queue
462494 foreach ( var outputDir in outputDirectories )
463495 {
464- int newFileCount = AddNewFilesWithDedup ( outputDir , filesToProcess , processedFiles , processedFilesLock ) ;
496+ int newFileCount = AddNewFilesWithDedup ( outputDir , filesToProcess , processedOrOutputFiles , processedFilesLock ) ;
465497 stats . AddGeneratedFiles ( newFileCount ) ;
466498 }
467499 }
0 commit comments