Skip to main content
Tweeted twitter.com/#!/StackProgrammer/status/646484013683769344
more info.
Source Link
aybe
  • 955
  • 9
  • 19

Summary

I am developing a WAV file format reader under WinRT, and for this I need to read random amounts of structs consisting of fundamental types such as int, uint, float and so on.

Back in desktop development one would rely on BinaryReader, now in WinRT it has been replaced by DataReader which works asynchronously.

Problem

I cannot grasp how to use this new class since now, an intermediate buffer must be filled using LoadAsync(), prior calling reading methods such as ReadInt32().

In contrast, with the old BinaryReader there was no notion of having to fill an intermediate buffer prior reading primitives from the source.

Every example I have seen on the web are 'naive' in the sense that they entirely read the source stream in memory, but in my case a WAV file is in the range of hundred megabytes and possibly gigabytes.

I have sketched the following helper methods which pre-fills the intermediate buffer with only what's needed and basically frees me from systematically calling LoadAsync every time before reading something from the stream:

internal static class DataReaderExtensions
{
    public static async Task<string> ReadStringAsync(this DataReader reader, uint length)
    {
        await LoadAsync(reader, length);
        return reader.ReadString(length);
    }

    private static async Task LoadAsync(DataReader reader, uint length)
    {
        var u = await reader.LoadAsync(length);
        if (u < length) throw new InvalidOperationException();
    }
}

But I'm not entirely sure whether it is the way to go when using DataReader.

Question

How is one supposed to pre-fill the intermediate buffer in my case ?

  • should one load only the needed amount as shown above ?
  • or should one load a constant size (e.g. 65536 bytes), keep track of reading position then possibly pre-fetch more on larger requests ? (basically wrapping a DataReader in a helper class)

EDIT

By looking at BinaryReader source code there doesn't seem to be any kind of magic behind the scene, i.e. bytes are fetched on demand. So for my case, even if it sounds a bit silly to read primitives asynchronously, I guess it's the simplest and safest way to do it; in contrast to wrapping a DataReader, tracking read position, handling an intermediate buffer and finally, the inability to derive from it as public WinRT types must be sealed ... not sure it is worth it for the outcome.

Unfortunately WINMD assemblies sources are unavailable, it would have been pretty interesting to see how they do it at Microsoft as these newer types can be used as older types, with these extension methods.

Summary

I am developing a WAV file format reader under WinRT, and for this I need to read random amounts of structs consisting of fundamental types such as int, uint, float and so on.

Back in desktop development one would rely on BinaryReader, now in WinRT it has been replaced by DataReader which works asynchronously.

Problem

I cannot grasp how to use this new class since now, an intermediate buffer must be filled using LoadAsync(), prior calling reading methods such as ReadInt32().

In contrast, with the old BinaryReader there was no notion of having to fill an intermediate buffer prior reading primitives from the source.

Every example I have seen on the web are 'naive' in the sense that they entirely read the source stream in memory, but in my case a WAV file is in the range of hundred megabytes and possibly gigabytes.

I have sketched the following helper methods which pre-fills the intermediate buffer with only what's needed and basically frees me from systematically calling LoadAsync every time before reading something from the stream:

internal static class DataReaderExtensions
{
    public static async Task<string> ReadStringAsync(this DataReader reader, uint length)
    {
        await LoadAsync(reader, length);
        return reader.ReadString(length);
    }

    private static async Task LoadAsync(DataReader reader, uint length)
    {
        var u = await reader.LoadAsync(length);
        if (u < length) throw new InvalidOperationException();
    }
}

But I'm not entirely sure whether it is the way to go when using DataReader.

Question

How is one supposed to pre-fill the intermediate buffer in my case ?

  • should one load only the needed amount as shown above ?
  • or should one load a constant size (e.g. 65536 bytes), keep track of reading position then possibly pre-fetch more on larger requests ? (basically wrapping a DataReader in a helper class)

Summary

I am developing a WAV file format reader under WinRT, and for this I need to read random amounts of structs consisting of fundamental types such as int, uint, float and so on.

Back in desktop development one would rely on BinaryReader, now in WinRT it has been replaced by DataReader which works asynchronously.

Problem

I cannot grasp how to use this new class since now, an intermediate buffer must be filled using LoadAsync(), prior calling reading methods such as ReadInt32().

In contrast, with the old BinaryReader there was no notion of having to fill an intermediate buffer prior reading primitives from the source.

Every example I have seen on the web are 'naive' in the sense that they entirely read the source stream in memory, but in my case a WAV file is in the range of hundred megabytes and possibly gigabytes.

