简体   繁体   中英

How to access files stored in SQL Server's FileTable?

As I know SQL Server since version 2012 has a new feature, FileTable . It allows us to store files in the file system and to use them from T-SQL.

I am trying to use this feature and I have no idea how to do it properly.

Generally, I don't know how to access files stored in the file table. Let's suppose I have asp.net MVC app and there are a lot of images which I show on web pages in img tags. I would like to store these images in Filetable and access them as files from the filesystem. But I don't know where these files are stored and how to use them as files. Now my images are stored in web application directory in folder images and I write something like this:

<img src='/images/mypicture.png' />

And if I move my images to file table what I should write in src?

<img src='path-toimage-in-filetable' />

I assume by FileTable you actually mean FileStream. A couple notes about that:

  1. This feature is best used if your files are actually files
  2. The files should be, on average, greater than 1mb - although there can be exceptions to this rule, if they're smaller than 1mb on average, you may be better off using a VARBINARY(MAX) or XML data type as appropriate. If your images are very small on average (only a few KB), consider using a VARBINARY(MAX) column.
  3. Accessing these files will require an open transaction and that the database is properly configured for FILESTREAM
  4. You can get some significant advantages bypassing the normal SQL engine/database file method of data access by telling SQL Server that you want to access the file directly, however it's not meant for directly accessing the file on the file system and attempting to do so can break SQL's management of these files (transactional consistency, tracking, locking, etc.).
  5. It's pretty likely that your use case here would be better served by using a CDN and storing image URLs in the table if you really need SQL for this. You can use FILESTREAM to do this (see code sample below for one implementation), but you'll be hammering your SQL server for every request unless you store the images somewhere else anyway that the browser can properly cache (my example doesn't do that) - and if you store them somewhere else for rendering int he browser you might as well store them there to begin with (you won't have transactional consistency for those images once they're copied to some other drive/disk/location anyway).

With all that said, here's an example of how you'd access the FILESTREAM data using ADO.NET:

public static string connectionString = ...; // get your connection string from encrypted config

// assumes your FILESTREAM data column is called Img in a table called ImageTable
const string sql = @"
    SELECT            
        Img.PathName(),
        GET_FILESTREAM_TRANSACTION_CONTEXT()
      FROM ImageTagble
      WHERE ImageId = @id";

public string RetreiveImage(int id)
{
    string serverPath;
    byte[] txnToken;
    string base64ImageData = null;
    using (var ts = new TransactionScope())
    {
        using (var conn = new SqlConnection(connectionString))
        {
            conn.Open();
            using (SqlCommand cmd = new SqlCommand(sql, conn))
            {
                cmd.Parameters.Add("@id", SqlDbType.Int).Value = id;
                using (SqlDataReader rdr = cmd.ExecuteReader())
                {
                    rdr.Read();
                    serverPath = rdr.GetSqlString(0).Value;
                    txnToken = rdr.GetSqlBinary(1).Value;
                }
            }
            using (var sfs = new SqlFileStream(serverPath, txnToken, FileAccess.Read))
            {
            // sfs will now work basically like a FileStream.  You can either copy it locally or return it as a base64 encoded string
               using (var ms = new MemoryStream())
               {
                  sfs.CopyTo(ms);
                  base64ImageData = Convert.ToBase64String(ms.ToArray());
               }
            }
        }
        ts.Complete();
        // assume this is PNG image data, replace PNG with JPG etc. as appropraite.  Might store in table if it will vary...
        return "data:img/png;base64," + base64ImageData;
    }
}

Obviously, if you have lots of images to handle like this this is not an ideal method - don't try to make an instance of SQL server into what you should be using a CDN for.... However, if you have other really good reasons, you should try to grab as many images as possible in a single request/transaction (eg if you know you're displaying 50 images on a page, get all 50 with a single transaction scope, don't use 50 transaction scopes - this code won't handle that).

I don't think you still need this, anyways I'll post my answer for anyone else interested. First, a filetable still being a table, so, if you want to access to data from it you need to use a Select SQL statement. So you'd need something like:

select name, file_stream from filetable_name 
where 
name = 'file_name',
file_type = 'file_extension'

just execute an statement like this in your asp.net app, then fetch the results and use the file_stream column to get the binary data of the stored file. If you want to retrieve the file from HTML, first you need to create an action in your controller, which will return the retrieved file:

public ActionResult GetFile(){
..
return File(file.file_stream,file.file_type);
}

After this, put in you HTML tag something like:

<img src="/controller/GetFile" />

hope this could help! If you want to know the schema of a filetable see here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM