DarthVader
DarthVader

Reputation: 55032

Writing and reading streams with offset to reduce disc seeks

I am reading a file and writing stream of that to a file, what I want to do is writing multiple files in a single file and reading them by their offset.

While writing the files, I understand that i need to know the file offset and length of the stream to read back the file.

var file = @"d:\foo.pdf";

var stream = File.ReadAllBytes(file);
// here i have the length of the 
Console.WriteLine(stream.LongLength);

using (var br = new BinaryWriter(File.Open(@"d:\foo.bin", FileMode.OpenOrCreate)))
{
     br.Write(stream);
}

I need to find the offset while writing multiple files.

Also while reading back the files, how do I start from an offset and read forwards as long as the length?

Finally, Does this method reduces number of disc seeks?

Upvotes: 1

Views: 383

Answers (1)

Marc Gravell
Marc Gravell

Reputation: 1062975

To read back various fragments, you will need to store the individual file lengths. For example:

using(var dest = File.Open(@"d:\foo.bin", FileMode.OpenOrCreate))
{
    Append(dest, file);
    Append(dest, anotherFile);
}
...
static void AppendFile(Stream dest, string path)
{
    using(var source = File.OpenRead(path))
    {
        var lenHeader = BitConverter.GetBytes(source.Length);
        dest.Write(lenHeader, 0, 4);
        source.CopyTo(dest);
    }
}

Then to read back you can do things like:

using(var source = File.OpenRead(...))
{
    int len = ReadLength(source);
    stream.Seek(len, SeekOrigin.Current); // skip the first file
    len = ReadLength(source);
    // TODO: now read len-many bytes from the second file        
}
static int ReadLength(Stream stream)
{
    byte[] buffer = new byte[4];
    int count = 4, offset = 0, read;
    while(count != 0 && (read = stream.Read(buffer, offset, count)) > 0)
    {
        count -= read;
        offset += read;
    }
    if (count != 0) throw new EndOfStreamException();
    return BitConverter.ToInt32(buffer, 0);
}

As for reading len-many bytes; you can either just keep track of it and decrement it while reading, or you can create a length-limited Stream wrapper. Either works.

Upvotes: 1

Related Questions