如何使用SQL Server列出文件夹中的文件

时间:2012-07-19 11:25:48

标签: sql sql-server

如何在不使用xp_cmdshell存储过程的情况下在SQL Server中的文件夹中列出文件?

6 个答案:

答案 0 :(得分:62)

您可以使用 xp_dirtree

需要三个参数:

根目录的路径, 您希望获取文件和文件夹的深度 最后一个是仅显示文件夹或同时显示文件夹和文件。

示例:EXEC xp_dirtree 'C:\', 10, 1

答案 1 :(得分:27)

可以使用xp_DirTree完成,然后循环以生成完整的文件路径(如果需要)。

以下是我用于自动将数据库还原到测试服务器的脚本的摘录。它会扫描文件夹和所有子文件夹中的任何备份文件,然后返回完整路径。


  DECLARE @BackupDirectory SYSNAME = @BackupFolder

  IF OBJECT_ID('tempdb..#DirTree') IS NOT NULL
    DROP TABLE #DirTree

  CREATE TABLE #DirTree (
    Id int identity(1,1),
    SubDirectory nvarchar(255),
    Depth smallint,
    FileFlag bit,
    ParentDirectoryID int
   )

   INSERT INTO #DirTree (SubDirectory, Depth, FileFlag)
   EXEC master..xp_dirtree @BackupDirectory, 10, 1

   UPDATE #DirTree
   SET ParentDirectoryID = (
    SELECT MAX(Id) FROM #DirTree d2
    WHERE Depth = d.Depth - 1 AND d2.Id < d.Id
   )
   FROM #DirTree d

  DECLARE 
    @ID INT,
    @BackupFile VARCHAR(MAX),
    @Depth TINYINT,
    @FileFlag BIT,
    @ParentDirectoryID INT,
    @wkSubParentDirectoryID INT,
    @wkSubDirectory VARCHAR(MAX)

  DECLARE @BackupFiles TABLE
  (
    FileNamePath VARCHAR(MAX),
    TransLogFlag BIT,
    BackupFile VARCHAR(MAX),    
    DatabaseName VARCHAR(MAX)
  )

  DECLARE FileCursor CURSOR LOCAL FORWARD_ONLY FOR
  SELECT * FROM #DirTree WHERE FileFlag = 1

  OPEN FileCursor
  FETCH NEXT FROM FileCursor INTO 
    @ID,
    @BackupFile,
    @Depth,
    @FileFlag,
    @ParentDirectoryID  

  SET @wkSubParentDirectoryID = @ParentDirectoryID

  WHILE @@FETCH_STATUS = 0
  BEGIN
    --loop to generate path in reverse, starting with backup file then prefixing subfolders in a loop
    WHILE @wkSubParentDirectoryID IS NOT NULL
    BEGIN
      SELECT @wkSubDirectory = SubDirectory, @wkSubParentDirectoryID = ParentDirectoryID 
      FROM #DirTree 
      WHERE ID = @wkSubParentDirectoryID

      SELECT @BackupFile = @wkSubDirectory + '\' + @BackupFile
    END

    --no more subfolders in loop so now prefix the root backup folder
    SELECT @BackupFile = @BackupDirectory + @BackupFile

    --put backupfile into a table and then later work out which ones are log and full backups  
    INSERT INTO @BackupFiles (FileNamePath) VALUES(@BackupFile)

    FETCH NEXT FROM FileCursor INTO 
      @ID,
      @BackupFile,
      @Depth,
      @FileFlag,
      @ParentDirectoryID 

    SET @wkSubParentDirectoryID = @ParentDirectoryID      
  END

  CLOSE FileCursor
  DEALLOCATE FileCursor

答案 2 :(得分:7)

创建具有外部访问权限的SQLCLR程序集,该权限将文件列表作为结果集返回。有很多例子如何做到这一点,例如。 Yet another TVF: returning files from a directoryTrading in xp_cmdshell for SQLCLR (Part 1) - List Directory Contents

答案 3 :(得分:4)

