Чтение файла по одному байту за раз в обратном порядке

Привет, я пытаюсь прочитать файл по одному байту за раз в обратном порядке. До сих пор мне удалось только прочитать файл с начала и до конца и записать его в другой файл.

Мне нужно иметь возможность прочитать файл с конца до начала и распечатать его в другой файл.

Это то, что я до сих пор:

        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);
                }
            }
        }

Я знаю, что мне нужно использовать метод Seek в fileStream, и это приводит меня к концу файла. Я уже делал это в прокомментированном виде кода, но сейчас я не знаю, как читать файл петля.

Как я могу достичь этого?

4 ответа

Решение
    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);
    }

Вы можете сделать это, читая по одному байту за раз, или вы можете прочитать больший буфер, записать его в выходной файл в обратном порядке и продолжать так до тех пор, пока не достигнете начала файла. Например:

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);
    }
}

Очевидная оптимизация - обратный буфер после того, как вы его прочитали, а затем записали его одним целым фрагментом в выходной файл.

И если вы знаете, что файл поместится в память, это действительно просто:

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);

Если файл небольшой (умещается в вашей оперативной памяти), то это сработает:

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

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

Применение:

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

}

Если файл большой (больше, чем ваша оперативная память), то это будет работать:

      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();
    }
}

Он использует ReverseStreamкласс, который можно найти здесь.

Другие вопросы по тегам