【问题标题】:Get each file size inside a Folder using SQL使用 SQL 获取文件夹中的每个文件大小
【发布时间】:2011-10-31 10:26:31
【问题描述】:

我们将图像保存在可以有图像和子文件夹的文件夹中,这些子文件夹也可以有图像和子文件夹,例如

c:\myImageFolder\image1.png    //'myImageFolder' have image
c:\myImageFolder\Folder1\imagex.png // 'myImageFolder' have another folder inside which is 'Folder1'.
c:\myImageFolder\Folder1\ChildFolder1\imagen.png // 'myImageFolder' have 'Folder1' which have 'ChildFolder1' which have imagen.png

我们需要知道有多少张图片超过 1 MB、超过 750KB 和 500KB?

一些事实:

  • 我们需要通过 SQL 来完成
  • 我们使用的是 SQL Server 2008
  • myImageFolder 包含数千个子文件夹
  • myImageFolder 大小接近 5 GB

提前感谢您宝贵的时间和帮助。 注意: I found the solution, you can find it here

【问题讨论】:

  • 为什么不将文档保存在数据库中?
  • @reinierpost 谢谢。图片路径存在于数据中。
  • 我明白了。为什么不将文档保存在数据库中?
  • @reinierpost 实际上文件信息不是定期需要的,这可能是我们第一次和最后一次需要知道文件大小。只是为了更新你,我找到了解决方案,你看到了吗?请找到我的答案here
  • 非常好,但我不知道这些天将文档保存在文件系统上并且只将它们的路径保存在数据库中是否是好的设计。

标签: sql-server file tsql filesize


【解决方案1】:

如果安全不是一个大问题并且您可以在您的 sql 实例上启用 xp_cmdshell,您可以使用命令 shell 目录列表来获取信息。例如

Declare @Dir VARCHAR(256)
DECLARE @CMD VARCHAR(256)
SET @Dir = 'C:\myImageFolder\'
SET @CMD = 'DIR "'+@DIR+'" /A /S'

CREATE TABLE #tmp 
    (returnval NVARCHAR(500), rownum INT IDENTITY(1,1))

-- Populate Temp Table with the contents of the outfiles directory
    INSERT #tmp EXEC master..xp_cmdshell @cmd

-- Delete rows with no file information
    DELETE FROM #tmp WHERE returnval IS NULL
    DELETE FROM #tmp WHERE ISNUMERIC(LEFT(returnval,1))=0 AND returnval NOT LIKE '%Directory of%'
    DELETE FROM #tmp WHERE returnval LIKE '%<DIR>          .%'

