Rookworst zonder R is ook worst.
Je kunt niet veel anders doen dat in de file naar de positie gaan op het punt waar de te verwijderen regel en vanaf dat punt de rest van de file vanaf dat punt wegschrijven.
Hint: fpos, fseek. Evt. nog zaken als truncate. Verder zul je natuurlijk delen van de file in geheugenbuffers moeten plaatsen.
Hint: fpos, fseek. Evt. nog zaken als truncate. Verder zul je natuurlijk delen van de file in geheugenbuffers moeten plaatsen.
putStr $ map (x -> chr $ round $ 21/2 * x^3 - 92 * x^2 + 503/2 * x - 105) [1..4]
Daar was ik ook al bang voor ja, maar ik wilde het voor de zekerheid toch ff vragen, misschien dat er een leuke libc functie voor is ofzoOp woensdag 03 april 2002 21:07 schreef Infinitive het volgende:
Je kunt niet veel anders doen dat in de file naar de positie gaan op het punt waar de te verwijderen regel en vanaf dat punt de rest van de file vanaf dat punt wegschrijven.
Rookworst zonder R is ook worst.
code:
1
2
3
4
5
6
7
8
| while(!feof())
{
data = fread();
if(!verwijderen)
{
fwrite(data);
}
} |
1 buffer nodig van bijvoorbeeld 4096 bytes en verder een manier om te bepalen of je de betreffende regel moet verwijderen...
Verwijderd
Zo moet je denk ik eerst je filetje kopiëren, en van daaruit weer schrijven naar je vorige file?Op woensdag 03 april 2002 21:36 schreef ACM het volgende:
code:
1 2 3 4 5 6 7 8while(!feof()) { data = fread(); if(!verwijderen) { fwrite(data); } }
1 buffer nodig van bijvoorbeeld 4096 bytes en verder een manier om te bepalen of je de betreffende regel moet verwijderen...
hoeft niet persee, meestal kun je files openen voor zowel reading als writing (tip: fopen (file, "r+"))
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Verwijderd
Omdat PHP aardig wat van C weg heeft met dit punt.
Hele file inlezen (Array) -> regel die weg moet onthouden -> each de file weer wegschrijven, zonder bewuste regel..
Moet de file uiteraard niet te groot zijn..
Is er anders in C geen functie die uit een array de zoveelste index verwijderd ?!?!
Hele file inlezen (Array) -> regel die weg moet onthouden -> each de file weer wegschrijven, zonder bewuste regel..
Moet de file uiteraard niet te groot zijn..
Is er anders in C geen functie die uit een array de zoveelste index verwijderd ?!?!
Waarom zou je de hele file in het geheugen willen zetten? Kost aleen maar extra tijd.. Gewoon filepointer op de beginpositie zetten.Op woensdag 03 april 2002 23:07 schreef Tizzwat het volgende:
Omdat PHP aardig wat van C weg heeft met dit punt.
Hele file inlezen (Array) -> regel die weg moet onthouden -> each de file weer wegschrijven, zonder bewuste regel..
Moet de file uiteraard niet te groot zijn..
Is er anders in C geen functie die uit een array de zoveelste index verwijderd ?!?!
Het is het makkelijkst als je (mbv bijvoorbeeld spaties) er voor zorgt dat elk record evenveel tekens bevat. Je bestand wordt mischien wel groter, maar in dat geval kun je gewoon iets doen als fseek(recordnummer * recordgrootte) om de filepointer aan het begin van dat record neer te zetten.
Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'
Ik wilde eigenlijk verwijzen naar eerdere posts over dit onderwerp, maar ik bedacht net een in mijn ogen elegante oplossing die nog niet eerder ter sprake gekomen was. Het werkt als volgt:
Allemaal niet getest dus misschien zitten er wat lompe bugs in, maar mijns inziens is dit de meest efficiente methode omdat deze geen tijdelijk bestand aanmaakt (en dus geen extra hdd ruimte nodig heeft), een constante hoeveelheid geheugen gebruikt (en het bestand dus niet in z'n geheel hoeft in te lezen) terwijl de invoer/uitvoer operaties in grote blokken uitgevoerd worden, zodat het hele gebeuren toch nog efficient werkt.
Let er wel op dat de regel in kwestie kleiner moet zijn dan je buffer. Meestal is dit echter wel te garanderen.
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| int dif, len;
char buf[...]; /* 4096 ofzo */
fp=fopen(filepath,"r+");
/* zoek de te verwijderen regel op */
do {
fgets(buf,sizeof(buf),fp);
if(...) break;
} while(!feof(fp));
/* dif = lengte van de te verwijderen regel */
dif=strlen(buf);
/* schrijf de data na de te verwijderen regel over de te verwijderen regel heen */
while(!feof(fp)&&(len=fread(buf,1,sizeof(buf),fp))
{
/* terug naar 'dif' bytes voor dit blok */
fseek(fp,-(len+dif),SEEK_CUR);
fwrite(buf,1,len,fp);
fseek(fp,dif,SEEK_CUR);
}
len=ftell(fp);
fclose(fp);
truncate(filepath,len-dif); |
Allemaal niet getest dus misschien zitten er wat lompe bugs in, maar mijns inziens is dit de meest efficiente methode omdat deze geen tijdelijk bestand aanmaakt (en dus geen extra hdd ruimte nodig heeft), een constante hoeveelheid geheugen gebruikt (en het bestand dus niet in z'n geheel hoeft in te lezen) terwijl de invoer/uitvoer operaties in grote blokken uitgevoerd worden, zodat het hele gebeuren toch nog efficient werkt.
Let er wel op dat de regel in kwestie kleiner moet zijn dan je buffer. Meestal is dit echter wel te garanderen.
Als je dit doet wordt niet alleen het zoeken van een record heel efficient, maar ook het verwijderen ervan. Je kunt dan namelijk het te verwijderen record gewoon overschrijven met het laatste record in de file en dan het laatste record verwijderen. Je hoeft dan dus geen grote stukken van de file te verplaatsen. Uiteraard werkt dit alleen als de records in de file ongeordend zijn. Je kunt ook overwegen om ergens in je file een lijst op te nemen met pointers naar de echte records, om het record te verwijderen hoef je dan alleen de pointer ernaar uit de lijst te halen. Het fysieke record wordt dan niet verwijderd, maar het is wel lekker snel. Vervolgens kun je af en toe alle records waar niet naar verwezen wordt verwijderen uit de file.Op woensdag 03 april 2002 23:13 schreef Janoz het volgende:
[..]
Waarom zou je de hele file in het geheugen willen zetten? Kost aleen maar extra tijd.. Gewoon filepointer op de beginpositie zetten.
Het is het makkelijkst als je (mbv bijvoorbeeld spaties) er voor zorgt dat elk record evenveel tekens bevat. Je bestand wordt mischien wel groter, maar in dat geval kun je gewoon iets doen als fseek(recordnummer * recordgrootte) om de filepointer aan het begin van dat record neer te zetten.
He who knows only his own side of the case knows little of that.
De methode die jij beschrijft, is vooral geschikt voor het gebruik van variable sized records. Wanneer je echter fixed sized records gebruikt, kun je nog efficienter records verwijderen, door de te verwijderen record te overschrijven met de laatste record in het bestand. Je hoeft vervolgens alleen je (relatief kleine) tabel, die de feitelijke ordening bevat, te herschrijven. Dat is natuurlijk erg efficient. Een voorwaarde voor al deze methoden is natuurlijk dat je de te verwijderen regel van te voren kan identificeren aan de hand van een beperkte hoeveelheid data (een getal ofzo).Op donderdag 04 april 2002 11:59 schreef RickN het volgende:
Je kunt ook overwegen om ergens in je file een lijst op te nemen met pointers naar de echte records, om het record te verwijderen hoef je dan alleen de pointer ernaar uit de lijst te halen. Het fysieke record wordt dan niet verwijderd, maar het is wel lekker snel. Vervolgens kun je af en toe alle records waar niet naar verwezen wordt verwijderen uit de file.
Wat in dit geval het handigst is, hangt erg af van de toepassing. Fixed sized records zijn bijvoorbeeld erg geschikt voor een database met naw-gegevens ofzo, waarbij elk veld een redelijk beperkte lengte heeft. Als je bijvoorbeeld een email-archief wilt samenstellen, zijn fixed sized records uitermate ongeschikt, aangezien er gegarandeerd één record komt dat relatief groot is en er voor zorgt dat een relatief groot deel (denk aan meer dan de helft) van de ruimte verspilt.
EuhOp donderdag 04 april 2002 12:58 schreef Soultaker het volgende:
[..]
Zoals ik hierboven liet zien, kan dat overschrijven ook prima met variable sized records.
Hier heb je het neem ik aan over het bijhouden van een lijst met pointers naar de echte records? Ja, dat is idd vooral handig bij variable sized records.De methode die jij beschrijft, is vooral geschikt voor het gebruik van variable sized records.
Ja, dit is dus wat ik ook voorstelde, en wat niet werkt voor variable size records.Wanneer je echter fixed sized records gebruikt, kun je nog efficienter records verwijderen, door de te verwijderen record te overschrijven met de laatste record in het bestand.
Dit is idd een handige methode om toch met ordening om te kunnen gaan, als dat nodig is. Maar als je deze lijst toch gaat bijhouden (omdat dat nodig is voor ordening) kun je je afvragen of je een record bij het verwijderen überhaupt wel direct fysiek wilt verwijderen of dat je alleen de pointer ernaar uit de lijst verwijderd. Zoals gezegd kun je de hele file dan af en toe een keer comprimeren door alle records waar niet meer naar verwezen wordt te verwijderen.Je hoeft vervolgens alleen je (relatief kleine) tabel, die de feitelijke ordening bevat, te herschrijven. Dat is natuurlijk erg efficient.
Ja, maar je kunt er natuurlijk altijd voor zorgen dat dat kan, door zo'n getal aan het record toe te voegen.Een voorwaarde voor al deze methoden is natuurlijk dat je de te verwijderen regel van te voren kan identificeren aan de hand van een beperkte hoeveelheid data (een getal ofzo).
Ofcourse, er is bijna nooit een methode voor iets die elke situatie de beste is.Wat in dit geval het handigst is, hangt erg af van de toepassing. Fixed sized records zijn bijvoorbeeld erg geschikt voor een database met naw-gegevens ofzo, waarbij elk veld een redelijk beperkte lengte heeft. Als je bijvoorbeeld een email-archief wilt samenstellen, zijn fixed sized records uitermate ongeschikt, aangezien er gegarandeerd één record komt dat relatief groot is en er voor zorgt dat een relatief groot deel (denk aan meer dan de helft) van de ruimte verspilt.
He who knows only his own side of the case knows little of that.
Sorry, ik had verkeerd gelezen. Omdat je pas later over een tabel met offsets begon, ging ik er van uit dat je, om de ordening te behouden, wel alle volgende records over de oude heen zou willen schuiven. Mijn fout dus en mijn 'nieuwe' oplossing had jij dus al gegeven.Op donderdag 04 april 2002 13:54 schreef RickN het volgende:
Euhmisschien moet je ff in woorden vertellen wat die code van je dan doet, maar voorzover ik het zie verschuif je alles na het te verwijderen record een stuk je op, over het te verwijderen record heen. Dat werkt inderdaad ook voor variable lengte records, maar het is niet de methode die ik voorstelde en het is lang niet zo efficient.
Ik zal ff een beetje knippen in m'n bericht.
Normaal met open(), seek(), write(), read(), etc. Indien de bestanden wat groter zijn is mmap() een stuk sneller.Ik ben bezig met een soort van database, die al zijn records opslaat in een tekstfile, nu wil ik dat als er een record verwijderd word de gehele regel verwijderen, dus inclusief newline zodat de regel in de file echt verdwijnt.
Hoe doe ik dit?
Het is btw in Linux (ik neem aan dat dit niet echt uitmaakt)
Pagina: 1