看此文檔前,先參考一下文檔 https://blog.csdn.net/downmoon/article/details/24374609 環境:阿裡雲ECS SQL Server 2017 + Delphi7 測試用xcopy,robocopy等命令遷移文件好像不太會用。有感興趣的朋友,告知一下。 ...
看此文檔前,先參考一下文檔 https://blog.csdn.net/downmoon/article/details/24374609
環境:阿裡雲ECS SQL Server 2017 + Delphi7
測試用xcopy,robocopy等命令遷移文件好像不太會用。
倒是可以通過T-SQL的方法,但是需要文件在伺服器上面,這就有點難受了。如下:
--我們使用該函數插入一個圖片文件到該目錄下:這裡的路徑需要是伺服器上的路徑。 declare @image1 varbinary(max), @path_locator hierarchyid; select @image1=cast(bulkcolumn as varbinary(max)) from openrowset(bulk N'C:\1.png', single_blob) as x; select @path_locator=path_locator from DocumentStores where [name]='MyDir1'; insert into DocumentStores(name, file_stream, path_locator) values('1.png', @image1, dbo.fnGetNewPathLocator(newid(), @path_locator)); --如果你想使用SQL Server本身提供的hierarchyid層次結構,下麵這個函數也許可以幫你: create FUNCTION fnGetNewPathLocator (@child uniqueidentifier, @parent hierarchyid) returns hierarchyid as begin declare @ret hierarchyid, @binid Binary(16) = convert(binary(16), @child); select @ret=hierarchyid::Parse( COALESCE(@parent.ToString(), N'/') + CONVERT(nvarchar, CONVERT(bigint, SUBSTRING(@binId, 1, 6))) + N'.' + CONVERT(nvarchar, CONVERT(bigint, SUBSTRING(@binId, 7, 6))) + N'.' + CONVERT(nvarchar, CONVERT(bigint, SUBSTRING(@binId, 13, 4))) + N'/'); return @ret; end;
通過程式也能實現,只是如果層級太深,生成的path_locator太長,總感覺不太靠譜。
下麵是用Delphi實現的,Insert操作(本地E:\Doc目錄下所有文件遷移到FileTable)。
procedure TForm1.BitBtn9Click(Sender: TObject); var lst, lstContent: TStrings; I: Integer; strSQL: string; begin lst := TStringList.Create; lstContent := TStringList.Create; try GetFileStructureList('E:\Doc', lst); strSQL := EmptyStr; rzprogressbar1.TotalParts := lst.Count; for I:=0 to lst.Count-1 do begin SplitString(lst.Strings[I], '|', lstContent); if SameText(lstContent.Strings[0], '0') then //目錄 strSQL := strSQL + Format('Insert into DocumentStores(name, path_locator, is_directory, is_archive) values(%S, %S, %D, %D);', [QuotedStr(ExtractFileName(lstContent.Strings[1])), QuotedStr(lstContent.Strings[2]), 1, 0]) + #13#10 else if SameText(lstContent.Strings[0], '1') then //文件 strSQL := strSQL + Format('Insert into DocumentStores(name, path_locator, file_stream) values(%S, %S, %S);', [QuotedStr(ExtractFileName(lstContent.Strings[1])), QuotedStr(lstContent.Strings[2]), StrToHex(BaseEncodeFile(lstContent.Strings[1]))]) + #13#10; rzprogressbar1.PartsComplete := rzprogressbar1.PartsComplete + 1; Application.ProcessMessages; end; try ADOConnection1.Connected := True; ADOConnection1.BeginTrans; ADOQuery1.SQL.Text := strSQL; ADOQuery1.ExecSQL; ADOConnection1.CommitTrans; except ADOConnection1.RollbackTrans; end; finally lst.Free; lstContent.Free; end; end; //下麵是公用單元 unit U_Commfunc; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, EncdDecd, Contnrs; //生成filetable用的path_locator function GetPathLocator(root: Boolean=True): string; function GetGUID: string; function StrToHex(AStr: string): string; //文件轉字元串流 function BaseEncodeFile(fn: TFileName): string; procedure SplitString(Source,Deli:string; var lst :TStrings); //獲取目錄+文件的列表 返回值是文件的個數,頂層為選擇的目錄 為filetalbe插入用 function GetFileStructureList(Path: PChar; var lst: TStrings): LongInt; implementation function GetGUID: string; var LTep: TGUID; sGUID: string; begin CreateGUID(LTep); sGUID := GUIDToString(LTep); sGUID := StringReplace(sGUID, '-', '', [rfReplaceAll]); sGUID := Copy(sGUID, 2, Length(sGUID) - 2); Result := sGUID; end; function GetPathLocator(root: Boolean): string; var //LocatorPath的三個組成部分 S1,S2,S3; sGuid, S1, S2, S3: string; begin Result := ''; if root then Result := '/'; sGuid := GetGUID; S1 := IntToStr(StrToInt64(StrToHex(Copy(sGuid, 1, 6)))); S2 := IntToStr(StrToInt64(StrToHex(Copy(sGuid, 7, 6)))); S3 := IntToStr(StrToInt64(StrToHex(Copy(sGuid, 13, 4)))); Result := Result + S1 + '.' + S2 + '.' + S3 + '/'; end; function StrToHex(AStr: string): string; var i : Integer; ch:char; begin Result:='0x'; for i:=1 to length(AStr) do begin ch:=AStr[i]; Result:=Result+IntToHex(Ord(ch),2); end; end; function BaseEncodeFile(fn: TFileName): string; var ms: TMemoryStream; ss: TStringStream; str: string; begin ms := TMemoryStream.Create; ss := TStringStream.Create(''); try ms.LoadFromFile(fn); EncdDecd.EncodeStream(ms, ss); // 將ms的內容Base64到ss中 str := ss.DataString; str := StringReplace(str, #13, '', [rfReplaceAll]); // 這裡ss中數據會自動添加回車換行,所以需要將回車換行替換成空字元 str := StringReplace(str, #10, '', [rfReplaceAll]); result := str; // 返回值為Base64的Stream finally FreeAndNil(ms); FreeAndNil(ss); end; end; procedure SplitString(Source,Deli:string; var lst :TStrings); var EndOfCurrentString: Integer; begin if lst = nil then exit; lst.Clear; while Pos(Deli, Source)>0 do begin EndOfCurrentString := Pos(Deli, Source); lst.add(Copy(Source, 1, EndOfCurrentString - 1)); Source := Copy(Source, EndOfCurrentString + length(Deli), length(Source) - EndOfCurrentString); end; lst.Add(source); end; function GetFileStructureList(Path: PChar; var lst: TStrings): LongInt; var SearchRec: TSearchRec; Found: Integer; TmpStr, TmpLocator: string; CurDir, DirLocator: PChar; DirQue: TQueue; C: Cardinal; begin Result := 0; if lst = nil then exit; dirQue := TQueue.Create; try CurDir := Path; DirLocator := PChar(GetPathLocator()); lst.Add('0|'+CurDir+'|'+DirLocator); while CurDir <> nil do begin //搜索尾碼,如:c:\*.*; TmpStr := IncludeTrailingPathDelimiter(curDir)+'*.*'; Found := FindFirst(TmpStr, faAnyFile, SearchRec); while Found = 0 do begin C := GetFileAttributes(PChar(IncludeTrailingPathDelimiter(curDir) + SearchRec.Name)); //if (searchRec.Attr and faDirectory)<>0 then //這個貌似有問題/ if (C and FILE_ATTRIBUTE_DIRECTORY)<> 0 then begin if (SearchRec.Name <> '.') and (SearchRec.Name <> '..') then begin TmpStr := IncludeTrailingPathDelimiter(curDir)+SearchRec.Name; TmpLocator := GetPathLocator(False); TmpLocator := DirLocator + TmpLocator; lst.Add('0|'+TmpStr+'|'+TmpLocator); DirQue.Push(StrNew(PChar(TmpStr))); DirQue.Push(StrNew(PChar(TmpLocator))); end; end else begin Result:=Result+1; TmpLocator := GetPathLocator(False); TmpLocator := DirLocator + TmpLocator; lst.Add('1|'+IncludeTrailingPathDelimiter(curDir)+SearchRec.Name+'|'+TmpLocator); end; found:=FindNext(SearchRec); end; {當前目錄找到後,如果隊列中沒有數據,則表示全部找到了; 否則就是還有子目錄未查找,取一個出來繼續查找。} if DirQue.Count > 0 then begin CurDir := DirQue.Pop; DirLocator := DirQue.Pop; end else begin CurDir := nil; DirLocator := nil; end; end; finally dirQue.Free; end; end; end.
效果圖如下,目錄加文件共計20個。
本地文件夾E:\Doc:
FileTable虛擬目錄文件Doc:
資料庫表中存放數據: