Copying part of a file to istream buffer

Started by
3 comments, last by snk_kid 19 years, 5 months ago
Basically, I have an ifstream object representing an open file. I want to copy a part of the data from this stream to a buffer in local memory, and then access the buffer through an istream object. I've tried with different combinations of streambuf's and stringstreams, but I just can't get it to work properly. Surely there must be a way to accomplish this in a non-ugly manner? /John
/John
Advertisement
If you could elaborate some more maybe with some code, for instance when you say copy part of a file exactly how much or what value indicates when to stop reading in? what is it your hoping to achieve (like parsing a string in memory to some particular type then stringstreams etc)? and what exactly was it you tried that didn't work? then we can give you better advice and/or maybe a better alternative.

[Edited by - snk_kid on November 8, 2004 3:53:37 PM]
Thank you for the help! I really appreciate it.

So, what I'm trying to do is parse a MIDI file. The file is made up of chunks, each representing a MIDI track. Each track chunk consists of a header, followed by a number of midi events. The header contains the byte length of the chunk.

Now, what I want to do is to read only the chunk that I'm currently working with into a separate buffer, that I want to access through another istream object.
The reason for this is, so I don't read past the end of the track chunk, since it is hard to keep track of how many bytes different functions extract from the stream. With a limited stream, there is an exception thrown if i read past the end of the chunk.

Something like this (though this code doesn't work, of course):
ifstream midiFileStream("test.mid");//Once for every track do thisfor (....){ //Number of bytes in the track chunk DWORD chunkLength = midiFileStream.get(); //Create a temp buffer and read data from midiFile into it istream tempBufferStream; midiFileStream.read(tempBufferStream, chunkLength) //Perform actions with tempBufferStream, instead of midiFileStream ReadFromStreamFunction(tempBufferStream);}


I tried to create a streambuf object from a char array, which I filled with the chunk data, and then use that streambuf to create an istream object, but it only gives me -1 instead of the correct byte values when I call get().

Hope this explanation made things easier to understand...
It's a bit hard to explain in a simple way...
/John
Try using an istringstream object:

static char tempBuffer[1024]; // Make sure this is big enough to hold the largest chunk size; if you're unsure, make this dynamic instead of staticmidiFileStream.read(tempBuffer, 1024); istringstream tempBufferStream(tempBuffer); ReadFromStreamFunction(tempBufferStream); // tempBufferStream is derived from istream, so this is kosher
Quote:Original post by FunkyTune
Thank you for the help! I really appreciate it.

So, what I'm trying to do is parse a MIDI file. The file is made up of chunks, each representing a MIDI track. Each track chunk consists of a header, followed by a number of midi events. The header contains the byte length of the chunk.

Now, what I want to do is to read only the chunk that I'm currently working with into a separate buffer, that I want to access through another istream object.
The reason for this is, so I don't read past the end of the track chunk, since it is hard to keep track of how many bytes different functions extract from the stream. With a limited stream, there is an exception thrown if i read past the end of the chunk.


i don't think its nessercary to open another stream for this, this whole idea about "chunks" is way to represent data that has a hierarchical structure (think of trees) in a binary file, much like xml is used to represent data that has a hierarchical structure in a text file. i looked up the midi file format and there is only 2 offical levels the header and the tracks and would like something like this:

 MThd //<--------------------------------------------  |                   ^              ^  |                   | sub-chunk    |  |                   | level 1      |  |                   |              |  +---+--- (MTrk chunk) track 1 //<--|      |  ^                           |      |  | sub-chunk level 2         |      +--- track 2                   |      |                              |      |                              |Main chunk, the whole file      +--- track 3                   |level 0      |                              |      |                              |      +--- track N - 1               |      |                              |      |                              |      +--- track N //<----------------------------------


As you can see from the rubbbish ascii art a the whole file can be considered a chunk and each sub-chunk is also a chunk, the way you would normally handle reading this is to recursively go into each level read a new chunk (but not data just 8 bytes chunk) in then have a switch statemenet check the chunk type and do the appropriate action such as if a paritcular sub-chunk has sub-chunks with-in it then recusively call the function again, its like your "traversing a tree" and the chunks are your tree nodes.

You can easily find & keep track how much you've read in aswell, you can find out the size of the file with the I/O streams lib e.g.

// get length of file:in.seekg (0, ios::end);length = is.tellg();in.seekg (0, ios::beg);


and to find out how much you've currently read in std::istream::gcount will say how many bytes you've read after the last unformatted operation.

With this in mind you need a generic midi chunk structure that has the chunk id & the length the chunk plus how many bytes have currently been read to keep track of where you are:

typedef unsigned long dword;struct midi_chunk {   char ID[4];             dword length;     //<------ this member is stored in the file in big-endian byte-order   std::streamsize bytes_read; //<--- this member is a derived value not from the file};


i think you should read this this there are some useful structures & functions and info on midi file format, i read that the midi file format stores its data in binary and most data is in big endian format so you must convert the order for your platform (PCs generally being little-endian), note also from what you've shown me you haven't opened your stream in binary mode.

EDIT: You can use these to convert big-endian to little endian:

typedef unsigned long dword;typedef unsigned short word;inline dword byte_swap(dword n) {   return (((n & 0x000000FF) << 24) + ((n & 0x0000FF00) << 8) +           ((n & 0x00FF0000) >> 8) + ((n & 0xFF000000) >> 24));}inline word byte_swap(word n) {   return (((n >> 8)) | (n << 8));}


[Edited by - snk_kid on November 8, 2004 7:06:31 PM]

This topic is closed to new replies.

Advertisement