0

我正在创建一个从数据库中获取文件数据的程序。要求是文件在存在“IMAGE_00001.JPG”、“IMAGE_00002.JPG”、...

由于性能问题,我正在并行加载数据,但在创建文件时遇到了问题。

For i As Long = 1 To maxSeqNr
    DIDir = New DirectoryInfo(currDir)
    If DIDir.GetFiles(currFilePrefix & Microsoft.VisualBasic.Right(maxSeqNrLeadingZeros & CStr(i), Len(maxSeqNr.ToString)) & ".*", SearchOption.TopDirectoryOnly).Length = 0 Then
        sRetValue = currFilePrefix & Microsoft.VisualBasic.Right(maxSeqNrLeadingZeros & CStr(i), Len(maxSeqNr.ToString)) & currFileExtention

        Dim oSW As StreamWriter
        oSW = New StreamWriter(currDir & sRetValue)
        oSW.WriteLine("")
        oSW.Close()
        oSW.Dispose()
        oSW = Nothing

        Exit For
    End If
Next

问题是有时 2 个线程正在运行同一行代码。我添加了日志记录,我发现了这个:

Check for 'IMAGE_00001.JPG' ; Directory: ''
Check for 'IMAGE_00001.JPG' ; Directory: ''
Check for 'IMAGE_00002.JPG' ; Directory: 'IMAGE_00001.JPG'
Check for 'IMAGE_00003.JPG' ; Directory: 'IMAGE_00001.JPG,IMAGE_00002.JPG'

在我执行 Exists 语句之前是否有可能“锁定”工作目录。创建文件后“释放”?其他线程应该等到他们可以“锁定”目录。

4

3 回答 3

1

您应该生成要使用的名称,然后尝试FileStream使用该名称创建对象。使用接受FileMode参数的合适构造函数(例如this)并指定CreateNew.

如果抛出一个 IOException,则捕获一个IOException并生成一个新名称。

否则,您将面临一种经典的比赛形式。您是选择组合原始策略(检查是否存在,然后尝试打开文件)还是只是尝试创建文件并期待异常,这取决于您。

成功打开FileStream后,您可以将其传递给StreamWriter接受Stream参数的构造函数,然后从那里继续。

于 2013-08-29T14:15:21.793 回答
0

我会使用 syn / lock 策略:当您的线程想要写入文件时锁定并停止所有其他线程直到完成,然后释放锁定。 http://msdn.microsoft.com/de-de/library/vstudio/ms173179.aspx

或者,使用非阻塞整数作为计数器,这样可以保证文件是唯一的,但它可能会弄乱您的“编号”要求。 http://msdn.microsoft.com/en-us/library/system.threading.interlocked.aspx

于 2013-08-29T14:12:03.910 回答
0

如果您需要做的就是通过 生成空白文件IMG_00000.jpg,如果文件不存在IMG_XXXXX.jpg,您可以使用循环来创建文件。Parallel.For这将确保两个不同的线程不会检查两个数字,而是将数字在线程之间分割出来。

虽然我不知道这实际上会更快,特别是如果您必须在目录中搜索具有与图像名称匹配的任何扩展名的文件:

Dim width = Len(maxSeqNr.ToString)
Dim DIDir = New DirectoryInfo(currDir)
Parallel.For(1L, maxSeqNr, Sub(i)
    Dim pattern = currFilePrefix & Microsoft.VisualBasic.Right(maxSeqNrLeadingZeros & CStr(i), Len(maxSeqNr.ToString)) & ".*"
    If Not DDir.EnumerateFiles(pattern, SearchOption.TopDirectoryOnly).Any Then
        Dim fn = currFilePrefix & Microsoft.VisualBasic.Right(maxSeqNrLeadingZeros & CStr(i), width) & currFileExtention
        File.Create(fn).Close
    End If
End Sub)

如果您正在搜索的文件夹很小,这可能会更好(假设您实际上关心与模式匹配的任何文件名):

' My VB.Net is horrible
Dim width = Len(maxSeqNr.ToString)
Dim files = Directory.GetFiles(currDir)
Parallel.For(1L, maxSeqNr, Sub(i)
    Dim pattern = currFilePrefix & Microsoft.VisualBasic.Right(maxSeqNrLeadingZeros & CStr(i), Len(maxSeqNr.ToString))
    ' consider case-insenstive matching
    If Not files.Any(Function(fn) Path.GetFileNameWithoutExtension(fn) = pattern) Then
        Dim fn = currFilePrefix & Microsoft.VisualBasic.Right(maxSeqNrLeadingZeros & CStr(i), width) & currFileExtention
        File.Create(fn).Close
    End If
End Sub)

或者,如果您真正需要的只是创建一个不存在的文件,您只需继续触摸它们:

Parallel.For(1L, maxSeqNr, Sub(i)
    Dim fn = currFilePrefix & Microsoft.VisualBasic.Right(maxSeqNrLeadingZeros & CStr(i), width) & currFileExtention
    File.Open(fn, FileMode.OpenOrCreate).Close
End Sub)
于 2013-08-29T14:29:02.767 回答