[英]Two computers trying to access a excel file in a third computer (server) to write. Problems with the method
我已經為朋友制作了POS系統。 POS系統是excel工作簿,可在帶有觸摸屏的台式計算機中運行。 對於每次銷售,它都會訪問服務器中名為product.xlms的文件,以更新產品數量。
當第二個終端嘗試同時訪問(寫入)服務器中的同一文件時,就會出現問題,因為如果第一台計算機每天都在使用該文件,則第二台計算機將以只讀模式打開它。
我以為我繞過了我在stackoverflow上發現的以下函數:
Function IsWorkBookOpen(filename As String)
Dim ff As Long, ErrNo As Long
On Error Resume Next
ff = FreeFile()
Open filename For Input Lock Read As #ff
Close ff
ErrNo = Err
On Error GoTo 0
Select Case ErrNo
Case 0: IsWorkBookOpen = False
Case 70: IsWorkBookOpen = True
Case Else: Error ErrNo
End Select
End Function
此函數打開文件以檢查是否正在使用該文件,並關閉返回錯誤。 根據錯誤號,我們能夠知道它是否打開。
然后,每當我要打開文件時都調用該函數,它將等待一秒鍾,然后重試該文件是否已打開:
Check:
Ret = IsWorkBookOpen("PATH\products.xlsx")
If Ret = True Then
Application.Wait Now() + TimeSerial(0, 0, 1)
GoTo Check
End If
Workbooks.Open("PATH\products.xlsx")
但是,它對我這樣不起作用,因為交互非常快,並且顯示這種交互的最佳方法是解釋有問題的情況:
終端1檢查文件是否打開:打開文件,關閉,沒有錯誤,然后變量= False。 然后(第二次)打開要使用的文件。
如果終端2剛在終端1第一次關閉文件時打開文件BUM,我有一個問題,因為它會認為未使用(那是對的!在那段時間內實際上未使用),然后繼續打開它再次(實際上是在只讀模式下使用原因)。
希望很明確,如果沒有,我會盡力澄清。 有什么建議,解決方法嗎?
謝謝
建議:不要將Excel用於多用戶方案。 實際上,除了電子表格外,請勿將Excel用於其他任何東西。 這是一個很棒的電子表格應用程序,當被迫做其他事情時效果不佳。 數據庫應用程序,POS系統等不是其設計目的。 方釘,圓孔等等。
如果您熱衷於使用MS Office,為什么不為此使用Access?
創建一個在每個觸摸屏終端上運行的前端應用程序,然后將其連接到集中存儲的后端數據庫。 這將在將來為您節省很多麻煩。
我應該指出,我同意馬克·巴特勒的觀點; 通過使用Excel作為“數據庫”,您肯定會很難做到這一點。 但是,已經完成了,所以這就是我會嘗試的...
Sub YourSub()
Dim WB As Workbook
Dim YourFile As String
'Note the ~$ in front of the file name
YourFile = "C:\Users\USERNAME\Documents\~$Book1.xlsx"
Do While IsFileOpen(YourFile)
Loop
'File should be available to you now
Set WB = Workbooks.Open(Replace(YourFile, "~$", ""), ReadOnly:=False, Notify:=False)
End Sub
Function IsFileOpen(fPath As String) As Boolean
Dim FSO As Object 'FileSystemObject
Set FSO = CreateObject("Scripting.FileSystemObject")
If FSO.FileExists(fPath) Then
IsFileOpen = True
End If
End Function
該代碼背后的邏輯是,當另一個用戶打開一個Excel文件時,Excel將創建一個帶有〜$前綴的“鎖定文件”。 此代碼檢查該鎖定文件是否存在,如果不存在,則打開該文件。 這將比您發布的解決方法效率更高,因為該解決方法每次需要檢查文件是否正在使用時都必須打開整個文件(現在不是什么大問題,但是當您有成千上萬的數據行時,它就變得非常重要了。更大的交易)。
但是,這里有一個很大的警告,在關閉文件后,有時不會刪除鎖定文件。 在這種情況下,由於鎖定文件將永久存在,因此您的應用程序將進入無限循環。 避免這種情況的一種方法是添加某種計數器,以便一旦循環達到您設置的最大計數(例如100000),它將以任何方式打開文件並以這種方式檢查只讀。
另一種選擇是在打開Excel文件之前立即用您的代碼創建一個文本文件。 然后,當您使用完Excel時,您將刪除文本文件(基本上是我前面提到的“鎖定文件”的模仿)。 這仍然會很有效,並且不會依賴Excel鎖定文件。 為此,請嘗試以下代碼:
Sub YourSub()
Dim WB As Workbook
Dim CheckFile As String
Dim YourFile As String
CheckFile = "C:\Users\USERNAME\Documents\OpenCheck.txt"
Do While IsFileOpen(CheckFile)
Loop
'File should be available to you now
YourFile = "C:\Users\USERNAME\Documents\YourFile.xlsx"
Set WB = Workbooks.Open(YourFile, ReadOnly:=False, Notify:=False)
'And then when you're done with the excel file
WB.Close SaveChanges:=True
Kill CheckFile
End Sub
Function IsFileOpen(fPath As String) As Boolean
Dim FSO As Object ' FileSystemObject
Dim TS As Object ' TextStream
Set FSO = CreateObject("Scripting.FileSystemObject")
If FSO.FileExists(fPath) Then
IsFileOpen = True
Else
On Error GoTo AlreadyCreated
Set TS = FSO.CreateTextFile(Filename:=fPath, overwrite:=False)
TS.Close
End If
ExitFunc:
On Error GoTo 0
Exit Function
AlreadyCreated:
IsFileOpen = True
Resume ExitFunc
End Function
顯然,該文本文件必須保存到您的服務器中。 我目前沒有任何方法可以測試這種方法,但據我所知它應該能很好地工作。
問題是, Worksbooks.Open
將打開工作簿。 您在IsWorkbookOpen
函數中打開該工作簿,然后再次寫入實際值。 您必須將這兩件事放在一起。
嘗試通過Workbooks.Open ReadOnly:=False, Notify:=False
來打開它,這將引發類似於您的函數的錯誤,您可以檢查該錯誤。 喜歡:
Dim wkb As Workbook
On Error Resume Next
Do
'Clear existing (old) Error-Code
Err.Clear
'Try to open
Open "Path/test.xlsx" For Input Lock Read Write As #ff
Set wkb = ActiveWorkbook
If Not Err.Number = 0 Then
'Workbook is opened from another client, put Wait-code here
End If
'If Workbook is open on this client, Error-code is 0 and the loop exits
Loop Until Err.Number = 0
'Write the Values, use wkb
On Error GoTo Errorhandler 'Its always good to catch Errors in an Errorhandler
'Write the Values, use wkb
我無法測試錯誤編號,因此您必須自己檢查一下。
我找到了解決方法。 我將先打開文件,然后檢查是否為ReadOnly模式,而不是先檢查然后再打開,並使用以下代碼:
Dim wkb As Workbook
Check:
'disable alerts to skip the excel message "file been used, Open Read Only?"
Application.DisplayAlerts = False
Set wkb = Workbooks.Open((Config.Range("O2").Value) & "\clientdb.xlsx", Notify:=False, ReadOnly:=False)
Application.DisplayAlerts = True
If wkb.ReadOnly Then
wkb.Close
'Wait code here
Application.Wait Now() + TimeSerial(0, 0, 1)
GoTo Check
End If
如果為ReadOnly,則表示已在某處打開,則它將等待1秒鍾,然后重試,直到打開啟用寫操作的文件為止。
發布答案的用戶Reen Winter值得贊揚,因為他幫助我思考。
謝謝大家的答復。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.