2013-03-13 122 views
0

我想使用powershell腳本導出sql文件流數據,它只導出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 2013-03-13 20:38:37

+0

否。它始終創建文件,但問題在於,如果文件大小超過8kb,則會創建至8kb,而不會寫入文件中的剩餘字節。結果由於損壞,文件無法打開。 – user972255 2013-03-13 20:53:55

回答

0

我認爲你正在閱讀8191字節,這意味着$收到的將是8191如果更多的數據比這個。

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

那麼你應該比較$收到(8191),以$緩衝區大小(8192)

If ($received -lt $bufferSize) 
+0

我刪除了-1,但現在我得到一個錯誤,說「偏移量和長度超出了數組的範圍。請幫助... – user972255 2013-03-13 21:19:07

+0

也許試着改變if語句嗎?像這樣:if($ received -lt $ bufferSize -1) – 2013-03-13 21:39:27

+0

把文件流導出到數組似乎是錯誤的,流中只有一個數據元素,它似乎試圖將它全部填充到第一個數組元素中並運行到數組定義中限制 – mjolinor 2013-03-14 10:58:36

0

我已經做了一些工作,文件流和PowerShell,我會與其他的意見一致 - 這似乎有你如何獲得長度的問題。下面是從我的博客http://sev17.com/2010/05/11/t-sql-tuesday-006-blobs-filestream-and-powershell/一些代碼,演示瞭如何獲取FILESTREAM數據到圖像文件:

$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 2013-03-18 20:35:50

+0

可能是另一個進程鎖定AV或備份軟件的文件,可以使用Sysinternals Process Monitor弄清楚什麼是進程鎖定文件。 – 2013-03-19 11:41:47