A BufferedStream osztály használható arra, hogy segítségével más, a Stream osztályból származó osztályú adatfolyamba írjunk, illetve abból adatokat olvassunk ki. Bináris adatok írására, illetve olvasására használható, más adattípusokkal való munkához a BinaryReader, és a BinaryWriter osztályok valók.
Mint azt neve is sugallja, munkája szorosan kapcsolódik a számítógép puffereihez. Jól tudjuk, hogy a pufferek bájtok blokkjaiból álló területek a memóriában abból a célból, hogy az adatokat az input/output folyamatokban átmenetileg tárolják, gyorsítva ezzel az átviteli folyamatot, valamint csökkentve a számát az operációs rendszer felé irányuló hívásoknak. A pufferek alkalmasak olvasásra és írásra egyaránt, azonban a két művelet soha nem történhet egyidejűleg.
Minden átviteli folyamat, legyen az például egy fájl input/output művelet, használ puffereket. Egy BufferedStream osztállyal beburkolva az adott átvitelhez kapcsolódó adatfolyamot elérhető, hogy az adott átvitel tökéletesebben kihasználja a puffer nyújtotta előnyöket.
A pufferek ugyanis bizonyos adatátvitelekben nem használatosak, ilyenkor ezekre nincs is szükség. A BufferedStream osztály beépített mechanizmusának köszönhetően megóvja az átviteli folyamatot attól, hogy a nem használt puffer lelassítsa az átviteli folyamatot. Amikor ugyanis a programozó rendszerint a belső puffer méterénél nagyobb méretű adatmennyiséget ír, illetve olvas, akkor a BufferedStream osztály metódusait használva az osztály nem foglalja le a belső puffert. Ez nem azt jelenti, hogy az adatok átmeneti tárolás nélkül kerülnek átvitelre, csak azt, hogy nem a belső pufferben tárolódnak. A BufferedStream osztállyal beburkolt adatfolyam ilyenkor egy, a folyamatok között megosztott (feltehetően nagyobb méretű) puffert használ az adatok átmeneti tárolására. A megvalósítás logikája szerint az osztály metódusai feltételezik, hogy a programozó majdnem mindig az írási, vagy olvasási műveletek sorozatát végzi egymás után, de csak ritkán fordul elő, hogy a két művelet egymást váltja.
Vizsgáljuk meg a BufferedStream osztály tulajdonságait property-jeinek és metódusainak referencia-szintű megadásával. A property-k:

CanRead
Osztály: BufferedStream
public override bool CanRead {get;}
Megadja, hogy az adott adatfolyam támogatja-e az olvasás műveletet. Értéke true amennyiben igen, false amennyiben az adatfolyam le van zárva vagy csak-írás joggal van megnyitva. Az olyan Stream osztályból származó osztályok esetén, melyek nem támogatják az olvasási műveletet a Read, vagy egyéb olvasáshoz kapcsolódó metódust meghívva NotSupportedException kivétel keletkezik.

CanSeek
Osztály: BufferedStream
public override bool CanSeek {get;}
Megadja, hogy az adott adatfolyam támogatja-e a keresési (pozícionálási) műveletet. Értéke true amennyiben igen, false amennyiben az adatfolyam le van zárva vagy az operációs rendszer valamilyen kezelője konstruálta. Az olyan Stream osztályból származó osztályok esetén, melyek nem támogatják a pozícionáló műveletet a Seek, vagy egyéb kereséshez kapcsolódó metódust meghívva NotSupportedException kivétel keletkezik.

CanWrite
Osztály: BufferedStream
public override bool CanWrite {get;}
Megadja, hogy az adott adatfolyam támogatja-e az írás műveletet. Értéke true amennyiben igen, false amennyiben az adatfolyam le van zárva vagy csak-olvasás joggal van megnyitva. Az olyan Stream osztályból származó osztályok esetén, melyek nem támogatják az írási műveletet a Write, vagy egyéb íráshoz kapcsolódó metódust meghívva NotSupportedException kivétel keletkezik.

Length
Osztály: BufferedStream
public override long Length {get;}
Megadja az adatfolyam hosszát bájtokban.

