如何使用PHP将MSSQL中存储的二进制文件导出为本地文件系统文件
关于存储格式的问题
你看到的0x开头的字符串是MSSQL中二进制数据的十六进制表示形式,你测试的文本Test document for migration对应的ASCII编码转十六进制后刚好就是这段内容,不需要额外做特殊编码转换,只要正确读取二进制内容写入文件即可得到原文件。
批量导出的最优实现方案
你不需要为每一行单独执行查询,也不需要强制使用sqlsrv_fetch_array,直接把现有的单文件逻辑套入sqlsrv_fetch的循环即可,这是性能最优、内存占用最低的实现方式:
// 去掉top(1)限制查询所有记录 $query = "select DESCRIPTION, FILETYPE, DOCUMENT from dbo.Documents;"; $stmt = sqlsrv_query($this->sqlsrv_conn, $query); if ($stmt === false) { // 此处可添加自定义错误处理逻辑 die(print_r(sqlsrv_errors(), true)); } // 循环遍历每一行结果 while (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), ); } sqlsrv_free_stmt($stmt);
补充说明
你找不到sqlsrv_fetch_array处理不同字段类型的资料是正常的,因为这个函数本身就是用来一次性返回整行的普通类型结果的,对于二进制大字段的流式处理场景,官方本来就推荐直接用sqlsrv_fetch + sqlsrv_get_field的组合来实现,这种方式可以避免一次性把所有大文件内容加载到内存中,哪怕有几万条文件记录,运行时的内存占用也能稳定保持在很低的水平。
如果确实偏好关联数组的写法,也可以在执行查询后、遍历结果前,用sqlsrv_set_field_type预先为每个字段指定返回类型,之后再用sqlsrv_fetch_array读取就能得到符合预期的类型结果,但综合性能和可读性来看还是循环调用sqlsrv_get_field的方案更适合文件导出场景。
内容的提问来源于stack exchange,提问作者Samuel Gfeller
相关产品推荐
相关产品推荐

