简体   繁体   English

如何访问存储在SQL Server FileTable中的文件?

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

As I know SQL Server since version 2012 has a new feature, FileTable . 据我所知,自2012版以来的SQL Server具有一项新功能FileTable It allows us to store files in the file system and to use them from T-SQL. 它使我们可以将文件存储在文件系统中,并可以通过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. 假设我有asp.net MVC应用程序,并且在网页上的img标签中显示了很多图像。 I would like to store these images in Filetable and access them as files from the filesystem. 我想将这些图像存储在Filetable中,并从文件系统中以文件形式访问它们。 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: 现在,我的图像存储在Web应用程序目录中的文件夹图像中,我编写如下内容:

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

And if I move my images to file table what I should write in src? 如果我将图像移动到文件表,应该在src中写什么?

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

I assume by FileTable you actually mean FileStream. 我假设FileTable实际上是指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. 文件平均应大于1mb-尽管此规则可能会有例外,但是如果文件平均小于1mb,则最好使用VARBINARY(MAX)XML数据类型。 If your images are very small on average (only a few KB), consider using a VARBINARY(MAX) column. 如果图像平均很小(只有几个KB),请考虑使用VARBINARY(MAX)列。
  3. Accessing these files will require an open transaction and that the database is properly configured for FILESTREAM 访问这些文件将需要一个打开的事务,并且已为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.). 通过告诉SQL Server您要直接访问文件,可以绕过常规SQL引擎/数据库文件的数据访问方法,可以获得一些显着的优势,但是,这并不意味着直接访问文件系统上的文件并且尝试这样做可以破坏SQL对这些文件的管理(事务一致性,跟踪,锁定等)。
  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. 如果您确实需要SQL,则很有可能通过使用CDN并在表中存储图像URL来更好地满足您的用例。 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). 可以使用FILESTREAM来执行此操作(有关一种实现,请参见下面的代码示例),但是除非您将图像存储在浏览器可以正常缓存的其他位置,否则您将为每个请求重用SQL Server(我的示例不这样做)那)-如果您将它们存储在其他位置以在浏览器中呈现,则最好将它们存储在此处(这些图像一旦复制到其他驱动器/磁盘/位置,就不会具有事务一致性) )。

With all that said, here's an example of how you'd access the FILESTREAM data using ADO.NET: 综上所述,这是一个如何使用ADO.NET访问FILESTREAM数据的示例:

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). 显然,如果您要处理大量图像,这不是理想的方法-请勿尝试将SQL Server实例转换为应使用CDN的对象。...但是,如果您确实有其他有充分的理由,您应该尝试在单个请求/事务中获取尽可能多的图像(例如,如果您知道在一个页面上显示50张图像,请使用单个交易范围获取全部50张图像,而不使用50个交易范围-此代码将无法处理)。

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. 首先,文件表仍然是表,因此,如果要从中访问数据,则需要使用Select SQL语句。 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. 只需在asp.net应用中执行这样的语句,然后获取结果并使用file_stream列即可获取存储文件的二进制数据。 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: 如果要从HTML检索文件,则首先需要在控制器中创建一个操作,该操作将返回检索到的文件:

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

After this, put in you HTML tag something like: 之后,在您的HTML标记中添加以下内容:

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

hope this could help! 希望这会有所帮助! If you want to know the schema of a filetable see here 如果您想了解文件表的架构,请参见此处

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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