Yesterday Is History. Today Is A Gift. Tomorrow Is Mystery
In een bestand, niet naar....
Yesterday Is History. Today Is A Gift. Tomorrow Is Mystery
Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'
Windows heeft tenslotte ook een "zoeken in" functie
[ Voor 45% gewijzigd door KO op 02-10-2003 10:17 ]
Yesterday Is History. Today Is A Gift. Tomorrow Is Mystery
Wat ik alleen maar wil zeggen is dat er (zonder dat je gebruik gaat maken van caching oid) geen snellere manier is dan degene die je opnoemt. Om te kijken of een woordje in een bestand zit zul je de computer elk woordtje in het bestand moeten laten controleren. Je kunt het natuurlijk wel ietsje versnellen door wat grotere blokken in te lezen dan alleen een regel, maar in principe komt het dan nog steeds op hetzelfde neer. Of het nu in je eigen programma gebeurt of doordat je een API call aanroept.
Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'
Als het in VBA zit, zal het met VB toch ook wel kunnen. Kijk eens naar de hele thread, en zie ergens Application.FileSearch staan. Dit is wat het daar in feite doet.
1) Open een bestand binair
2) Vul een string met String(Lof(bestand),chr(0))
3) Get die string
4) If instr(myStr,"zoek")>0 then gevonden
5) Close bestand...
Ik zal zometeen effe een voorbeeldje in elkaar flansen...
/edit/
Bij deze dus :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| Public Function FindStringInFile(strFile As String, strFind As String, Optional iCompareMethod As VbCompareMethod = vbTextCompare) As Long Dim FF As Integer Dim strTMP As String Dim lRes As Long lRes = -1 'Initialiseer return waarde If Len(Dir(strFile)) > 0 Then 'Bestaat het bestand? FF = FreeFile 'Vraag een vrije filehandle aan Open strFile For Binary As #FF strTMP = String(LOF(FF), Chr(0)) 'Initialiseer temp string op lengte van bestand met 0-en Get #FF, , strTMP 'Lees het hele bestand in de string Close #FF lRes = InStr(1, strTMP, strFind, iCompareMethod) 'Zoek naar het zoekwoord End If FindStringInFile = lRes 'Geef resultaat terug End Function |
Geeft eerste positie terug van plaats van gevonden keyword, -1 als bestand niet bestaat, 0 als niet gevonden. Dus als het resultaat > 0 dan komt het zoekwoord voor...
Aanroep voorbeeldje:
1
| Debug.Print FindStringInFile("C:\MijnMap\MijnSubmap\Mijnbestand.doc", "zoekdit") |
Overigens is er een 3e optionele parameter om aan te geven HOE je wil zoeken:
• Binary compare = Case sensitive
• Text compare = Case in-sensitive
That's it... Voorgekauwd en wel
Enkele kanttekeningen:
• Pas op met grote bestanden (je leest ze compleet in het geheugen in!). Is op te lossen door in blokken van (zeg) 1 meg te lezen
• Errorhandling mag je zelf doen
• Binaire bestanden, in tegenstelling tot ascii-files, willen nog wel eens unicode strings bevatten. In dat geval moet je na iedere char in je string een nul-char toevoegen. Wellicht dat je dan alsnog gewoon vindt wat je zoekt.
[ Voor 102% gewijzigd door RobIII op 02-10-2003 10:40 ]
There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.
Je eigen tweaker.me redirect
Over mij
Verwijderd
Zoals hierboven....
[ Voor 15% gewijzigd door Verwijderd op 02-10-2003 10:35 ]
+1 Bijzonder aardigRobIII schreef op 02 October 2003 @ 10:25:[...]
That's it... Voorgekauwd en welExcuses voor de layout
Yesterday Is History. Today Is A Gift. Tomorrow Is Mystery
Verwijderd
Precies, maar bij bestanden die minimaal 50mb tot 120 mb zijn en waarin meerdere keren per dag gezocht moet worden wordt jij niet vrolijk als dat ff tijd neemt....en er hangt een boze klant aan de lijn.....Verwijderd schreef op 02 oktober 2003 @ 10:46:
Dat neemt ff tijd maaar jah. Het werkt wel
Yesterday Is History. Today Is A Gift. Tomorrow Is Mystery
in zo'n geval is het misschien verstandig erbij te vertellen wat voor type bestand het is, het doel ervan en bijv. om hoeveel woorden het gaat etc.KO schreef op 02 October 2003 @ 10:54:
[...]
Precies, maar bij bestanden die minimaal 50mb tot 120 mb zijn en waarin meerdere keren per dag gezocht moet worden wordt jij niet vrolijk als dat ff tijd neemt....en er hangt een boze klant aan de lijn.....
God weet alles, want hij is lid van de Mosad. To protect your freedom i will take that away from you. Mijn drankgebruik heeft ernstig te lijden onder mijn gezondheid.
HeheKO schreef op 02 October 2003 @ 10:54:
[...]
Precies, maar bij bestanden die minimaal 50mb tot 120 mb zijn en waarin meerdere keren per dag gezocht moet worden wordt jij niet vrolijk als dat ff tijd neemt....en er hangt een boze klant aan de lijn.....
Bij deze dus een aangepaste versie die wat geheugenvriendelijker is
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
| Public Function FindStringInFile(strFile As String, strFind As String, Optional iCompareMethod As VbCompareMethod = vbTextCompare) As Long Dim FF As Integer Dim strTMP As String Dim lRes As Long Dim lSize As Long Dim lMaxBlocks As Long Dim lBlockCount As Long Dim lRest As Long Const cMaxBlockSize = &H100000 'Max blokken van 1 meg lRes = -1 'Initialiseer return waarde lBlockCount = 0 'Aantal gelezen blokken If Len(Dir(strFile)) > 0 Then 'Bestaat het bestand? FF = FreeFile 'Vraag een vrije filehandle aan Open strFile For Binary As #FF lSize = LOF(FF) 'Grootte van bestand uitlezen lMaxBlocks = lSize \ cMaxBlockSize 'Opdelen in x aantal blokken lRest = lSize - (lMaxBlocks * cMaxBlockSize) 'Hoeveel bytes blijven er over in het laatste blok? strTMP = String(cMaxBlockSize, Chr(0)) 'Initialiseer temp string op lengte van bestand met 0-en While Not EOF(FF) And (lRes < 1) And (lBlockCount < lMaxBlocks) 'Zoek door het hele bestand, of totdat we iets gevonden hebben Get #FF, , strTMP 'Lees een blok in de string lRes = InStr(1, strTMP, strFind, iCompareMethod) 'Zoek naar het zoekwoord lBlockCount = lBlockCount + 1 'Tel gelezen blok Wend If (lRest > 0) And (lRes < 1) And (Not EOF(FF)) Then 'Lees rest als nodig strTMP = String(lRest, Chr(0)) 'Vul string ter grootte van de rest Get #FF, , strTMP 'Lees laatste loodjes ;-) lRes = InStr(1, strTMP, strFind, iCompareMethod) 'Zoek naar het zoekwoord End If Close #FF End If FindStringInFile = lRes 'Geef resultaat terug End Function |
* RobIII heeft niks beters te doen
Nog meer opmerkingen:
• Binary compare is *sneller*!!
• Blokgrootte kun je wat mee spelen, kleiner of misschien groter kan betere prestaties leveren
Overigens vind ik dit 1 van de mooiere oplossingen onder (native) VB. Ik weet wel bijna zeker dat de WinAPI je voorziet van mooiere (lees: snellere) oplossingen, maar daar ben ik nu toch echt effe te druk voor. Je zult het hier effe mee moeten doen
Overigens, als je vaker zoekt is de Indexing service misschien eens iets waar je eens naar moet kijken
[ Voor 41% gewijzigd door RobIII op 02-10-2003 11:22 ]
There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.
Je eigen tweaker.me redirect
Over mij
Het (test) bestand bestaat 15000 regels en is iets van 50 mb (er zijn nog grotere bestanden)
Zelf heb ik dit gemaakt, ik heb het topic ff een uurtje niet gevolgd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| Set fi = FSO.GetFile(strInvoerBestand) FileBuffer = fi.Size Set fi = Nothing Set fIn = FSO.OpenTextFile(strInvoerBestand) b = fIn.Read(FileBuffer) If InStr(1, b, strFactuurnummer) > 0 Then ' Startpositie van het gevonden factuurnummer startPos = InStr(1, b, strFactuurnummer) ' Einde positie factuur bepalen lengteToEindPos = InStr(startPos, b, KENMERK_EINDE_FACTUUR) + Len(KENMERK_EINDE_FACTUUR) ' Dan hebben we de lengte van de factuur vanaf factuurnummer lengteFactuur = lengteToEindPos - startPos ' Dus terug zoeken naar het begin van de factuur startPosfactuur = InStrRev(b, KENMERK_BEGIN_FACTUUR, startPos) ' Dit suktje moet er nog aan geplakt worden bij de startpositie lengtePlus = startPos - startPosfactuur ' Een nieuwe start positie van de hele factuur nieuweStartPos = startPos - lengtePlus Debug.Print Mid$(b, nieuweStartPos, lengteFactuur + lengtePlus) End If |
Het zijn dus facturen waarvan een preview op het scherm getoond moet worden.
Het bestand delen in blokken is ook een goede tip
[ Voor 8% gewijzigd door KO op 02-10-2003 12:36 ]
Yesterday Is History. Today Is A Gift. Tomorrow Is Mystery
Als je een bestand in blokken "hakt", kan het zijn dat je zoektekst nét in 2 blokken ofzo valt. In dat geval zul je dus niets vinden...
Je kunt dit oplossen door te zorgen dat je blokken minimaal len(strZoek) overlappen.... Maar dat mag je zelf doen
Oh, en nogmaals: Ik gebruik dus in mijn voorbeelden Native VB, geen API's of FSO's. Beide hebben vast mooiere methodes voor je probleem...
[ Voor 19% gewijzigd door RobIII op 02-10-2003 13:02 ]
There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.
Je eigen tweaker.me redirect
Over mij
API's kan ik niet vinden, misschien is er iemand hier met nog een goede tip?RobIII schreef op 02 October 2003 @ 13:00:
Oh, en nogmaals: Ik gebruik dus in mijn voorbeelden Native VB, geen API's of FSO's. Beide hebben vast mooiere methodes voor je probleem...
Met fso kan je niet echt zoeken in een bestand.
Yesterday Is History. Today Is A Gift. Tomorrow Is Mystery
Heb me nog effe uitgeleefdKO schreef op 02 oktober 2003 @ 13:04:
[...]
API's kan ik niet vinden, misschien is er iemand hier met nog een goede tip?
Met fso kan je niet echt zoeken in een bestand.
• Mooie class van gemaakt
• Programmaatje omheen gebouwd
• In zipje gegooid (inc. source dus)
• Online gegooid voor je
De class heeft de volgende events:
• BeforeSearchStart(Path As String, FileSpecs As String, Recursive As Boolean) : Treedt op voordat er daadwerkelijk door alle directory's wordt geragd
• ChangeDirectory(Path As String) : Treedt op als er van directory gewisseld wordt
• Filematch(Path As String, FileName As String) : Treedt op als een bestand voldoet aan de filespecs
• SearchDone() : Treedt op als de zoekactie voltooid is
• ErrorOccured(ErrorNumber As Long, Description As String) : Treedt nooit op
• BeforeFileOpen(Path As String, FileName As String) : Treedt op voordat een bestand wordt geopend om naar de zoektekst te zoeken
• AfterFileClose(Path As String, FileName As String) : Treedt op als het zoeken in het bestand naar de zoektekst voltooid is
• BlockRead(CurrentBlock As Long, TotalBlocks As Long) : Treedt op als er een block wordt gelezen (handig voor progressbars etc)
Methods:
• CancelSearch : Breekt alle zoekacties af
• FindStringInFile(strPath As String, strFileName As String, strFind As String, Optional iCompareMethod As VbCompareMethod = vbTextCompare) : Ken je reeds
• Search(strRoot As String) : Doorzoekt alle mappen vanaf strRoot naar bestanden die voldoen aan FileSpecs
Properties:
• BlockSize : Zet of lees de blocksize (default 1Mb) die wordt gebruikt in FindStringInFile
• FileSpecs : Zet of lees de filespecs (default "*.*") waar de bestanden aan moeten voldoen. Filespecs voorbeelden zijn "*.htm" of "*.txt;*.doc"
• Exclude : De FileSpecs worden excluded (defaut False), dus alle bestanden die er niet aan voldoen worden doorzocht
• RecursiveSearch : De directory wordt recursief doorzocht (default True), anders alleen de directory zelf
Veel plezier ermee.... Mag ik nu gaan lunchen?
There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.
Je eigen tweaker.me redirect
Over mij
Yesterday Is History. Today Is A Gift. Tomorrow Is Mystery
daarmee kun je perfect doen wat je wilt, héééél snel woorden en complexe zoektermen zoeken IN een bestand
ook vanuit VB, VBA, whatever
[ Voor 9% gewijzigd door Yoeri op 02-10-2003 13:55 ]
Kijkje in de redactiekeuken van Tweakers.net
22 dec: Onze reputatie hooghouden
20 dec: Acht fouten
Le-zenRobbedoeske schreef op 02 October 2003 @ 13:55:
er bestaat iets als Microsoft Indexing Server (gratis bij .....)
daarmee kun je perfect doen wat je wilt, héééél snel woorden en complexe zoektermen zoeken IN een bestand
ook vanuit VB, VBA, whatever
RobIII schreef op 02 October 2003 @ 11:15:
[...]
<knip>
Overigens, als je vaker zoekt is de Indexing service misschien eens iets waar je eens naar moet kijken
[ Voor 3% gewijzigd door RobIII op 02-10-2003 14:22 ]
There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.
Je eigen tweaker.me redirect
Over mij
Heb je voorbeeld of url om dit vanuit vb te benaderen?Robbedoeske schreef op 02 October 2003 @ 13:55:
er bestaat iets als Microsoft Indexing Server (gratis bij .....)
daarmee kun je perfect doen wat je wilt, héééél snel woorden en complexe zoektermen zoeken IN een bestand
ook vanuit VB, VBA, whatever
Yesterday Is History. Today Is A Gift. Tomorrow Is Mystery
There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.
Je eigen tweaker.me redirect
Over mij