It's important to understand TDD as less about the end result - tested code, and more about the journey in getting there. TDD is a design process that encourages all the code qualities I'm sure you have learned about: reusability, separation of concerns, readability, maintainability, etc. Oh, and of course, correctness. Your tests drive you towards writing isolatable, testable code, which in turn drives these qualities. If you only understand TDD as about testing, you are in for a hard time.
Maybe you have already written this program (or maybe you have at least designed it in your head), and you are thinking about how to wrap tests around it. If this is true then start again as you are not driving the code from the tests: you're not doing TDD.
Writing your tests first, then making each pass, might lead you towards the following units:
- A thing that opens a file and exposes a byte stream
- A thing that parses a byte stream as a PDF
- A thing that takes the representation of a PDF and extracts what you're interested in
- A thing that groups by something extracted previously
- A thing that allocates a file location based on group
- A thing that moves a file to a location
(I may not have understood your program correctly, but you get the gist.)
Hopefully you can see that you've broken it down into easily testable units, many of which can be reused, most of which are agnostic of files, or PDFs. Those units that actually deal with real file operations are very simple and are few and far between, so testing them is not difficult; everything else deals with some in-memory representation.
It's not easy to get right at first, but the golden rule is to remember that if your tests becomes complicated, it's probably a clue that your code has become too complicated and is trying to do too much in one unit. It's your cue to take a step back and keep asking questions like these.