#sql #sql-server #powershell
Вопрос:
Я пытался заставить скрипт PS работать при извлечении файлов (pdf, word и т.д.) Из базы данных SQL Server. Я наткнулся на приведенный ниже сценарий PowerShell. Сценарий запускается и заполняет папку назначения, но все файлы имеют размер 0 байт и во время выполнения сценария. Это приводит к ошибке:
«Экспорт объектов из контейнера FILESTREAM: Исключение .docx, вызывающее «getBytes» с аргументом(ами) «5»: «Недопустимая попытка получить байты в столбце «расширение». Функция getBytes может использоваться только для столбцов типа e Text, NText или изображения.»»
Может ли кто-нибудь указать мне, что я делаю не так и как это исправить, пожалуйста? Очень признателен.
$Server = ".xxxxxx";
$Database = "xxxxxx";
$Dest = "C:DATA";
$bufferSize = 8192;
$Sql = "
SELECT
[extension]
FROM [XXXXXXXX].[dbo].[XXXXXXdocuments]
";
$con = New-Object Data.SqlClient.SqlConnection;
$con.ConnectionString = "Data Source=$Server;"
"Integrated Security=True;"
"Initial Catalog=$Database";
$con.Open();
Write-Output ((Get-Date -format yyyy-MM-dd-HH:mm:ss) ": Started ...");
$cmd = New-Object Data.SqlClient.SqlCommand $Sql, $con;
$cmd.CommandTimeout = 120
$rd = $cmd.ExecuteReader();
$out = [array]::CreateInstance('Byte', $bufferSize)
While ($rd.Read())
{
try
{
Write-Output ("Exporting Objects from FILESTREAM container: {0}" -f $rd.GetString(0));
$fs = New-Object System.IO.FileStream ($Dest $rd.GetString(0)), Create, Write;
$bw = New-Object System.IO.BinaryWriter $fs;
$start = 0;
enter code here
$received = $rd.Getbytes(0, $start, $out, 0, $bufferSize - 1);
While ($received -gt 0)
{
$bw.Write($out, 0, $received);
$bw.Flush();
$start = $received;
$received = $rd.Getbytes(0, $start, $out, 0, $bufferSize - 1);
}
$bw.Close();
$fs.Close();
}
catch
{
Write-Output ($_.Exception.Message)
}
finally
{
$fs.Dispose();
}
}
$rd.Close();
$cmd.Dispose();
$con.Close();
Write-Output ("Finished");
Read-Host -Prompt "Press Enter to exit"
Комментарии:
1. Ошибка кажется очевидной в отношении проблемы с данными, когда поле, которое вы пытаетесь прочитать, не может быть вызвано
GetBytes()
. Каков тип поля данныхextension
? Помнитеvarchar
, что » илиnvarchar
«- это не то жеtext
самое, что «илиntext
«. Вы сохраняете двоичные данные PDF, DOCX и т.д. в базе данных?2. Спасибо, что уделили время, чтобы посмотреть на это, мне удалось выяснить, что проблема в том, что я вызывал столбцы, которые не содержали данные, которые я пытался извлечь, после того, как они были просмотрены и исправлены, все работает нормально. Очень признателен
Ответ №1:
BinaryWriter не нужен. Это для записи примитивных типов в поток.
И нет необходимости возиться с буферами; вы можете просто использовать SqlDataReader.GetStream(int).CopyTo(Stream)
, например
$Server = "localhost";
$Database = "adventureworks2017";
$Dest = "C:temp";
$Sql = "
SELECT concat('photo', ProductPhotoID, '.jpg') name, LargePhoto from Production.ProductPhoto
";
$con = New-Object Data.SqlClient.SqlConnection;
$con.ConnectionString = "Data Source=$Server;Integrated Security=True;Initial Catalog=$Database;TrustServerCertificate=true";
$con.Open();
Write-Output ((Get-Date -format yyyy-MM-dd-HH:mm:ss) ": Started ...");
$cmd = New-Object Data.SqlClient.SqlCommand $Sql, $con;
$cmd.CommandTimeout = 120
$rd = $cmd.ExecuteReader();
While ($rd.Read())
{
try
{
Write-Output ("Exporting: {0}" -f $rd.GetString(0));
$fs = New-Object System.IO.FileStream ($Dest $rd.GetString(0)), Create, Write;
$rd.GetStream(1).CopyTo($fs)
$fs.Close()
}
catch
{
Write-Output ($_.Exception.Message)
}
finally
{
$fs.Dispose();
}
}
$rd.Close();
$cmd.Dispose();
$con.Close();
Write-Output ("Finished");