4

Hi I am trying to read a file one byte at a time in reverse order.So far I only managed to read the file from begining to end and write it on another file.

I need to be able to read the file from the end to the begining and print it to another file.

This is what I have so far:

        string fileName = Console.ReadLine();
        using (FileStream file = new FileStream(fileName ,FileMode.Open , FileAccess.Read))
        {

            //file.Seek(endOfFile, SeekOrigin.End);

            int bytes;
            using (FileStream newFile = new FileStream("newsFile.txt" , FileMode.Create , FileAccess.Write))
            {
                while ((bytes = file.ReadByte()) >= 0)
                {
                    Console.WriteLine(bytes.ToString());
                    newFile.WriteByte((byte)bytes);
                }
            }
        }

I know that I have to use the Seek method on the fileStream and that gets me to the end of the file.I already did that at the commented protion of the code , but I do not know how to read the file now in the while loop.

How can I achive this?

aleczandru
  • 5,319
  • 15
  • 62
  • 112
  • 2
    Have another look at [Seek](http://msdn.microsoft.com/en-us/library/system.io.filestream.seek.aspx). You can specify seeking -1 from the current position to move backwards theough the file one byte at a time. After seeking the end of file, you would seek backwards one byte in your loop until you reach the beginning. – HABO Apr 10 '13 at 16:49

4 Answers4

1
    string fileName = Console.ReadLine();
    using (FileStream file = new FileStream(fileName, FileMode.Open, FileAccess.Read))
    {
        byte[] output = new byte[file.Length]; // reversed file 

        // read the file backwards using SeekOrigin.Current
        //
        long offset;
        file.Seek(0, SeekOrigin.End);        
        for (offset = 0; offset < fs.Length; offset++)
        {
           file.Seek(-1, SeekOrigin.Current);
           output[offset] = (byte)file.ReadByte();
           file.Seek(-1, SeekOrigin.Current);
        }

        // write entire reversed file array to new file
        //
        File.WriteAllBytes("newsFile.txt", output);
    }
d.moncada
  • 16,900
  • 5
  • 53
  • 82
  • Why not just `file.Seek(-1, SeekOrigin.End);` then in the loop `file.Seek(-1, SeekOrigin.Current);`? Probably a lot less seeking under the hood. – user7116 Apr 10 '13 at 16:59
1

You could do it by reading one byte at a time, or you could read a larger buffer, write it to the output file in reverse, and continue like that until you've reached the beginning of the file. For example:

string inputFilename = "inputFile.txt";
string outputFilename = "outputFile.txt";
using (ofile = File.OpenWrite(outputFilename))
{
    using (ifile = File.OpenRead(inputFilename))
    {
        int bufferSize = 4096;
        byte[] buffer = new byte[bufferSize];
        long filePos = ifile.Length;
        do
        {
            long newPos = Math.Max(0, filePos - bufferSize);
            int bytesToRead = (int)(filePos - newPos);
            ifile.Seek(newPos, SeekOrigin.Set);
            int bytesRead = ifile.Read(buffer, 0, bytesToRead);
            // write the buffer to the output file, in reverse
            for (int i = bytesRead-1; i >= 0; --i)
            {
                ofile.WriteByte(buffer[i]);
            }
            filePos = newPos;
        } while (filePos > 0);
    }
}

An obvious optimization would be to reverse the buffer after you've read it, and then write it in one whole chunk to the output file.

And if you know that the file will fit into memory, it's really easy:

var buffer = File.ReadAllBytes(inputFilename);
// now, reverse the buffer
int i = 0;
int j = buffer.Length-1;
while (i < j)
{
    byte b = buffer[i];
    buffer[i] = buffer[j];
    buffer[j] = b;
    ++i;
    --j;
}
// and write it
File.WriteAllBytes(outputFilename, buffer);
Jim Mischel
  • 131,090
  • 20
  • 188
  • 351
  • 1
    Should the values of `i` and/or `j` change in the loop? Seems like the runtime might be excessive if you just keep swapping the same two bytes. – HABO Apr 10 '13 at 19:43
  • @HABO: Yeah, that might take a while. Thanks for the correction. – Jim Mischel Apr 10 '13 at 19:55
0

If the file is small (fits in your RAM) then this would work:

public static IEnumerable<byte> Reverse(string inputFilename)
{
    var bytes = File.ReadAllBytes(inputFilename);
    Array.Reverse(bytes);

    foreach (var b in bytes)
    {
        yield return b;
    }
}

Usage:

foreach (var b in Reverse("smallfile.dat"))
{

}
Fidel
  • 7,027
  • 11
  • 57
  • 81
0

If the file is large (bigger than your RAM) then this would work:

using (var inputFile = File.OpenRead("bigfile.dat"))
using (var inputFileReversed = new ReverseStream(inputFile))
using (var binaryReader = new BinaryReader(inputFileReversed))
{
    while (binaryReader.BaseStream.Position != binaryReader.BaseStream.Length)
    {
        var b = binaryReader.ReadByte();
    }
}

It uses the ReverseStream class which can be found here.

Fidel
  • 7,027
  • 11
  • 57
  • 81