I have sketched the following helper methods which pre-fills the intermediate buffer with only what's needed and basically frees me from systematically calling LoadAsync every time before reading something from the stream:

internal static class DataReaderExtensions
{
    public static async Task<string> ReadStringAsync(this DataReader reader, uint length)
    {
        await LoadAsync(reader, length);
        return reader.ReadString(length);
    }

    private static async Task LoadAsync(DataReader reader, uint length)
    {
        var u = await reader.LoadAsync(length);
        if (u < length) throw new InvalidOperationException();
    }
}

But I'm not entirely sure whether it is the way to go when using DataReader.

Question

How is one supposed to pre-fill the intermediate buffer in my case ?

  • should one load only the needed amount as shown above ?
  • or should one load a constant size (e.g. 65536 bytes), keep track of reading position then possibly pre-fetch more on larger requests ? (basically wrapping a DataReader in a helper class)

EDIT

By looking at BinaryReader source code there doesn't seem to be any kind of magic behind the scene, i.e. bytes are fetched on demand. So for my case, even if it sounds a bit silly to read primitives asynchronously, I guess it's the simplest and safest way to do it; in contrast to wrapping a DataReader, tracking read position, handling an intermediate buffer and finally, the inability to derive from it as public WinRT types must be sealed ... not sure it is worth it for the outcome.

Unfortunately WINMD assemblies sources are unavailable, it would have been pretty interesting to see how they do it at Microsoft as these newer types can be used as older types, with these extension methods.

Post Reopened by aybe, CommunityBot, Dan Pichelman, durron597, Bart van Ingen Schenau
question reformulated
Source Link
aybe
  • 955
  • 9
  • 19

Which pattern How is one supposed to adopt fordeal with the new asyncintermediate buffer of DataReader in comparison to the old BinaryReaderclass?

Problem summarySummary

BeforeI am developing a WAV file format reader under WinRT, one would rely to BinaryReader when it is necessaryand for this I need to read random amounts of structs consisting of fundamental types such as int32int, uint32uint, float from an input stream. The process was really straightforward as one only has to call ReadInt32() for instanceand so on.

TheBack in desktop development one would rely on BinaryReader, now in WinRT replacement isit has been replaced by DataReader which differs by the fact that it is works asynchronously.

asynchronousProblem.

So when one needsI cannot grasp how to read 'values' from the inputuse this new class since now, it has to do all these steps:an intermediate buffer must be filled using LoadAsync(), prior calling reading methods such as ReadInt32().

  1. feed an intermediate buffer through LoadAsync()
  2. as a safe measure, check that returned count is enough for the next operation
  3. call one of the methods to get an int, float etc ...

It is extremely annoying inIn contrast, with the sense it'sold BinaryReader there was no longer easy to read random amountsnotion of different types (such as structs) from an input stream; without having to litter these extra steps between every parts of my codefill an intermediate buffer prior reading primitives from the source.

And to add to the problem,Every example I do not knowhave seen on the exact amount of bytes to provisionweb are 'naive' in the intermediate buffer unless I'vesense that they entirely read some of the structssource stream in memory, but in my case a WAV file is in the range of hundred megabytes and possibly gigabytes.

My attempt to address the problem

I've decided to sketch I have sketched the following helpers to keep my code freehelper methods which pre-fills the intermediate buffer with only what's needed and basically frees me from all this boilerplate codesystematically calling LoadAsync every time before reading something from the stream:

internal static class DataReaderExtensions
{
    public static async Task<byte[]> ReadBytesAsync(this DataReader reader, uint length)
    {
        await LoadAsync(reader, length);
        var bytes = new byte[length];
        reader.ReadBytes(bytes);
        return bytes;
    }

    public static async Task<ushort> ReadUInt16Async(this DataReader reader)
    {
        await LoadAsync(reader, sizeof (ushort));
        return reader.ReadUInt16();
    }

    public static async Task<uint> ReadUInt32Async(this DataReader reader)
    {
        await LoadAsync(reader, sizeof (uint));
        return reader.ReadUInt32();
    }

    public static async Task<string> ReadStringAsync(this DataReader reader, uint length)
    {
        await LoadAsync(reader, length);
        return reader.ReadString(length);
    }

    private static async Task LoadAsync(DataReader reader, uint length)
    {
        var u = await reader.LoadAsync(length);
        if (u < length) throw new InvalidOperationException();
    }
}

