从存储在Microsoft SQL数据库中的文件创建文件系统文件
标题听起来令人困惑,但我不知道如何更好地描述它。
我的任务是将数据库从程序A迁移到程序B。程序A使用MSSQL数据库并将其所有文件存储在该数据库中。
程序B处理以正常方式存储的文件,即存储在文件系统中。
现在我必须使用PHP将数据库存储的文件提取、转换并下载到文件系统文件,但尝试转换它们失败。
出于测试目的,我创建了一个内容为Test document for migration
的简单.txt
文件,程序A将其存储在数据库中:
0x5465737420646F63756D656E7420666F72206D6967726174696F6E'
这是什么格式,以及如何将其转换为普通document.txt
文件?
编辑
非常感谢@PanagiotisKanavos。现在可以使用流:$query = "select top(1) DESCRIPTION, FILETYPE, DOCUMENT from dbo.Documents;";
$stmt = sqlsrv_query($this->sqlsrv_conn, $query);
if (sqlsrv_fetch($stmt)) {
$document = sqlsrv_get_field($stmt, 2, SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY));
$fileName = sqlsrv_get_field($stmt, 0, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR));
$ext = sqlsrv_get_field($stmt, 1, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR));
file_put_contents(
$fileName . '.' . $ext,
stream_get_contents($document),
);
}
现在,对所有文件执行此操作的最有效方法是什么?我必须对每一行执行查询吗?
通过PDO,我可以使用$stmt->fetchAll(FETCH_ASSOC)
,它为我提供了一个包含数据的漂亮的ASSOC数组。
sqlsrv
具有类似的sqlsrv_fetch_array
功能,php.net和[docs.microsoft]通过以下示例进行说明:
while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_ASSOC) ) {
echo $row['LastName'].", ".$row['FirstName']."<br />";
}
但就我所能进行的搜索而言,我找不到一种方法来循环遍历结果集,除非读取它,然后在流和字符串类型混合的情况下分别读取每一行。sqlsrv_fetch_array
只接受SQLSRV_FETCH_NUMERIC
、SQLSRV_FETCH_ASSOC
和SQLSRV_FETCH_BOTH
,然后结果集已经获取,不能使用sqlsrv_get_field
来设置每个字段的类型。
我不可能是第一个需要这样东西的人,但我找不到任何关于它的东西。可能我搜索错误,或者我误解了一个概念。
解决方案
这不是一种格式,它是某些数据库管理工具(如SSMS)显示二进制数据的方式。数据已经是二进制数据,不需要转换。
读取大对象(LOB)就像它们是数字或字符串一样非常慢,在服务器和客户端内存中缓存整个文档,即使对象不会被重用,甚至不需要保存在内存中。毕竟,SQL Server中的BLOB
可以是2 GB甚至更大。这就是为什么几乎所有数据库和数据访问库都允许将LOB作为文件流处理。
Microsoft的PHP文档示例显示了如何将PDO和SQLSRV的LOB读取为文件流。
复制该示例,此参数化查询将搜索用户的图片:
/* Get the product picture for a given product ID. */
$tsql = "SELECT LargePhoto
FROM Production.ProductPhoto AS p
JOIN Production.ProductProductPhoto AS q
ON p.ProductPhotoID = q.ProductPhotoID
WHERE ProductID = ?";
$params = array(&$_REQUEST['productId']);
/* Execute the query. */
$stmt = sqlsrv_query($conn, $tsql, $params);
不是将整个图片作为单个值读取,而是以文件流的形式加载:
$getAsType = SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY);
if ( sqlsrv_fetch( $stmt ) )
{
$image = sqlsrv_get_field( $stmt, 0, $getAsType);
fpassthru($image);
}
else
{
echo "Error in retrieving data.</br>";
die(print_r( sqlsrv_errors(), true));
}
$getAsType = SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY);
指定将以流的形式检索数据。
$image = sqlsrv_get_field( $stmt, 0, $getAsType);
使用指定的类型检索第一个字段,在本例中为流。这不会加载实际内容。
fpassthru将流内容直接复制到输出。图片大小可能为2 GB,但永远不会保存在Web服务器的内存中。
相关文章