如果您愿意,可以使用CLR功能/组件实现此目的。

  1. 创建SQL Server CLR程序集项目。
  2. 转到属性并确保“连接”上的权限级别设置为“外部”
  3. 将Sql函数添加到程序集中。
  4. 这是一个示例,允许您选择表格结果集。

    public partial class UserDefinedFunctions
    {
        [SqlFunction(DataAccess = DataAccessKind.Read,
            FillRowMethodName = "GetFiles_FillRow", TableDefinition = "FilePath nvarchar(4000)")]
        public static IEnumerable GetFiles(SqlString path)
        {
            return System.IO.Directory.GetFiles(path.ToString()).Select(s => new SqlString(s));
        }
    
        public static void GetFiles_FillRow(object obj,out SqlString filePath)
        {
            filePath = (SqlString)obj;
        }
    };
    

    你的SQL查询。

    use MyDb
    
    select * From GetFiles('C:\Temp\');
    

    请注意,您的数据库需要使用以下SQL命令启用CLR程序集功能。

    sp_configure 'clr enabled', 1
    GO
    RECONFIGURE
    GO
    

    CLR程序集(如XP_CMDShell)默认情况下处于禁用状态,因此如果不使用XP Cmd Shell的原因是您没有权限,那么您可能会遇到这种情况选项以及...仅供参考。

答案 4 :(得分:1)

我狩猎了很多年才找到一个不错的简单解决方案,最后找到了一些非常复杂的CLR解决方案,所以决定编写我自己的简单VB。只需从已安装的模板下的数据库选项卡创建一个新的VB CLR项目,然后添加一个新的 SQL CLR VB用户定义函数。我将其重命名为 CLRGetFilesInDir.vb 。这是里面的代码......

Imports System
Imports System.Data
Imports System.Data.Sql
Imports System.Data.SqlTypes
Imports Microsoft.SqlServer.Server
Imports System.IO
-----------------------------------------------------------------------------
Public Class CLRFilesInDir
-----------------------------------------------------------------------------
<SqlFunction(FillRowMethodName:="FillRowFiles", IsDeterministic:=True, IsPrecise:=True, TableDefinition:="FilePath nvarchar(4000)")> _
Public Shared Function GetFiles(PathName As SqlString, Pattern As SqlString) As IEnumerable
    Dim FileNames As String()

    Try
    FileNames = Directory.GetFiles(PathName, Pattern, SearchOption.TopDirectoryOnly)
    Catch
        FileNames = Nothing
    End Try

    Return FileNames

End Function
-----------------------------------------------------------------------------
Public Shared Sub FillRowFiles(ByVal obj As Object, ByRef Val As SqlString)
    Val = CType(obj, String).ToString
End Sub

End Class

我还将项目属性窗口中的程序集名称更改为 CLRExcelFiles ,将默认名称空间更改为 CLRGetExcelFiles

注意:如果您使用的内容少于SQL Server 2012,请将目标框架设置为3.5。

编译项目,然后将CLRExcelFiles.dll从\ bin \ release复制到SQL Server计算机上的C:\ temp ,而不是您自己的。

在SSMS中: -

CREATE ASSEMBLY <your assembly name in here - anything you like>
FROM 'C:\temp\CLRExcelFiles.dll';

CREATE FUNCTION dbo.fnGetFiles
(
@PathName NVARCHAR(MAX),
@Pattern NVARCHAR(MAX)
)
RETURNS TABLE (Val NVARCHAR(100))
AS
EXTERNAL NAME <your assembly name>."CLRGetExcelFiles.CLRFilesInDir".GetFiles;
GO

然后调用它

SELECT * FROM dbo.fnGetFiles('\\<SERVERNAME>\<$SHARE>\<folder>\' , '*.xls')

注意:即使我在项目属性下的SQLCLR选项卡上将权限级别更改为EXTERNAL_ACCESS,我仍然需要在每次(重新)创建它时运行它。

ALTER ASSEMBLY [CLRFilesInDirAssembly] 
WITH PERMISSION_SET = EXTERNAL_ACCESS 
GO

和wullah!应该工作。

答案 5 :(得分:-7)

非常简单,只需使用SQLCMD语法。

请记住在SSMS中启用SQLCMD模式,查看“查询” - &gt; SQLCMD模式

尝试执行:

!! DIR
!!:GO

或者可能:
    !! DIR“c:/ temp”
    !!:GO