2013-03-13 5 views
0

Я пытаюсь экспортировать данные sql filestream с помощью сценария powershell и экспортирует только до 8kb, и он не может экспортировать, если файл больше 8kb. Но он создает файл частично. Я не знаю, чего не хватает.Что не так с этим скриптом PowerShell?

$Server = "(local)";    # SQL Server Instance.    
$Database = "AdventureWorks";    
$Dest = "D:\Export\";    # Path to export to.    
$bufferSize = 8192;    # Stream buffer size in bytes.    

$con = New-Object Data.SqlClient.SqlConnection;    
$con.ConnectionString = "Data Source=$Server;" +    
        "Integrated Security=True;" +    
        "Initial Catalog=$Database";    
$con.Open();    

[System.Data.SqlClient.SqlTransaction]$tran = $con.BeginTransaction("fs");    
$Sql = "SELECT GET_FILESTREAM_TRANSACTION_CONTEXT()";    
$ctx = [array]::CreateInstance('Byte', 16);    
$cmdct = New-Object Data.SqlClient.SqlCommand($Sql, $con, $tran);    
$ctx = $cmdct.ExecuteScalar();    
$cmdct.Dispose();    

$Sql = "SELECT [FileName] 
      ,[FileStreamData].PathName() 
    FROM dbo.FileStreamStorage ";    

$out = [array]::CreateInstance('Byte', $bufferSize);    

$cmd = New-Object Data.SqlClient.SqlCommand($Sql, $con, $tran);    
$rd = $cmd.ExecuteReader();    

While ($rd.Read())    
{    
Write-Output ("Exporting: {0}" -f $rd.GetString(0));      

$fs = New-Object System.IO.FileStream ($Dest + $rd.GetString(0)), Create, Write;    
$bw = New-Object System.IO.BinaryWriter($fs);    
$sfs = New-Object System.Data.SqlTypes.SqlFileStream $rd.GetString(1), $ctx, Read, None, 0;    

$start = 0;    
While (1 -eq 1)    
{        
    $received = $sfs.Read($out, $start, $bufferSize - 1);    
    $bw.Write($out, 0, $received);    
    $bw.Flush();    
    $start += $received;    

    If ($received -lt $bufferSize)    
    { break; }    
}    

$bw.Close();    
$fs.Close();    
$sfs.Close();    
}    

$fs.Dispose();    
$sfs.Dispose();    
$rd.Close();    
$rd.Dispose();    
$tran.Commit();    
$cmd.Dispose();    
$tran.Dispose();    
$con.Close();    
$con.Dispose();    

Write-Output ("Finished"); 

Любая помощь будет действительно оценена.

+0

Любые ошибки? Исключения? – Oded

+0

Нет. Он создает файл все время, но проблема в том, что размер файла больше 8kb, он создает до 8kb и не записывает оставшиеся байты в файл. В результате файлы не могут быть открыты из-за коррупции. – user972255

ответ

0

Я думаю, что вы читаете 8191 байт, что означает, что $ получено будет 8191, если у вас больше данных, чем это.

$received = $sfs.Read($out, $start, **$bufferSize - 1**); 

Тогда вы сравните $ получил (8191) до $ BufferSize (8192)

If ($received -lt $bufferSize) 
+0

Я удалил -1, но теперь я получаю сообщение об ошибке: «Смещение и длина были за пределами массива. Пожалуйста, помогите ... – user972255

+0

Может быть, попытайтесь изменить вместо этого выражение if? Например: if ($ received -lt $ bufferSize -1) –

+0

Идея экспортировать поток в массив кажется неправильной. В потоке будет только один элемент данных. Кажется, он пытается заполнить все это в первый элемент массива и запустить определение массива Ограничения – mjolinor

0

Я сделал некоторые работы с Powershell и потокового видео, и я согласен с другими комментариями - Оказывается, есть проблема в том, как вы получаете длину. Вот какой код из моего блога http://sev17.com/2010/05/11/t-sql-tuesday-006-blobs-filestream-and-powershell/, который демонстрирует получение данных потока в файл изображения:

$server = "Z002sql2k8" 
$database = "AdventureWorks2008" 
$query = "SELECT TOP(10) Document.PathName(), GET_FILESTREAM_TRANSACTION_CONTEXT(), Title + FileExtension AS FileName FROM Production.Document WHERE FileExtension = '.doc'" 
$dirPath = "C:Usersu00" 

$connection=new-object System.Data.SqlClient.SQLConnection 
$connection.ConnectionString="Server={0};Database={1};Integrated Security=True" -f $server,$database 
$connection.Open() 
$command=new-object system.Data.SqlClient.SqlCommand("",$connection) 
$command.CommandTimeout=120 
$tran = $connection.BeginTransaction([System.Data.IsolationLevel]'ReadCommitted') 
$command.Transaction = $tran 
$command.CommandText = $query 
$reader = $command.ExecuteReader() 
while ($reader.Read()) 
{ 
    $path = $reader.GetString(0) 
    [byte[]]$transactionContext = $reader.GetSqlBytes(1).Buffer 
    $filepath = "$dirPath{0}" -f $reader.GetValue(2) 

    $fileStream = new-object System.Data.SqlTypes.SqlFileStream($path,[byte[]]$reader.GetValue(1), [System.IO.FileAccess]'Read', [System.IO.FileOptions]'SequentialScan', 0) 
    $buffer = new-object byte[] $fileStream.Length 
    $fileStream.Read($buffer,0,$fileStream.Length) 
    $fileStream.Close() 
    [System.IO.File]::WriteAllBytes($filepath,$buffer) 

} 

$reader.Close() 
$tran.Commit() 
$connection.Close() 
+0

Но при использовании приведенного выше сценария появляется ошибка «Файл используется другим процессом». – user972255

+0

Возможно, это другой файл блокировки процесса, такой как AV или программное обеспечение для резервного копирования. Вы можете использовать Sysinternals Process Monitor для выяснить, какой файл блокировки процесса. –