2013-08-27 108 views
0

我在寫一個VB.NET webforms站點,其中的一個頁面必須將一列文件加載到列表框中。它需要將所有PDF和TIF文件加載到數據庫中沒有條目的目錄中。目前我正在使用以下代碼成功完成此操作。基本上,我查詢數據庫以獲取文件名條目的數組列表,然後遍歷目錄中的每個文件,根據數組列表中的每個條目檢查其名稱,並且如果其名稱不在數組列表中,則將其添加到列表以綁定到列表框:從VB.NET中的另一個數組列表中刪除ArrayList中的項目

Dim category As String = "RFQ" 

    'Initialize database connection variables 
    Dim sql As String 
    Dim query As System.Data.SqlClient.SqlCommand 
    Dim result As System.Data.SqlClient.SqlDataReader 

    'Load document list from database 
    Dim savedfiles As New ArrayList 
    database.Open() 'Open connection to database 
    sql = "SELECT filename FROM fileheaders WHERE [category] = '" & category & "'" 'SQL query to read file header information 
    query = New System.Data.SqlClient.SqlCommand(sql, database) 'Create query to send to database 
    result = query.ExecuteReader() 'Execute query 
    While result.Read() 
     savedfiles.Add(row(result, "filename")) 
    End While 
    result.Close() 
    dbDocscan.Close() 


    'The following code section pulls all files from the current file directory. 
    Dim filelist = New ArrayList 
    Dim dir As New System.IO.DirectoryInfo(dirName) 'Get directory information 
    Dim files As System.IO.FileInfo() = dir.GetFiles() 'Get all files in directory 
    Dim file As System.IO.FileInfo 
    Dim i As Integer = 0 
    For Each file In files 
     If ((file.Extension Like ".pdf") Or (file.Extension Like ".tif")) And Not inArray(savedfiles, file.Name) Then 
      filelist.Add(file.Name) 'Add .pdf and .tif files to list of documents 
     End If 
    Next 

    filelist.TrimToSize() 
    eltFilelist.DataSource = filelist 
    eltFilelist.DataBind() 'Bind document list to listbox 

然後inArray功能代碼:

Function inArray(arr As ArrayList, str As String) As Boolean 
    For Each item In arr 
     If TypeOf (item) Is String Then 
      If str = item Then 
       Return True 
       Exit Function 
      End If 
     End If 
    Next 
    Return False 
End Function 

這裏的問題:雖然它的工作原理,它似乎非常低效的。目錄中有大約27,000個文件,數據庫中大約有26,000個文件入口。因此,我正在檢查27,000個文件名中的每一個,並列出26,000個名稱。如果不將它變成組合問題,那就是數以百萬計的字符串匹配語句。有沒有更有效的方法去解決這個問題?

+0

這是一個很好的問題,但我會說這是更適合[代碼審查(HTTP://codereview.stackexchange。 com /) –

+0

我已經得到了答案,所以現在不用移動它。但CodeReview的目的與StackOverflow的目的有什麼不同? – user1978952

+0

我想說,區分這兩者的最簡單方法是,CodeReview適用於已經可以運行(但可能需要改進)的代碼,而StackOverflow適用於尚未運行的代碼:)也就是說,可能會簡單化一點,但整齊地總結起來。我幾乎不推薦它,因爲這種問題屬於StackOverflow中仍然有效的灰色區域,但它正在擴展它。 –

回答

0

你可以使用SQL參數來避免類別字符串的問題(例如,如果它有一個撇號,連接的查詢字符串將被打破),只獲取目錄中有你感興趣的擴展名的文件在,你可以使用LINQ獲得以簡單的方式丟失的文件:

Imports System.Data.SqlClient 
Imports System.IO 
Module Module1 
    Function GetMissingFiles(sourceDirectory As String, category As String) As List(Of String) 
     Dim missingFiles As New List(Of String) 

     Dim filesInDatabase As New List(Of String) 

     ' Query the database for the files in the given category' 
     Using conn As New SqlConnection("connection string here") 
      conn.Open() 
      Dim sqlCmd As String = "SELECT filename FROM fileheaders WHERE [category] = @category" 
      Dim query As New System.Data.SqlClient.SqlCommand(sqlCmd, conn) 
      'TODO: change .SqlDbType to what it is in the database.' 
      query.Parameters.Add(New SqlParameter With {.ParameterName = "@category", .SqlDbType = SqlDbType.NVarChar, .Value = category}) 

      Dim rdr As SqlDataReader = query.ExecuteReader() 

      While rdr.Read() 
       filesInDatabase.Add(rdr.GetString(0)) 
      End While 

      conn.Close() 

     End Using 

     'TODO: it could be that filesInDatabase.Count = 0 is valid. Adjust if required.' 
     If filesInDatabase.Count > 0 Then 
      ' Get the existing files from the given directory. 

      ' the extensions we are going to consider 
      Dim extensions() As String = {"pdf", "tif"} 

      Dim existingFiles As New List(Of String) 

      ' get all the filenames (without the path) to consider' 
      For Each extn In extensions 
       existingFiles.AddRange(Directory.GetFiles(sourceDirectory, "*." & extn).ToList().Select(Function(p) Path.GetFileName(p))) 
      Next 

      missingFiles = existingFiles.Except(filesInDatabase).ToList() 

     End If 

     Return missingFiles 

    End Function 
    Sub Whatever() 
     Dim myMissingFiles As List(Of String) 
     Try 
      myMissingFiles = GetMissingFiles("C:\temp", "RFQ") 
     Catch ex As Exception 
      ' Inform user it went wrong.' 
     End Try 

     If myMissingFiles IsNot Nothing AndAlso myMissingFiles.Count > 0 Then 
      eltFilelist.DataSource = myMissingFiles 
      eltFilelist.DataBind() 
     End If 

    End Sub 

End Module 
+0

感謝您的建議。我對VB.NET相當陌生,並且我不知道列表類。這應該是非常有用的。 只是一個關於SQL參數的附註,我只是用一個變量去簡單的路由,因爲變量是由腳本定義的,沒有用戶輸入,所以沒有真正的衝突空間。不過感謝您的支持。 我會嘗試一下你的List.Except方法,確保我可以讓它工作,然後回報。 – user1978952

+0

只是一個更新:我將savedfiles設置爲List(Of String)並放入數據庫的所有文件名。我將filelist設置爲List(Of String)並放入目錄中的所有文件名。然後我將missingfile設置爲List(Of String)並將其設置爲filelist.Except(savedfiles).toList(),並將其用作我的listbox.DataSource。完美工作。再次感謝提示! – user1978952

+0

@ user1978952還有一個提示:如果您正在向數據庫進行大量查詢並且類別名稱的長度可能變化很大,那麼您還應該將SqlParameter的.Length參數設置爲在數據庫中設置的值。 SQL Server在執行查詢之前使自己成爲「計劃」,並且如果它看到參數的不同長度,則會爲每個長度制定一個新計劃。無論如何,使用SQL Server 2008 R2進行IME。 –

0

不使用ArrayList,而是使用Dictionary或HashTable來保存查詢中的文件名。

您的inArray函數爲每個找到的文件執行O(n)表掃描,這很慢。

字典和HashTable都有一個Contains成員,它將以顯着更快的速度搜索您的文件名。