You could have ABC::Reader and ABC::Writer classes. ABC's constructor -- new() -- would accept ABC::Reader as input.
ABC's export() or write() method would take ABC::Writer as its argument. This way ABC's core functions would always deal with the same interface. You can provide basic functionality in ABC::Reader and ABC::Writer to read/write from/to scalars and files. The end user will always be able to expand the functionality by extending ABC::Reader and ABC::Writer classes.
My 2c.