-- Separate the output into it's proper columns
    SELECT 
        rownum,
        (SELECT TOP 1 REPLACE(returnVal, ' Directory of ','') FROM #tmp t2 WHERE t2.rownum < t.rownum AND t2.returnval LIKE ' Directory of%' ORDER BY t2.rownum DESC) Directory,
        CAST(LEFT(returnval,10) AS DATETIME) AS file_date,
        CASE WHEN SUBSTRING(returnval,22,17) LIKE '%<DIR>%' THEN NULL ELSE CAST(REPLACE(SUBSTRING(returnval,22,17),',','') AS NUMERIC) END AS 'size(bytes)',
        RIGHT(RTRIM([returnval]),LEN(RTRIM([returnval]))-39) AS [file_name],
        CASE WHEN SUBSTRING(returnval,22,17) LIKE '%<DIR>%' THEN 'Directory' ELSE 'File' END AS [Type],
        CASE WHEN SUBSTRING(returnval,22,17) LIKE '%<DIR>%' THEN NULL ELSE RIGHT(rtrim([returnval]), CHARINDEX('.',REVERSE(RTRIM([returnval])))) END AS extension
    FROM #tmp t
    WHERE returnval NOT LIKE '%Directory of%'

【讨论】:

  • 谢谢。 'size(bytes)' 总是返回 NULL。你注意到了吗?
  • 应该只为目录返回 null
  • 这个解决方案依赖于语言环境,我不得不像这样修改选择:SELECT convert(datetime, LEFT(returnval,17),104) AS file_date, CAST( LTRIM(RTRIM(REPLACE(SUBSTRING(returnval,20,17),' ',''))) AS bigint) AS size, SUBSTRING(returnval,37, 50) AS [file_name]
【解决方案2】:

我认为您可以使用sp_OAGetProperty。类似...

DECLARE @OLEResult INT
DECLARE @FS INT
DECLARE @FileID INT
DECLARE @Size BIGINT

-- Create an instance of the file system object
EXEC @OLEResult = sp_OACreate 'Scripting.FileSystemObject', @FS OUT
EXEC @OLEResult = sp_OAMethod @FS, 'GetFile', @FileID OUT, 'C:\Filename'
EXEC @OLEResult = sp_OAGetProperty @FileID, 'Size', @Size OUT

--@Size now holds file size

您可能需要使用sp_configure 更改“Ole 自动化程序”的配置选项

查看this link

【讨论】:

  • 谢谢@EI Ronnoco 我正在尝试这个,但我担心它可能不是我正在寻找的解决方案,因为该文件夹包含数千个图像文件。
  • 这个程序工作正常,但只适用于有限的文件......知道如何解决这个问题吗?它只是在 100 个文件之后返回 null。
【解决方案3】:

您可以创建一个 c# 函数并将其添加到您的 SQL Server 2008 数据库中,然后从 SQL 内部调用该函数。 CLR 存储过程或 CLR 函数都适用于您的方案。

Creating CLR Stored Procedures - MSDN

或者,您还可以做什么(这对我来说更有意义,但需要更多的工作)...您的程序如何上传文件? - 进入该例程,并在数据库中创建一个指示其大小和位置的条目。

【讨论】:

  • 谢谢。将图像大小和位置存储在数据库中是一个好主意,我们将在未来尝试实现它。
【解决方案4】:

完美解决方案2.0版!!

-- =============================================
-- Author:      Carlos Dominguez (krlosnando@gmail.com)
-- Create date: July 07th 2017
-- Description: Scan folders and files Size
-- Example: EXEC [dbo].[spScanFolder] 'C:\Users\Public'
-- =============================================
CREATE PROCEDURE [dbo].[spScanFolder] 
(
    @FolderToScan VARCHAR(1000)
)
AS
BEGIN
    ---------------------------------------------------------------------------------------------
    -- Variable declaration
    ---------------------------------------------------------------------------------------------
    DECLARE @CurrentDir VARCHAR(400)
    DECLARE @Line VARCHAR(400)
    DECLARE @Command VARCHAR(400)
    DECLARE @Counter int

    DECLARE @1MB DECIMAL
    SET @1MB = 1024 * 1024

    DECLARE @1KB DECIMAL
    SET @1KB = 1024 

    ---------------------------------------------------------------------------------------------
    -- DROP temp tables
    ---------------------------------------------------------------------------------------------
    IF OBJECT_ID(N'tempdb..#tableTempDirs') IS NOT NULL BEGIN  DROP TABLE #tableTempDirs END
    IF OBJECT_ID(N'tempdb..#tableTempOutput') IS NOT NULL BEGIN  DROP TABLE #tableTempOutput END
    IF OBJECT_ID(N'tempdb..#tableTempResult') IS NOT NULL BEGIN  DROP TABLE #tableTempResult END
    IF OBJECT_ID(N'tempdb..#tableTempFilePaths') IS NOT NULL BEGIN  DROP TABLE #tableTempFilePaths END
    IF OBJECT_ID(N'tempdb..#tableTempFileInfo') IS NOT NULL BEGIN  DROP TABLE #tableTempFileInfo END

    ---------------------------------------------------------------------------------------------
    -- Temp tables creation
    ---------------------------------------------------------------------------------------------
    CREATE TABLE #tableTempDirs (DIRID int identity(1,1), directory varchar(400))
    CREATE TABLE #tableTempOutput (line varchar(400))
    CREATE TABLE #tableTempResult (Directory varchar(400), FilePath VARCHAR(400), SizeInMB DECIMAL(13,2), SizeInKB DECIMAL(13,2))
    CREATE TABLE #tableTempFilePaths (Files VARCHAR(500))
    CREATE TABLE #tableTempFileInfo (FilePath VARCHAR(500), FileSize VARCHAR(100))

    ---------------------------------------------------------------------------------------------
    -- Call xp_cmdshell
    ---------------------------------------------------------------------------------------------    
    SET @Command = 'dir "'+ @FolderToScan +'" /S/O/B/A:D'
    INSERT INTO #tableTempDirs EXEC xp_cmdshell @Command
    INSERT INTO #tableTempDirs SELECT @FolderToScan
    DELETE FROM #tableTempDirs WHERE Directory is null   

    ---------------------------------------------------------------------------------------------
    -- Remove text to extract file information from command result "05/27/2017  12:26 PM 5,208 rulog.txt"
    ---------------------------------------------------------------------------------------------      
    SET @Counter = (select count(*) from #tableTempDirs)
    WHILE @Counter <> 0
    BEGIN
        DECLARE @filesize INT
        SET @CurrentDir = (SELECT directory FROM #tableTempDirs WHERE DIRID = @Counter)
        SET @Command = 'dir "' + @CurrentDir +'"'

        -- Clear the table
        TRUNCATE TABLE #tableTempFilePaths

        -- Get files from current directory
        INSERT INTO #tableTempFilePaths
        EXEC MASTER..XP_CMDSHELL @Command 

        --delete all directories
        DELETE #tableTempFilePaths WHERE Files LIKE '%<dir>%'

        --delete all informational messages
        DELETE #tableTempFilePaths WHERE Files LIKE ' %'

        --delete the null values
        DELETE #tableTempFilePaths WHERE Files IS NULL

        --delete files without date "05/27/2017  12:26 PM 5,208 rulog.txt"
        --Fix error: Invalid length parameter passed to the right function.
        DELETE #tableTempFilePaths WHERE LEN(files) < 20

        --get rid of dateinfo
        UPDATE #tableTempFilePaths SET files = RIGHT(files,(LEN(files)-20))

        --get rid of leading spaces
        UPDATE #tableTempFilePaths SET files =LTRIM(files)

        --split data into size and filename and clear the table
        TRUNCATE TABLE #tableTempFileInfo;

        -- Store the FileName & Size
        INSERT INTO #tableTempFileInfo
        SELECT  
            RIGHT(files,LEN(files) -PATINDEX('% %',files)) AS FilePath,
            LEFT(files,PATINDEX('% %',files)) AS FileSize
        FROM
            #tableTempFilePaths

        --Remove the commas
        UPDATE #tableTempFileInfo
        SET FileSize = REPLACE(FileSize, ',','')

        --------------------------------------------------------------
        -- Store the results in the output table
        -- Fix Error: conveting varchar to decimal
        --------------------------------------------------------------
        INSERT INTO #tableTempResult--(FilePath, SizeInMB, SizeInKB)
        SELECT  
            @CurrentDir,
            FilePath,
            CASE FileSize
                WHEN 'File ' THEN 0
                ELSE CAST(CAST(FileSize AS DECIMAL(13,2))/ @1MB AS DECIMAL(13,2))
            END,
            CASE FileSize
                WHEN 'File ' THEN 0
                ELSE CAST(CAST(FileSize AS DECIMAL(13,2))/ @1KB AS DECIMAL(13,2))
            END
        FROM    
            #tableTempFileInfo

        Set @Counter = @Counter -1
    END

    -- Remove null directories
    DELETE FROM #tableTempResult WHERE Directory is null       

    ----------------------------------------------
    -- Show result
    ----------------------------------------------           
    SELECT * FROM  #tableTempResult 

    ----------------------------------------------
    -- DROP temp tables
    ----------------------------------------------           
    IF OBJECT_ID(N'tempdb..#tableTempDirs') IS NOT NULL BEGIN  DROP TABLE #tableTempDirs END
    IF OBJECT_ID(N'tempdb..#tableTempOutput') IS NOT NULL BEGIN  DROP TABLE #tableTempOutput END
    IF OBJECT_ID(N'tempdb..#tableTempResult') IS NOT NULL BEGIN  DROP TABLE #tableTempResult END
    IF OBJECT_ID(N'tempdb..#tableTempFilePaths') IS NOT NULL BEGIN  DROP TABLE #tableTempFilePaths END
    IF OBJECT_ID(N'tempdb..#tableTempFileInfo') IS NOT NULL BEGIN  DROP TABLE #tableTempFileInfo END
END

【讨论】:

    【解决方案5】:

    检查这个解决方案:

    ALTER  PROCEDURE   [dbo].[GetListOfFileWithSize]  
    (
        @Dir    VARCHAR(1000)
    )
    AS
    ---------------------------------------------------------------------------------------------
    -- Variable decleration
    ---------------------------------------------------------------------------------------------
        declare @curdir nvarchar(400)
        declare @line varchar(400)
        declare @command varchar(400)
        declare @counter int
    
        DECLARE @1MB    DECIMAL
        SET     @1MB = 1024 * 1024
    
        DECLARE @1KB    DECIMAL
        SET     @1KB = 1024 
    
    ---------------------------------------------------------------------------------------------
    -- Temp tables creation
    ---------------------------------------------------------------------------------------------
    CREATE TABLE #dirs (DIRID int identity(1,1), directory varchar(400))
    CREATE TABLE #tempoutput (line varchar(400))
    CREATE TABLE output (Directory varchar(400), FilePath VARCHAR(400), SizeInMB DECIMAL(13,2), SizeInKB DECIMAL(13,2))
    
    CREATE TABLE #tempFilePaths (Files VARCHAR(500))
    CREATE TABLE #tempFileInformation (FilePath VARCHAR(500), FileSize VARCHAR(100))
    
    ---------------------------------------------------------------------------------------------
    -- Call xp_cmdshell
    ---------------------------------------------------------------------------------------------    
    
         SET @command = 'dir "'+ @Dir +'" /S/O/B/A:D'
         INSERT INTO #dirs exec xp_cmdshell @command
         INSERT INTO #dirs SELECT @Dir
         SET @counter = (select count(*) from #dirs)
    
    ---------------------------------------------------------------------------------------------
    -- Process the return data
    ---------------------------------------------------------------------------------------------      
    
            WHILE @Counter <> 0
              BEGIN
                DECLARE @filesize INT
                SET @curdir = (SELECT directory FROM #dirs WHERE DIRID = @counter)
                SET @command = 'dir "' + @curdir +'"'
                ------------------------------------------------------------------------------------------
                    -- Clear the table
                    DELETE FROM #tempFilePaths
    
    
                    INSERT INTO #tempFilePaths
                    EXEC MASTER..XP_CMDSHELL @command 
    
                    --delete all directories
                    DELETE #tempFilePaths WHERE Files LIKE '%<dir>%'
    
                    --delete all informational messages
                    DELETE #tempFilePaths WHERE Files LIKE ' %'
    
                    --delete the null values
                    DELETE #tempFilePaths WHERE Files IS NULL
    
                    --get rid of dateinfo
                    UPDATE #tempFilePaths SET files =RIGHT(files,(LEN(files)-20))
    
                    --get rid of leading spaces
                    UPDATE #tempFilePaths SET files =LTRIM(files)
    
                    --split data into size and filename
                    ----------------------------------------------------------
                    -- Clear the table
                    DELETE FROM #tempFileInformation;
    
                    -- Store the FileName & Size
                    INSERT INTO #tempFileInformation
                    SELECT  
                            RIGHT(files,LEN(files) -PATINDEX('% %',files)) AS FilePath,
                            LEFT(files,PATINDEX('% %',files)) AS FileSize
                    FROM    #tempFilePaths
    
                    --------------------------------
                    --  Remove the commas
                    UPDATE  #tempFileInformation
                    SET FileSize = REPLACE(FileSize, ',','')
    
                    --------------------------------
                    --  Remove the white space
                    UPDATE  #tempFileInformation
                    SET FileSize = REPLACE(FileSize, char(160) , '')
    
                    --------------------------------------------------------------
                    -- Store the results in the output table
                    --------------------------------------------------------------
    
                    INSERT INTO output--(FilePath, SizeInMB, SizeInKB)
                    SELECT  
                            @curdir,
                            FilePath,
                            CAST(CAST(FileSize AS DECIMAL(13,2))/ @1MB AS DECIMAL(13,2)),
                            CAST(CAST(FileSize AS DECIMAL(13,2))/ @1KB AS DECIMAL(13,2))
                    FROM    #tempFileInformation
    
                --------------------------------------------------------------------------------------------
    
    
                Set @counter = @counter -1
               END
    
    
        DELETE FROM OUTPUT WHERE Directory is null       
    ----------------------------------------------
    -- DROP temp tables
    ----------------------------------------------           
    DROP TABLE #Tempoutput  
    DROP TABLE #dirs  
    DROP TABLE #tempFilePaths  
    DROP TABLE #tempFileInformation  
    --DROP TABLE #tempfinal  
    
    
    SELECT  * FROM  OutPut
    DROP TABLE output 
    

    而且 伙计们,它有效!!!

    【讨论】:

    • 我不确定使用 xp_cmdshell 的任何东西都可以称为“完美”
    • 我不确定使用 WHILE 循环的任何东西都可以称为“完美”
    • 对我不起作用。在第 94 行出现转换错误( CAST(CAST(FileSize AS DECIMAL(13,2))/@1MB AS DECIMAL(13,2)), )。似乎我服务器上的 DIR 不同。
    • Msg 8114, Level 16, State 5, Procedure GetListOfFileWithSize, Line 97 Error converting data type varchar to numeric.
    • @YaqubAhmad,查看line no:85 and 90。如果您将脚本复制粘贴到 SSMS。这没有声明我相信这应该是#tempfileinformation
    【解决方案6】:

    这是一个使用 xp_cmdshell 运行 powershell 的解决方案,它返回可以解析的 xml,因为为什么不可以。

    set nocount on;
    
    declare @path varchar(1000), @cmd varchar(2000);
    
    -- File path
    set @path = 'c:\temp';
    -- Powershell command to get a directory listing and output in to its clixml for parsing
    set @cmd = 'powershell.exe -noprofile -outputformat xml -command "get-childitem -path ''' + @path + ''' -File"';
    
    -- output table for xp_cmdshell
    create table #cmdOutput ( [output] varchar(max));
    
    -- run powershell command and collect output
    insert into #cmdOutput ( output ) exec sys.xp_cmdshell @cmd;
    
    -- remove some values for paring xml, agg to a single string, cast as xml
    with cte as ( select cast(string_agg(
                              iif(a.output like '%xmlns%', replace(a.output, 'xmlns="http://schemas.microsoft.com/powershell/2004/04"', ''), a.output), ''
                              ) as xml) myDoc from #cmdOutput a where a.output <> '#< CLIXML'
                )
    -- select data out of xml 
    select b.fileObj.value('(./Props/S)[1]', 'varchar(1000)') [Name]
      , b.fileObj.value('(./Props/I64)[1]', 'bigint') [Length]
      , b.fileObj.value('(./Props/S)[2]', 'varchar(1000)') DirectoryName
      , b.fileObj.value('(./Props/B)[1]', 'bit') IsReadOnly
      , b.fileObj.value('(./Props/B)[2]', 'bit') [Exists]
      , b.fileObj.value('(./Props/S)[3]', 'varchar(1000)') FullName
      , b.fileObj.value('(./Props/S)[4]', 'varchar(1000)') Extension
      , b.fileObj.value('(./Props/DT)[1]', 'datetime2') CreationTime
      , b.fileObj.value('(./Props/DT)[3]', 'datetime2') LastAccessTime
      , b.fileObj.value('(./Props/DT)[5]', 'datetime2') LastWriteTime
    from cte a
    cross apply a.myDoc.nodes('/Objs/Obj') as b(fileObj)
    where b.fileObj.value('(./Props/S)[1]', 'varchar(1000)') is not null
    
    
    -- clean it up
    drop table #cmdOutput;
    

    【讨论】:

      猜你喜欢
      • 2020-07-26
      • 1970-01-01
      • 2014-04-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-01
      • 2022-08-08
      • 1970-01-01
      相关资源
      最近更新 更多