Basically these extension methods do fill the intermediate buffer, ensure enough has been read and do the actual reading. WhileBut I'm not entirely sure whether it works well, some absurd things are surfacing such as an async uint32 readis the way to go when using ..DataReader.

Is there some more appropriated patternHow is one supposed to that problem thanpre-fill the intermediate buffer in my current attemptcase ?

  • should one load only the needed amount as shown above ?
  • or should one load a constant size (e.g. 65536 bytes), keep track of reading position then possibly pre-fetch more on larger requests ? (basically wrapping a DataReader in a helper class)

Which pattern to adopt for the new async DataReader in comparison to the old BinaryReader?

Problem summary

Before WinRT, one would rely to BinaryReader when it is necessary to read fundamental types such as int32, uint32, float from an input stream. The process was really straightforward as one only has to call ReadInt32() for instance.

The WinRT replacement is DataReader which differs by the fact that it is asynchronous.

So when one needs to read 'values' from the input, it has to do all these steps:

  1. feed an intermediate buffer through LoadAsync()
  2. as a safe measure, check that returned count is enough for the next operation
  3. call one of the methods to get an int, float etc ...

It is extremely annoying in the sense it's no longer easy to read random amounts of different types (such as structs) from an input stream; without having to litter these extra steps between every parts of my code.

And to add to the problem, I do not know the exact amount of bytes to provision in the intermediate buffer unless I've read some of the structs.

My attempt to address the problem

I've decided to sketch the following helpers to keep my code free from all this boilerplate code:

internal static class DataReaderExtensions
{
    public static async Task<byte[]> ReadBytesAsync(this DataReader reader, uint length)
    {
        await LoadAsync(reader, length);
        var bytes = new byte[length];
        reader.ReadBytes(bytes);
        return bytes;
    }

    public static async Task<ushort> ReadUInt16Async(this DataReader reader)
    {
        await LoadAsync(reader, sizeof (ushort));
        return reader.ReadUInt16();
    }

    public static async Task<uint> ReadUInt32Async(this DataReader reader)
    {
        await LoadAsync(reader, sizeof (uint));
        return reader.ReadUInt32();
    }

    public static async Task<string> ReadStringAsync(this DataReader reader, uint length)
    {
        await LoadAsync(reader, length);
        return reader.ReadString(length);
    }

    private static async Task LoadAsync(DataReader reader, uint length)
    {
        var u = await reader.LoadAsync(length);
        if (u < length) throw new InvalidOperationException();
    }
}

Basically these extension methods do fill the intermediate buffer, ensure enough has been read and do the actual reading. While it works well, some absurd things are surfacing such as an async uint32 read ...

Is there some more appropriated pattern to that problem than my current attempt ?

How is one supposed to deal with the intermediate buffer of DataReader class?

Summary

I am developing a WAV file format reader under WinRT, and for this I need to read random amounts of structs consisting of fundamental types such as int, uint, float and so on.

Back in desktop development one would rely on BinaryReader, now in WinRT it has been replaced by DataReader which works asynchronously.

Problem

I cannot grasp how to use this new class since now, an intermediate buffer must be filled using LoadAsync(), prior calling reading methods such as ReadInt32().

In contrast, with the old BinaryReader there was no notion of having to fill an intermediate buffer prior reading primitives from the source.

Every example I have seen on the web are 'naive' in the sense that they entirely read the source stream in memory, but in my case a WAV file is in the range of hundred megabytes and possibly gigabytes.

I have sketched the following helper methods which pre-fills the intermediate buffer with only what's needed and basically frees me from systematically calling LoadAsync every time before reading something from the stream:

internal static class DataReaderExtensions
{
    public static async Task<string> ReadStringAsync(this DataReader reader, uint length)
    {
        await LoadAsync(reader, length);
        return reader.ReadString(length);
    }

    private static async Task LoadAsync(DataReader reader, uint length)
    {
        var u = await reader.LoadAsync(length);
        if (u < length) throw new InvalidOperationException();
    }
}

But I'm not entirely sure whether it is the way to go when using DataReader.

How is one supposed to pre-fill the intermediate buffer in my case ?

  • should one load only the needed amount as shown above ?
  • or should one load a constant size (e.g. 65536 bytes), keep track of reading position then possibly pre-fetch more on larger requests ? (basically wrapping a DataReader in a helper class)
Post Closed as "Needs details or clarity" by Robert Harvey, CommunityBot, durron597, ChrisF
edited tags
Link
aybe
  • 955
  • 9
  • 19
Source Link
aybe
  • 955
  • 9
  • 19
Loading