Position
Osztály: BufferedStream
public override long Position {get; set;}
Megadja az adott adatfolyamon belüli aktuális pozíciót.
Amikor lekérdezzük a property értékét, akkor a Seek metódus meghívásával lekérdezésre kerül az adatfolyamon belüli pozíció, majd ezt az értéket hozzáigazítja a puffer adott pozíciójához.
Amikor beállítjuk a property értékét, akkor a pufferbe előzőleg beírt adatokat bemásolja az adott adatfolyamba, majd ezután hívódik meg a Seek metódus. Bármilyen adatfolyam hosszán kívüli pozícionálás megengedett.
Vizsgáljuk meg a BufferedStream osztály konstruktorait:

BufferedStream
Osztály: BufferedStream
public BufferedStream(
Stream stream
);
Létrehoz egy példányt az osztályból úgy, hogy 4096 bájtnyi puffer-területet foglal le.
Paraméterek
Stream stream
Az adott adatfolyam, melyet beburkol.

BufferedStream
Osztály: BufferedStream
public BufferedStream(
Stream stream,
int bufferSize
);
Létrehoz egy példányt az osztályból úgy, hogy a második paraméterben megadott bájt méretű puffert foglalja le.
Paraméterek
Stream stream
Az adott adatfolyam.
int bufferSize
A lefoglalandó puffer mérete.
A legfontosabb metódusok a következők:

Close
Osztály: BufferedStream
public override void Close();
Bezárja az adott adatfolyamot, majd felszabadítja az összes, de különösképpen a rendszererőforrásokat, mint fájl-, vagy socket-kezelőket (handle).
Ez a metódus meghívja a Dispose metódust is, true értéket átadva annak paraméterként.
Zárás előtt valamennyi pufferbe írt adat kimásolódik az adatfolyamba, így nem szükséges meghívni a Flush metódust. Minden metódushívás, vagy művelet, mely a lezárt puffert érinti, kivétel keletkezését eredményezi, mely ObjectDisposedException típusú.

Flush
Osztály: BufferedStream
public override void Flush(
);
A Close metódus meghívja a lezárás előtt. Minden pufferben található adatot kiír az adatfolyamba, majd kiüríti a puffert (minden puffert, mely az adatfolyamhoz kapcsolódik). Mivel minden írás és olvasás után a BufferedStream objektum karbantartja a puffert, nincs szükség ennek a meghívására az író, illetve olvasó műveletek közti kapcsolgatáskor.

Read
Osztály: BufferedStream
public override int Read(
out byte[] array,
int offset,
int count
);
Az adott adatfolyamból kimásolja az adatokat a megadott bájt-tömbbe.
Paraméterek
out byte[] array
A bájt-tömb, melybe az adatok kerülnek.
int offset
A kezdő pozíció, ahonnan kezdve másolja az adatokat.
int count
A beolvasandó bájtok száma.
Visszatérési érték
Az összes bájt száma, mely kiolvasásra került az adatfolyamból.
Megjegyzés
A visszatérési érték akkor nulla, ha az adatfolyamnak vége, egyébként legalább egy bájtot kimásol visszatérés előtt.

ReadByte
Osztály: BufferedStream
public override int ReadByte();
Egy bájt adatot olvas az adott adatfolyamból, majd erre a bájtra int típust kényszerít.
Visszatérési érték
Az adott int típusú érték, vagy –1, ha az olvasás az adatfolyam végéről kezdődött.

Seek
Osztály: BufferedStream
public override long Seek(
long offset,
SeekOrigin origin
);
Az adatfolyamon belül a megadott helyre pozícionál.
Paraméterek
long offset
A második paraméterhez képesti eltolást adja.
SeekOrigin origin
Megadja, hogy a pozícionálás az adatfolyam mely részéről kezdődjön. Ez nevezhető egy referencia pontnak. Értékei a következők:
- Begin: az adott referenciapont az adatfolyam kezdete.
- End: az adott referenciapont az adatfolyam vége.
- Current: az adott referenciapont a jelenlegi pozíció.
Például: a Seek metódus az adatfolyam 2. bájtjára pozícionál a folyam elejétől kezdve.
FileStream fs = new FileStream(...);
Fs.Seek(2,SeekOrigin.Begin);
Visszatérési érték
Az új pozíció értéke az adatfolyamon belül.
Megjegyzés
Ha az első paraméter negatív, az új pozíció a második paraméterben megadott értéket megelőzi annyival, amennyi a megadott érték abszolút értékben.
Ha az első paraméter nulla, az új pozíció a második paraméterben megadott érték lesz.

SetLength
Osztály: BufferedStream
public override void SetLength(
long value
);
Megadható az adatfolyam hossza bájtokban.
Paraméterek
long value
Az adott hossz egész számmal megadva.
A pufferre meghívódik a Flush metódus, mielőtt érvényre jutna az új méretbeállítás. Amennyiben az új méret kisebb, mint az adatfolyam aktuális hossza, a folyam csonkul, nagyobb méret megadásakor a folyam mérete is növekszik.
A művelet végrehajtásához az adott adatfolyamnak, melyet a BufferedStream objektum beburkol, támogatnia kell mind az írási, mind az olvasási műveletet.

Write
Osztály: BufferedStream
public override void Write(
byte[] array,
int offset,
int count
);
Az adott bájt-tömbben lévő adatok harmadik paraméterben megadott mennyiségét az adatfolyamba írja a megadott pozíciótól kezdve.
Paraméterek
byte[] array
Az adatokat tartalmazó tömb.
int offset
A kezdő pozíció.
int count
A kimásolandó adatok mennyisége.

WriteByte
Osztály: BufferedStream
public override void WriteByte(
byte value
);
Az adatfolyam aktuális pozíciójába írja a paraméterben megadott bájt értéket.
Paraméterek
byte value
A kiírandó adat.
A mellékelt példában egy képállományhoz tartozó adatfolyamot, mely mind írás, mind olvasás esetén egy FileStream objektum, beburkolunk egy-egy BufferedStream osztályú objektummal. Két műveletet végzünk el: beolvassuk a képet és megjelenítjük, valamint beolvassuk és elmentjük egy tetszőleges néven az alkalmazás futtatható állományát tartalmazó mappájába.
A képállomány olvasásához a Form TabControl-jának ’Beolvasás’ fülén található ’Beolvasás és megjelenítés’ feliratú gombjára kell kattintani, melynek eredményeképpen a kép megjelenik a Form-ra helyezett PictureBox kontrolban.
Ehhez létrehozunk egy FileStream objektumot a képállományhoz, valamint létrehozunk egy bájt tömböt, melybe az adatokat beolvassuk:
FileStream fs = new FileStream(Application.StartupPath + "\\img.bmp", FileMode.Open, FileAccess.Read);
byte[] imageData = new Byte[fs.Length];
A BufferedStream osztályt példányosítjuk, megadva a lefoglalandó puffer méretét 8000 bájtnak:
bStreamRead = new BufferedStream(fs,8000);
Beolvassuk az adatokat az adatfolyamból:
bStreamRead.Read(imageData,0, (int)fs.Length);
A megjelenítéshez egy Bitmap objektumot használunk, konstruktorában megadva, hogy mely adatfolyam alapján jöjjön létre. A művelet végén lezárjuk az adott adatfolyamot:
Bitmap bmp = new Bitmap(bStreamRead);
pBox.Image = bmp;
fs.Close();
A TabControl ’Beolvasás és mentés’ fülére kattintva megadható egy állománynév a kiterjesztés és elérési út nélkül, melybe az említett képállomány átmásolható a BufferedStream osztály segítségével.
A művelethez két FileStream objektumot használunk: az egyiket a fájlból való beolvasáshoz, a másikat a fájlba való íráshoz. Mindkettőt beburkoljuk egy-egy BufferedStream objektummal, 8000 bájtban határozva meg méretét a lefoglalandó puffernek, majd az első adatfolyamból kiolvassuk az adatokat egy imageData tömbbe, míg a másikkal kiírjuk az adatokat ebből a tömbből az adott adatfolyamba:
...
bStreamRead = new BufferedStream(fsSource,8000);
bStreamRead.Read(imageData,0,(int)fsSource.Length);
bStreamWrite = new BufferedStream(fsDesc,8000);
bStreamWrite.Write(imageData,0,(int)fsSource.Length);
A kiírandó adatfolyamhoz létrehozunk egy Bitmap objektumot, melynek Save metódusával elmentjük az állományt. Az ImageFormat osztállyal megadjuk, hogy .bmp formátumban történjen a mentés:
Bitmap bmp = new Bitmap(bStreamRead);
bmp.Save(bStreamWrite,ImageFormat.Bmp);
Végül lezárjuk az adatfolyamokat:
fsSource.Close();
fsDesc.Close();