C# - Állományok tárolása MS SQL Server binary típusú oszlopában

forráskód letöltése
A cikkben annak a lehetőségnek járunk utána, hogy milyen módon lehet tetszőleges állományokat eltárolni az SQL adatbázis tábláinak binary típusú oszlopában, illetve hogyan lehet az eltárolt állományokat kiolvasni és akár más néven elmenteni.
A példához szükséges a BinaryStoring adatbázis, melyet a mellékelt BinaryStoring.sql lefuttatásával hozhatunk létre. A BinaryStoring.sql script 5. sorában a létrehozandó adatbázisfájlok meghajtó-betűjelét ki kell cserélni a megfelelő betűre.
Az állomány tárolása a táblában
A kód ismertetése előtt meg kell említeni, hogy az MS SQL Server a binary típusú oszlopokban csak maximálisan 8 kB méretű állományok tárolását teszi lehetővé.
A programban a felhasználó tetszőleges helyen található, tetszőleges típusú állományt elmenthet az adatbázisban. Ennek kiválasztásában egy szabványos OpenFileDialog ablak lesz a segítségére. A program megvizsgálja, hogy a mentendő állomány megfelel-e a 8 kB-os mérethatárnak.
A feltételeknek megfelelő állományt olvassuk be a BinaryStoring adatbázis Table1 táblájának egyik sorába. Ehhez a FileStream osztály segítségével az állományt beolvassuk egy bájtokat tartalmazó tömbbe.
private void storeButton_Click(object sender, System.EventArgs e)
{
  ...
  FileStream fs=new FileStream (textBox1.Text,  FileMode.Open, FileAccess.Read);
  byte[] binaryData = new Byte[fs.Length];
  fs.Read(binaryData, 0, (int)fs.Length);
  fs.Close();
...
Az állomány adattáblába történő beírását egy tárolt eljárás végzi el, mely már létrejött a BinaryStoring adatbázisunkban InsertBinary néven. A tábla felépítéséből adódóan a tárolt eljárásnak egy paramétert kell átadni. A tábla első oszlopa ugyanis IDENTITY típusú, így az adatbeszúráskor automatikusan betesz egy egyedi azonosítót az oszlopba. A tárolt eljárás egyetlen paraméterét manuálisan adjuk meg tervezési időben, így futás során már csak ennek kell értéket adni a következő módon.
insertCommand.Parameters["@binaryvalue"].Value=binaryData;
Végül már csak futtatjuk a tárolt eljárást, mely egy egyszerű insert into parancsot hajt végre.
insertCommand.ExecuteNonQuery();
Állomány kiolvasása a táblából és elmentése egy másik állományba
A programban mindig az utoljára elhelyezett állományt tudjuk kiolvasni és elmenteni egy másik állományba, akár másik néven. Ehhez futtatunk egy egyszerű SELECT lekérdezést, majd az eredmény olvasását egy SqlDataRead osztályra bízzuk.
private void toFileButton_Click(object sender, System.EventArgs e)
{
  ...
  SqlDataReader dr2 = selectCommand.ExecuteReader();
  Dr2.Read();
Az állomány eléréséhez szintén egy bájt tömbre lesz szükségünk első lépésben, csak hogy most nem tudjuk, hogy mekkora állományt tároltunk el és ehhez mekkora bájt tömböt kellene létrehoznunk. Ezért először az SqlDataRead osztály GetBytes függvényét úgy futtatjuk, hogy nem adunk meg buffert, melyre a bájtokat másolhatná, így eredményül visszakapjuk, hogy hány bájtra van szükség a tömbben az adott állomány tárolásához. Felhasználva ezt az értéket, most már létre tudjuk hozni a tömböt a megfelelő mérettel, majd egy ismételt GetBytes függvény hívással most már kiolvashatjuk a bájtokat, melyek az állományt alkotják.
long bytesize = dr2.GetBytes(1, 0, null, 0, 0);
byte[] binaryData = new byte[bytesize];
dr2.GetBytes(1, 0, binaryData, 0, (int)bytesize);
dr2.Close();
Most már csak a tárolt bájtokból kell állományt előállítanunk. Ehhez létre kell hoznunk egy FileStream objektumot a létrehozandó fájl nevével - mely a textBox kontrol Text property-je lesz -, valamint a megnyitás és a hozzáférés módjának megadásával.
FileStream fs = new FileStream(textBox2.Text,FileMode.Create,FileAccess.Write);
Majd a FileStream osztály Write függvényével kiírjuk a bájtokat a létrehozott állományba és lezárjuk az állományt.
fs.Write(binaryData, 0, (int)binaryData.Length);
fs.Close();
A példa alkalmazásban amennyiben nem adunk meg fájlkiterjesztést a mentendő fájlnévhez, a program .txt kiterjesztést ad hozzá.