欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

文件迁移到FileTable中

程序员文章站 2022-03-03 08:17:59
看此文档前,先参考一下文档 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中

 

 filetable虚拟目录文件doc:

文件迁移到FileTable中

数据库表中存放数据:

文件迁移到FileTable中