1 of 2

Smalltalk

There is a library yet ported to several Smalltalk dialects (Visualworks, Gemstone Squeak/Pharo, ...) named Xtreams that makes this task more than easy.

FileStream would be as simple as 'foo' asFilename reading and 'bar' asFilename writing for example in Visualworks, but are dialect specific.
For this reason I demonstrate the algorithm with dialect neutral internal Streams instead.
A good idea could be to process each byte code in increasing order:

| input |
input := 'Hello world' asByteArray reading.
^((ByteArray new writing)
    write: ((0 to: 255) inject: ByteArray new reading into: [:outputSoFar :code |
        | nextOutput |
        nextOutput := ByteArray new writing.
        ((input += 0; selecting: [:c | c <= code]) ending: code inclusive: true) slicing do: [:subStream |
            | positionable |
            positionable := subStream positioning.
            nextOutput write: (outputSoFar limiting: (positionable ending: code) rest size).
            nextOutput write: (positionable += 0; selecting: [:c | c = code])].
        nextOutput conclusion reading]);
    conclusion) asString

Of course, it is also possible to process in random order, but i'm afraid that it makes the code a bit too compact:

| input output |
input := 'Hello world' asByteArray reading.
output := ByteArray new writing.
(0 to: 255) asArray shuffled do: [:code |
        output += 0.
        (input += 0; ending: code inclusive: true) slicing do: [:subStream |
            | positionable |
            positionable := subStream positioning.
            output ++ (positionable += 0; rejecting: [:c | c = code]) rest size.
            output write: (positionable += 0; selecting: [:c | c = code])]].
^output conclusion asString