Code-Dump from our repo. We're no longer using FileTables, hence I had to dig deep in our git history and haven't used this code since early 2020, but I assume it still runs.
This is all the interesting stuff I could find, I assume everything else (like checking if a file exists, updating attributes etc) is pretty self-explaining.
Get a new Hierarchy-Id in code (needed for a few queries)
Public Function GetNewHierarchyId() As String
Dim g = Guid.NewGuid().ToByteArray()
Dim used = 0
Dim strings = New List(Of String)()
For Each i In {6, 6, 4}
Dim buf(7) As Byte
Array.Copy(g, used, buf, CInt(IIf(BitConverter.IsLittleEndian, 0, 2)), i)
used += i
strings.Add(BitConverter.ToUInt64(buf, 0).ToString())
Next
Return String.Join(".", strings) & "/"
End Function
Handling Directories
Delete directory non-recursively (only if its empty)
DELETE TOP(1) a FROM MyFilesTable a WHERE a.path_locator = GetPathLocator(@path) AND a.is_directory=1 AND NOT EXISTS (SELECT 1 FROM MyFilesTable b WHERE b.parent_path_locator = a.path_locator)
Delete directory recursively
DELETE FROM MyFilesTable WHERE path_locator.IsDescendantOf(GetPathLocator(@path)) = 1
Moving a Directory (including all files / subfolders)
DECLARE @srcID hierarchyid = GETPATHLOCATOR(@src);
DECLARE @srcParentId hierarchyid = (SELECT ISNULL(parent_path_locator, 0x) FROM MyFilesTable WHERE path_locator = @srcId);
IF @srcParentId IS NULL
BEGIN
RAISERROR('Source Directory ""%s"" does not exist', 16, 1, @src)
RETURN
END
DECLARE @newName nvarchar(max) = right(@dest, charindex('\', reverse(@dest) + '\') - 1);
DECLARE @destParentId hierarchyid = GetPathLocator(@dest);
DECLARE @destExists bit = 1;
IF @destParentId IS NULL
--dest does not exist yet, will move into dest's parent + rename
BEGIN
SET @destExists = 0;
SET @destParentID = GetPathLocator(left(@dest, len(@dest) - charindex('\', reverse(@dest) + '\')));
IF @destParentID IS NULL
BEGIN
RAISERROR('Destination Directory ""%s"" or its parent do not exist', 16, 1, @dest)
RETURN
END
END
IF @destParentId != @srcParentId AND @srcID != @destParentId
BEGIN
UPDATE MyFilesTable
SET path_locator = STUFF(path_locator.ToString(), 1, len(@srcParentId.ToString()), @destParentId.ToString())
WHERE path_locator.IsDescendantOf(GetPathLocator(@src)) = 1;
SET @srcId = STUFF(@srcId.ToString(), 1, len(@srcParentId.ToString()), @destParentId.ToString());
END
IF @destExists = 0 OR @srcID = @destParentId
UPDATE MyFilesTable
SET name = @newName
WHERE path_locator = @srcID"
Get Content of a Directory
SELECT FileTableRootPath() + file_stream.GetFileNamespacePath()
FROM MyFilesTable
WHERE path_locator.IsDescendantOf(GetPathLocator(@path)) = 1 --recursively
--AND parent_path_locator = GetPathLocator(@path) --use this instead for non-recursive search
Handling Files
Move a file
UPDATE MyFilesTable
SET
path_locator = STUFF(path_locator.ToString(), 1, ISNULL(LEN(parent_path_locator.ToString()), 1), GetPathLocator(@dstPath).ToString()),
name = @dstName
WHERE path_locator = GetPathLocator(@src)
Add a file
INSERT INTO MyFilesTable (name, path_locator, file_stream) VALUES (@name, CONCAT(GetPathLocator(@parent).ToString(), @newHierarchyId), @bytes)
Copy a file: First add a file with empty @bytes, then:
UPDATE dst
SET
dst.file_stream = src.file_stream,
dst.creation_time = src.creation_time,
dst.last_write_time = src.last_write_time,
dst.last_access_time = GETDATE(),
dst.is_offline = src.is_offline,
dst.is_hidden = src.is_hidden,
dst.is_readonly = src.is_readonly,
dst.is_archive = src.is_archive,
dst.is_system = src.is_system,
dst.is_temporary = src.is_temporary
FROM MyFilesTable dst
INNER JOIN MyFilesTable src ON src.path_locator=GetPathLocator(@src)
WHERE dst.path_locator=GetPathLocator(@dst)
Special Stuff
Read a value from an ini-file:
DECLARE @content varchar(max)
DECLARE @sectionStart int
DECLARE @sectionEnd int
DECLARE @valueStart int
DECLARE @valueEnd int
SELECT @content = convert(varchar(max), file_stream) FROM MyFilesTable WHERE path_locator=GetPathLocator(@filePath)
SELECT @sectionStart = CHARINDEX(CHAR(10) + '[' + @section, @content);
IF @sectionStart = 0
SELECT @sectionStart = CHARINDEX(@section, @content);
IF @sectionStart = 0
SELECT NULL;
ELSE
BEGIN
SELECT @sectionEnd = CHARINDEX(CHAR(10) + '[', @content, @sectionStart + 2);
IF @sectionEnd = 0
SELECT @sectionEnd = LEN(@content)
SELECT @content = SUBSTRING(@content, @sectionStart, @sectionEnd - @sectionStart)
SELECT @valueStart = CHARINDEX(CHAR(10) + @value, @content)
IF @valueStart = 0
SELECT NULL
ELSE
BEGIN
SELECT @valueEnd = CHARINDEX(CHAR(10), @content, @valueStart + 1)
IF @valueEnd = 0
SELECT @valueEnd = LEN(@content)
SELECT @content = LTRIM(RTRIM(SUBSTRING(@content, @valueStart + LEN(@value) + 1, @valueEnd - @valueStart - LEN(@value) - 1)))
IF LEN(@content) > 0
SELECT REPLACE(LTRIM(RIGHT(@content, LEN(@content) - 1)), CHAR(13), '')
ELSE
SELECT NULL
END
END
Write a value to an ini-value
DECLARE @content varchar(max)
DECLARE @sectionStart int
DECLARE @sectionEnd int
DECLARE @valueStart int
DECLARE @valueEnd int
SELECT @content = convert(varchar(max), file_stream) FROM MyFilesTable WHERE path_locator=GetPathLocator(@filePath)
SELECT @sectionStart = CHARINDEX(CHAR(10) + '[' + @section, @content);
IF @sectionStart = 0
SELECT @sectionStart = CHARINDEX(@section, @content);
IF @sectionStart = 0
--section not found
BEGIN
WHILE LEN(@content) >= 2 AND RIGHT(@content, 2) = CONCAT(CHAR(13), CHAR(10))
SELECT @content = LEFT(@content, LEN(@content)-2) --remove newlines at end of file
SELECT @content = @content + CHAR(13) + CHAR(10) + CHAR(13) + CHAR(10) + '[' + @section + ']' + CHAR(13) + CHAR(10)
SELECT @sectionStart = LEN(@content) - 3
END
SELECT @sectionEnd = CHARINDEX(CHAR(10) + '[', @content, @sectionStart + 2);
IF @sectionEnd = 0
SELECT @sectionEnd = LEN(@content)
SELECT @valueStart = CHARINDEX(CHAR(10) + @valueName, SUBSTRING(@content, 0, @sectionEnd), @sectionStart + 1)
IF @valueStart = 0
--new value
BEGIN
WHILE @sectionEnd > 2 AND SUBSTRING(@content, @sectionEnd-1, 2) = CONCAT(CHAR(13), CHAR(10))
BEGIN
SELECT @content = STUFF(@content, @sectionEnd-1, 2, '') --remove newlines at end of section
SELECT @sectionEnd = @sectionEnd -2
END
IF @sectionEnd = LEN(@content)
SELECT @content = CONCAT(@content, CHAR(13), CHAR(10), @valueName, '=', @newValue, CHAR(13), CHAR(10)) --add new value at end of file
ELSE
SELECT @content = STUFF(@content, @sectionEnd+1, 0, CONCAT(CHAR(13), CHAR(10), @valueName, '=', @newValue, CHAR(13), CHAR(10), CHAR(13), CHAR(10))) --add new value at end of section
END
ELSE
--existing value
BEGIN
SELECT @valueEnd = CHARINDEX(CHAR(10), @content, @valueStart + 1)
IF @valueEnd = 0
SELECT @valueEnd = LEN(@content)
SELECT @content = STUFF(@content, @valueStart + 1, @valueEnd - @valueStart, CONCAT(@valueName, '=', @newValue, CHAR(13), CHAR(10))) --replace line with @valueName=@newValue
END
UPDATE MyFilesTable SET file_stream = CAST(@content as varbinary(max)) WHERE path_locator=GetPathLocator(@filePath)