mikrocontroller.net

Forum: PC Hard- und Software Informationen zu FAT16


Autor: Bernhard B. (schluchti)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

ich bin auf der Suche nach Informationen zu FAT16. Da ich im Internet 
fast ausschließlich Informationen zu FAT32 finden konnte, dachte ich 
mir, ich frage mal nach ob hier jemand eine gute Seite kennt, die sich 
mit FAT16 beschäftigt.

So etwas ähnliches wie http://www.pjrc.com/tech/8051/ide/fat32.html wäre 
super.

PS: Mir ist bewusst, dass es bereits einige FAT16 Implementierungen 
gibt, dennoch möchte ich gerne verstehen wie die Daten in dem Filesystem 
abgelegt werden.

: Verschoben durch User
Autor: Mobius (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
http://lmgtfy.com/?q=FAT16+aufbau

erster Treffer.

gruß
Mobius

P.S.: Die Ablage ist genauso wie bei FAT32. Nur die Zahl der Sektoren 
ist begrenzt auf 65535 (16bit halt, wer hätte das erwartet ;) )

Autor: Bernd Rüter (Firma: Promaxx.net) (bigwumpus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bernhard B. schrieb:
> ich bin auf der Suche nach Informationen zu FAT16. Da ich im Internet
> fast ausschließlich Informationen zu FAT32 finden konnte, dachte ich
> mir, ich frage mal nach ob hier jemand eine gute Seite kennt, die sich
> mit FAT16 beschäftigt.

Wie hast Du das geschafft ?

Google platzt doch fast vor Links zum Thema FAT16 !

Oder soll es wieder fertiger Quellcode genau für Deine Anwendung sein ?

Autor: Bernhard B. (schluchti)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ok, dann eine konkrete Frage:

Wenn ich eine Datei mit dem Namen "TEST.txt" auf einer frisch 
formatierten FAT16 SD Karte erstelle, dann müsste doch ein 32 byte 
langer Directory-Eintrag im Root-Directory der SD Karte auftauchen.

Bei mir wird da jedoch im Root-Directory für die Datei "TEST.txt" ein 
Eintrag erstellt, der um einiges größer als 32 Byte ist.
Zuerst hab ich vermutet, dass es vielleicht dieser "Long-File-Zusatz" 
ist, doch mein Dateiname besteht ja nur aus 4.3 Zeichen.

Kann mir jemand erklären was diese Bytes, die ich im Bild mit einem 
Fragezeichen markiert habe, zu bedeuten haben?

Lg

Autor: ich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
des is ne gelöschte datei mit dem namen "Neu Textdokument.txt"

Autor: hdd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du hast die Text-Datei auf der SD-Karte erstellt und dadurch hatte die 
Datei erstmal den Namen "Neu Textdokument.txt". Die hast du dann 
umbenannt in TEST.TXT. Dadurch hast du erst die beiden (nicht mehr 
gültigen) Einträge für den langen Dateinamen und dannach den mit dem 
kurzen Namen, die beide auf den selben Dateieintrag zeigen

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>des is ne gelöschte datei mit dem namen "Neu Textdokument.txt"

Jupp.

>Bei mir wird da jedoch im Root-Directory für die Datei "TEST.txt" ein
>Eintrag erstellt, der um einiges größer als 32 Byte ist.

Der gehört nicht zu deiner Datei. Das sind Reste von einer anderen 
Datei.

Autor: Bernhard B. (schluchti)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Achso, jetzt wird mir einiges klar. Danke euch Dreien!

Noch eine Frage: Werden diese nicht mehr gültigen Einträge eigentlich 
irgendwann gelöscht/überschrieben?

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bernhard B. schrieb:
> Noch eine Frage: Werden diese nicht mehr gültigen Einträge eigentlich
> irgendwann gelöscht/überschrieben?

Ja, leg' einfach noch ein paar Dateien an und sieh Dir das Directory 
dann nochmal an.

Autor: Bernd Rüter (Firma: Promaxx.net) (bigwumpus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und arbeite nicht mit einer Windows-Umgebung mit LFN-Support und dem 
Explorer. Mehr Mist kann man ja nicht sammeln.

Autor: Bernhard B. (schluchti)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rufus t. Firefly schrieb:
> Ja, leg' einfach noch ein paar Dateien an und sieh Dir das Directory
> dann nochmal an.

Danke!

Autor: Troll (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei den meisten Dateisystemen werden Dateien nicht sofort gelöscht 
sondern nur als gelöscht markiert, bzw. der Speicherplatz als frei. Erst 
wenn der Bereich wieder neu beschrieben wird, verschwindet die alte 
Datei endgültig.

Autor: Bernhard B. (schluchti)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Troll schrieb:
> Bei den meisten Dateisystemen werden Dateien nicht sofort gelöscht
> sondern nur als gelöscht markiert, bzw. der Speicherplatz als frei. Erst
> wenn der Bereich wieder neu beschrieben wird, verschwindet die alte
> Datei endgültig.

Gut zu wissen, danke für die Info.
Aufgrund deines Tipps hab ich mir den Aufbau der Root-Directory-Einträge 
nochmal genauer angeschaut:
"0xE5: Entry has been previously erased and is available. File undelete 
utilities must replace this character with a regular character as part 
of the undeletion process."

Quelle: http://en.wikipedia.org/wiki/File_Allocation_Table


Das klingt doch ganz gut. Das muss ich mir nachher genauer im Hex-Editor 
ansehen.
Danke nochmals für den Hinweis!

Autor: Bernhard B. (schluchti)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

ich bin gerade dabei eine FAT16 Lesefunktion zu implementieren, die eine 
beliebige Datei auf der SD Karte öffnet und deren Inhalt ausgibt.
Im Moment gehe ich so vor:
Ich hol mir aus der Directory Table den Startcluster der zu lesenden 
Datei. Den Startcluster wandle ich in eine Sektoradresse um und lese 
anschließend den kompletten Cluster (meine SD Karte hat 16 Sectors per 
Cluster) aus.
Das funktioniert prinzipiell ganz gut, aber nur solange alle Sektoren in 
einem Cluster mit Daten gefüllt sind.
Jetzt gibts aber auch den Fall, dass meine zu lesende Datei so klein 
ist, dass diese nicht den kompletten Cluster (also 16 Sektoren) 
verwendet, sondern nur 5 Sektoren. Wenn ich jetzt den kompletten Cluster 
auslese, dann kommt am Anfang der Inhalt der Datei und dann nur mehr 
Datenmüll, der nicht mehr zur Datei gehört. Meine Frage ist nun: Wie 
erkenne ich am effizientesten das die Datei nur einen Teil des Clusters 
belegt?

Mein Ansatz wäre: In jedem 32 Byte langen Directory-Entry gibts 4 Byte 
die die Größe der Datei in Bytes angeben - diese werte ich aus und 
berechne mir die Anzahl der Sektoren die ich lesen muss, bis das Ende 
des Files erreicht wurde.
Ist der Ansatz ok, oder gibts einen besseren?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bernhard B. schrieb:

> Ist der Ansatz ok, oder gibts einen besseren?

Genauso hat es DOS letzten Endes auch gemacht.

Autor: Bernhard B. (schluchti)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Bernhard B. schrieb:
>
>> Ist der Ansatz ok, oder gibts einen besseren?
>
> Genauso hat es DOS letzten Endes auch gemacht.

Danke für den Hinweis. Dann werd' ich das auch mal so probieren.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ist der sinnvollste Ansatz.
Bei Textdateien findet man manchmal ein aus der Urzeit stammendes 
Relikt, das Steuerzeichen Ctrl-Z als Dateiendekennung, aber auf so etwas 
sollte man sich nicht verlassen, denn neuzeitliche Texteditoren 
verzichten auf so etwas.

Autor: Bernhard B. (schluchti)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rufus t. Firefly schrieb:
> Das ist der sinnvollste Ansatz.
> Bei Textdateien findet man manchmal ein aus der Urzeit stammendes
> Relikt, das Steuerzeichen Ctrl-Z als Dateiendekennung, aber auf so etwas
> sollte man sich nicht verlassen, denn neuzeitliche Texteditoren
> verzichten auf so etwas.

Mit dem Gedanken hab ich am Anfang auch gespielt, war mir aber nicht 
sicher ob es ein Steuerzeichen gibt, welches wirklich von jedem OS und 
jedem Texteditor als letztes Zeichen eingefügt wird...
Danke für den Hinweis!

Ich hab jetzt die Leseroutine fertig und würde gerne ein paar Meinungen 
zur Performance einholen. Um den Code möglichst übersichtlich zu 
gestalten, hab ich mir viele kleine Routinen geschrieben, die gewisse 
Teilaufgaben übernehmen. So wird zum Beispiel jedes Mal wenn ich die 
Adresse des Bootsectors benötige, diese erneut von der SD Karte gelesen. 
Performanceschonender wärs wahrscheinlich die Adresse in einer globalen 
Variable abzulegen und bei Bedarf auf diese zuzugreifen. Aber da ich 
möglichst auf globale Variablen verzichten möchte, bleibt mir nichts 
anderes übrig als den Wert jedes Mal von der SD Karte zu lesen.
Lange Rede, kurzer Sinn: Ich hab mal einen Lesevorgang von der SD Karte 
durchgeführt und würde gerne wissen wie schlecht meine Performance ist.
Ich bin mir dessen bewusst, dass ich sicherlich kein neues FAT16 
Performancewunder erschaffen werde, dennoch hätte ich gerne eine Routine 
die halbwegs flink arbeitet.

Die Daten:
.) Die zu lesende Datei ist 40kB groß
.) SPI Taktrate: 4MHz
.) CPU taktet mit 8MHz
.) Benötigte Zeit, um die Datei zu lesen: 28 Sekunden

Mit ist klar, dass ich sowohl die CPU als auch SPI schneller takten 
kann, aber ich möchte meinen schlechten Programmierstil nicht dadurch 
wettmachen, dass ich einfach den Takt erhöhe. Ich glaub das wäre der 
falsche Ansatz...

Was meint ihr? Ist die Lese-Performance akzeptabel oder grottenschlecht? 
Hab leider keine Ahnung welche Richtwerte man da erwarten 
soll/kann/muss...

Autor: Bernhard B. (schluchti)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab jetzt ein wenig recherchiert und bin draufgekommen, dass meine 
Lesegeschwindigkeit extrem schlecht ist.
Ich vermute mal, dass ich in dieser Funktion ziemlich viel Zeit 
herschenke:
struct FAT_struct fat16_get_fs_info(){
  struct FAT_struct FAT_values; 

  //only if the last two bytes of the MBR are 0x55 and 0xAA
  if((mmc_read_byte(0,510) == 0x55) && (mmc_read_byte(0,511) == 0xAA)){ 
      FAT_values.error_flag = 0;

    //get bootsector address
    FAT_values.bootsector = mmc_read_byte(0,457) << 24;
    FAT_values.bootsector += mmc_read_byte(0,456) << 16; 
    FAT_values.bootsector += mmc_read_byte(0,455) << 8;
    FAT_values.bootsector += mmc_read_byte(0,454) << 0;

    FAT_values.fat_type = mmc_read_byte(0, 450); //read from sector 0 byte 450 = file system type 

    //get bytes per sector
    FAT_values.bytes_per_sector = mmc_read_byte(FAT_values.bootsector, 12) << 8;
    FAT_values.bytes_per_sector += mmc_read_byte(FAT_values.bootsector, 11) << 0;

    //get sectors per cluster
    FAT_values.sectors_per_cluster = mmc_read_byte(FAT_values.bootsector, 13);

    //get reserved sectors
    FAT_values.reserved_sectors = mmc_read_byte(FAT_values.bootsector, 15) << 8;
    FAT_values.reserved_sectors += mmc_read_byte(FAT_values.bootsector, 14) << 0;
  

    //get sectors per FAT
    FAT_values.sectors_per_fat = mmc_read_byte(FAT_values.bootsector, 23) << 8;
    FAT_values.sectors_per_fat += mmc_read_byte(FAT_values.bootsector, 22) << 0;

    //get number of FATs
    FAT_values.number_of_fats = mmc_read_byte(FAT_values.bootsector, 16);

    //get max. number of root entries
    FAT_values.max_root_entry = mmc_read_byte(FAT_values.bootsector, 18) << 8;
    FAT_values.max_root_entry += mmc_read_byte(FAT_values.bootsector, 17) << 0;
  }

  else{ //otherwise: set error flag!
    FAT_values.error_flag = 1;
  }
  return FAT_values;  
}

Diese Funktion wird jedes Mal aufgerufen, wenn ich einen Wert (Anzahl 
der Sektoren, Anzahl der Root-Einträge...etc) daraus benötige.

Das heißt: Wenn ich z.B: die Adresse des Bootsectors in der Funktion 
test benötige, dann schreibe ich:
void test(){
   struct FAT_struct FAT; 
   FAT = fat16_get_fs_info(); 
   FAT.bootsector = tu_irgendwas_damit; 
}

Bei jedem Aufruf der Funktion mmc_read_byte werden 512 Byte (also ein 
Sektor) gelesen und dann wird das jeweilige Zeichen, welches der 
übergebenen Position entspricht, zurückgegeben.
Eine Möglichkeit wäre nun, die Werte in globale Variablen abzulegen und 
die Funktion zur Berechnung dieser Werte nur einmal auszuführen. Die 
Frage, die sich mir dabei stellt: Ist das ein guter Programmierstil, 
wenn ich all diese Werte in globale Variablen ablege?

Autor: Bernhard B. (schluchti)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, ich hab meinen Code jetzt mal so umgebaut wie oben beschrieben, also 
auf globale Variablen. Um eine 40kB große Datei zu lesen, benötige ich 
jetzt nur noch ca. 2 Sekunden. Mit so einem großen Performancegewinn 
hätte ich nie gerechnet. Einziger Nachteil: Der Code ist durch die 
zahlreichen globalen Variablen nicht immer einfach zu lesen...da muss 
ich mir noch etwas überlegen. Hat vielleicht jemand nen Tipp wie man das 
schöner lösen könnte?

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es empfiehlt sich sehr, mindestens den letzten gelesenen Sektor komplett 
zu puffern. Deine mmc_read_byte-Funktion kann nachsehen, ob die ihr 
übergebene Sektornummer die des bereits gelesenen Sektors ist, und kann 
dann den Lesevorgang überspringen. Nur bei einer abweichenden 
Sektornummer muss erneut gelesen werden.

Wenn ausreichend viel Speicher zur Verfügung steht, können auch mehrere 
Sektoren zwischengespeichert werden, beim Lesezugriff ist dann in der 
Liste der gelesenen Sektoren nachzuschauen, ob der gewünschte Sektor 
bereits im Speicher vorliegt. Beim Nachladen von noch nicht bekannten 
Sektoren ist dann sinnvollerweise ein Alterungsmechanismus zu verwenden, 
um zu bestimmen, welcher Sektor aus dem Speicher 'rausgekippt wird.

Gewiss, um so etwas zu implementieren, braucht man irgendwo irgendwelche 
Variablen. Das kann man mit globalen Variablen erledigen, das kann man 
aber auch mit statischen, nur aus einem C-Modul heraus sichtbaren 
Variablen erledigen. Das nicht zu tun, nur um globale Variablen zu 
scheuen wie der Teufel das Weihwasser, ist offensichtlich ineffizient.

Autor: Bernhard B. (schluchti)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rufus t. Firefly schrieb:
> Es empfiehlt sich sehr, mindestens den letzten gelesenen Sektor komplett
> zu puffern. Deine mmc_read_byte-Funktion kann nachsehen, ob die ihr
> übergebene Sektornummer die des bereits gelesenen Sektors ist, und kann
> dann den Lesevorgang überspringen. Nur bei einer abweichenden
> Sektornummer muss erneut gelesen werden.
>
> Wenn ausreichend viel Speicher zur Verfügung steht, können auch mehrere
> Sektoren zwischengespeichert werden, beim Lesezugriff ist dann in der
> Liste der gelesenen Sektoren nachzuschauen, ob der gewünschte Sektor
> bereits im Speicher vorliegt. Beim Nachladen von noch nicht bekannten
> Sektoren ist dann sinnvollerweise ein Alterungsmechanismus zu verwenden,
> um zu bestimmen, welcher Sektor aus dem Speicher 'rausgekippt wird.
>
Danke, die Idee ist echt nicht schlecht!

> Gewiss, um so etwas zu implementieren, braucht man irgendwo irgendwelche
> Variablen. Das kann man mit globalen Variablen erledigen, das kann man
> aber auch mit statischen, nur aus einem C-Modul heraus sichtbaren
> Variablen erledigen. Das nicht zu tun, nur um globale Variablen zu
> scheuen wie der Teufel das Weihwasser, ist offensichtlich ineffizient.

Ich meinte eigentlich eh statische Variablen, die nur in einem C-Modul 
sichtbar sind. Ich hab diese Variablen bisher immer fälschlicherweise 
als globale Variablen bezeichnet. Mein C-Modul sieht so aus:

fat16.c:
//Include-Files

//statische Variablen
static uint32_t bootsector;
static uint8_t fat_type;
static uint8_t error_flag;
static uint16_t bytes_per_sector;
static uint8_t sectors_per_cluster;
static uint16_t reserved_sectors;
static uint16_t sectors_per_fat;
static uint8_t number_of_fats;
static uint16_t max_root_entry;

//Hier kommen dann die Funktionen
[....]

Ich weiß, dass ich langsam am ursprünglichen Topic vorbeischieße, ich 
möchte aber keinen neuen Thread eröffnen. Deshalb stelle ich die Fragen 
hier. Ich hoffe man nimmt es mir nicht übel.
Und zwar:
.)Ist es besser(übersichtlicher?), die statischen Variablen in das 
Headerfile auszulagern oder können die ruhig im C-File stehen?
.)Gibt es einen Standard um statische Variablen (also jene Variablen die 
innerhalb eines kompletten C-Moduls gelten) bereits im Namen zu 
kennzeichnen? Also das man bereits am Variablennamen erkennt, dass sich 
der Gültigkeitsbereich der Variablen über das komplette C-Modul 
erstreckt.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bernhard B. schrieb:

> .)Ist es besser(übersichtlicher?), die statischen Variablen in das
> Headerfile auszulagern oder können die ruhig im C-File stehen?

Das ist die falsche Frage.

Die richtige Frage muss lauten:
Geht es ausserhalb deines SD-Moduls irgendjemanden etwas an, dass du da 
ein paar globale Variablen hast und ist es ok, wenn sich da jemand mit 
einem "extern" an diese Variablen klemmen kann?

Wenn die Antwort ja lautet, dann darfst du die Variablen nicht static 
machen und ein extern Eintrag kommt ins Header File.

Lautet die Antwort aber nein, dann gehören die Variablen ins *.c File 
und im Header File taucht kein Sterbenswörtchen über diese Variablen 
auf.

Bei dir lautet die Antwort, wie meistens, nein!

> .)Gibt es einen Standard um statische Variablen (also jene Variablen die
> innerhalb eines kompletten C-Moduls gelten) bereits im Namen zu
> kennzeichnen?

Eine zeitlang habe ich die Variablen mit einem vorangestelltem s als 
Modul-static gekennzeichnet. Aber im Grunde genommen, braucht man kaum 
eine derartige Kennzeichnung. Aus dem Zusammenhang und der Verwendung 
ist normalerweise relativ klar, welche Variablen Modulglobal sind und 
welche nicht.

Autor: Bernhard B. (schluchti)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Die richtige Frage muss lauten:
> Geht es ausserhalb deines SD-Moduls irgendjemanden etwas an, dass du da
> ein paar globale Variablen hast und ist es ok, wenn sich da jemand mit
> einem "extern" an diese Variablen klemmen kann?
>
> Wenn die Antwort ja lautet, dann darfst du die Variablen nicht static
> machen und ein extern Eintrag kommt ins Header File.
>
> Lautet die Antwort aber nein, dann gehören die Variablen ins *.c File
> und im Header File taucht kein Sterbenswörtchen über diese Variablen
> auf.

Wieder etwas gelernt. Alles klar, dann werd' ich die statischen 
Variablen im C-File belassen.

Karl heinz Buchegger schrieb:
> Eine zeitlang habe ich die Variablen mit einem vorangestelltem s als
> Modul-static gekennzeichnet. Aber im Grunde genommen, braucht man kaum
> eine derartige Kennzeichnung. Aus dem Zusammenhang und der Verwendung
> ist normalerweise relativ klar, welche Variablen Modulglobal sind und
> welche nicht.

Ok, dann werd' ich diese auch nicht weiter kennzeichnen. Ich hab mir 
gedacht, dass es vielleicht einen Standard gibt, den man bei der 
Namensgebung unbedingt beachten muss. Aber so wie ich das aus deinem 
Beitrag herauslese, dürfte da jeder Programmierer seinen eigenen "Stil" 
haben.

Danke für die ausführliche Erklärung!

Autor: Michael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bernhard B. schrieb:
> Aber so wie ich das aus deinem
> Beitrag herauslese, dürfte da jeder Programmierer seinen eigenen "Stil"
> haben.

Dürfen ja, solange es nur der Programmierer mit dem Code zu tun bekommt 
ist das auhc OK. Ich hab mir jedoch angewöhnt Variablen zu kennzeichnen 
damit, wenn mein Code von jemand anderen gelesen wird der keine Ahnung 
von meinem Stil hat, sich schnell reinfinden kann.

Autor: Bernhard B. (schluchti)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

ich bin gerade dabei meine Schreibroutine zu implementieren und dabei 
ist noch eine Frage aufgetaucht:

Mir ist klar, dass ich die SD Karte immer nur sektorweise beschreiben 
kann. Aber was mach ich, wenn eine Datei öffne, die nur 1,5 Sektoren 
belegt und ich bei dieser etwas ergänzen möchte?

Ein konkretes Beispiel:
Ich öffne eine Datei mit 798 Byte. In einen Sektoren passen 512 Byte 
(zumindest bei meiner SD Karte), das heißt: 798Byte / 512 
Byte_per_sector = 1,55...
Das heißt, ein Sektor ist komplett beschrieben und der andere nur etwa 
zur Hälfte. Jetzt möchte ich diese Datei öffnen und etwas 
hineinschreiben. Muss ich jetzt unmittelbar hinter dem halbbeschriebenen 
Sektor weiterschreiben oder kann ich nen neuen Sektor anfangen? Ersteres 
wäre ziemlich umständlich, da ich jedes Mal den letzten Sektor komplett 
lesen müsste, um zu überprüfen ob wirklich alle 512 Byte belegt sind. 
Wenn dies nicht der Fall ist, dann müsste ich die fehlenden Bytes 
ergänzen und den Sektor wieder auf die SD Karte schreiben.

Zur besseren Verdeutlichung hab ich nen Screenshot angehängt.

Mein erster Versuch war, einen komplett neuen Sektor zu beschreiben 
(siehe die vielen 'A's im Screenshot), aber das hat irgendwie nicht ganz 
geklappt.

Falls man unmittelbar hinter dem halbbeschriebenen Sektor 
weiterschreiben muss: Wie macht man das am effizientesten? Die einzige 
Möglichkeit wäre wie gesagt, dass ich den Sektor komplett lese und 
überprüfe ob dort wirklich alle 512 Byte belegt sind. Falls nur 500 Byte 
belegt sind, dann häng ich an die 500 Byte 12 Byte dran und schreib den 
Sektor nochmals auf die SD Karte. Gibts nen eleganteren Weg?

Jedes Mal den letzten Sektor lesen kostet halt schon etwas an Zeit...

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bernhard B. schrieb:
> Das heißt, ein Sektor ist komplett beschrieben und der andere nur etwa
> zur Hälfte. Jetzt möchte ich diese Datei öffnen und etwas
> hineinschreiben. Muss ich jetzt unmittelbar hinter dem halbbeschriebenen
> Sektor weiterschreiben oder kann ich nen neuen Sektor anfangen?

Du musst dort im Sektor weiterschreiben, wo die Datei vorher aufgehört 
hat.

Bernhard B. schrieb:
> Ersteres
> wäre ziemlich umständlich, da ich jedes Mal den letzten Sektor komplett
> lesen müsste, um zu überprüfen ob wirklich alle 512 Byte belegt sind.

Wieso das? Wofür gibt es im Directory eine Dateilängenangabe? Die modulo 
512 sagt Dir, wieviele Bytes im letzten genutzten Sektor der Datei noch 
nicht genutzt sind.

Bedenke hierbei, daß FAT mehrere Sektoren zu Clustern 
("Zuordnungseinheit") zusammenfasst und daß eine Datei immer eine 
ganzzahlige Anzahl von Clustern belegt.

Auch eine Datei, in der nur ein einziges Byte belegt ist, belegt einen 
vollständigen Cluster, der wiederum mehrere Sektoren groß sein kann 
(Anzahl ist eine Zweierpotenz).

Für Deine Dateiendebetrachtung musst Du also zuerst Dateigröße modulo 
Clustergröße anwenden, um herauszufinden, wo im Cluster die Datei endet.

Diesen Wert musst Du nun noch durch die Anzahl der Sektoren pro Cluster 
teilen (hier kommen die oben erwähnten Zweierpotenzen sehr praktisch ins 
Spiel), um die Nummer des Sektors im Cluster zu erhalten, und dann 
kannst Du wie oben bereits beschrieben die Anzahl der genutzten Bytes in 
diesem Sektor ermitteln.

Beim Beschreiben des letzten Sektors musst Du in der Tat den bisherigen 
Inhalt lesen, und an der korrekten Position die neuen Daten anhängen.

Dadurch, daß Du durch die im Verzeichniseintrag gespeicherte Dateilänge 
kennst, kannst Du diese Position ja berechnen. Das musst Du sogar - wie 
wolltest Du bei einer Datei, die binären Krempel enthält, sonst ihr Ende 
bestimmen?

Autor: Bernhard B. (schluchti)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rufus t. Firefly schrieb:
> Du musst dort im Sektor weiterschreiben, wo die Datei vorher aufgehört
> hat.

Alles klar, danke!

Rufus t. Firefly schrieb:
> Wieso das? Wofür gibt es im Directory eine Dateilängenangabe? Die modulo
> 512 sagt Dir, wieviele Bytes im letzten genutzten Sektor der Datei noch
> nicht genutzt sind.

Da hab ich mich etwas schlecht ausgedrückt. Ich hätte schon vorher mit 
modulo 512 überprüft, wieviele Bytes im letzten genutzten Sektor der 
Datei noch nicht genutzt sind. Ich wollte mir das komplette Lesen des 
letzten Sektors sparen, indem ich einfach nen neuen Sektor beschreibe. 
Das wäre glaub ich schneller gegangen und auf die paar ungenutzten Bytes 
wär es mir auch nicht angekommen.

Rufus t. Firefly schrieb:
> Bedenke hierbei, daß FAT mehrere Sektoren zu Clustern
> ("Zuordnungseinheit") zusammenfasst und daß eine Datei immer eine
> ganzzahlige Anzahl von Clustern belegt.
>
> Auch eine Datei, in der nur ein einziges Byte belegt ist, belegt einen
> vollständigen Cluster, der wiederum mehrere Sektoren groß sein kann
> (Anzahl ist eine Zweierpotenz).

Das ist mir soweit klar. Einzig das "Anzahl ist eine Zweierpotenz" 
wusste ich bisher nicht.

Rufus t. Firefly schrieb:
> Für Deine Dateiendebetrachtung musst Du also zuerst Dateigröße modulo
> Clustergröße anwenden, um herauszufinden, wo im Cluster die Datei endet.
>
> Diesen Wert musst Du nun noch durch die Anzahl der Sektoren pro Cluster
> teilen (hier kommen die oben erwähnten Zweierpotenzen sehr praktisch ins
> Spiel), um die Nummer des Sektors im Cluster zu erhalten, und dann
> kannst Du wie oben bereits beschrieben die Anzahl der genutzten Bytes in
> diesem Sektor ermitteln.

Mit dieser Erklärung komme ich nicht ganz klar (ich hätte es nämlich 
etwas umständlicher berechnet).

Mal angenommen wir haben eine Datei die 160000 Byte groß ist.

Deine Berechnung hab ich so verstanden:

Dateigröße % Clustergröße = Dateigröße % (Bytes_per_Sector * 
Sectors_per_Cluster) = 160000 % (512 * 16) = 4352

4352 / Sectors_per_Cluster = 4352 / 16 = 272
<-- was sagt dieser Wert(also die 272) jetzt eigentlich aus? Das kapier 
ich nicht ganz.

Ich hätte es so berechnet:

Dateigröße / Bytes_per_Sector = 160000 / 512 = 312,5 Sektoren (wird 
aufgerundet, da Sektoren immer ganzzahlig sind)

Diese 313 Sektoren werden dann durch Sectors_per_Cluster dividiert, um 
die Anzahl der Cluster zu berechnen.
--> 313 / 16 = 19 Cluster

19 Cluster * 16 (Sectors_per_Cluster) = 304 Sektoren

313 Sektoren - 304 Sektoren = 9.Sektor

Das heißt das Dateiende liegt im letzten (19.) Cluster an der 9. 
Sektorposition.
Die Byteposition innerhalb dieses Sektors würde ich mir dann mit 
Dateigröße % Bytes_per_Sector = 160000 % 512 = 256 berechnen.

Bin mir aber nicht ganz sicher ob der Ansatz in der Praxis auch 
funktioniert bzw. ob das praktikabel ist.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rufus t. Firefly schrieb:
> Diesen Wert musst Du nun noch durch die Anzahl der Sektoren pro Cluster
> teilen (hier kommen die oben erwähnten Zweierpotenzen sehr praktisch ins
> Spiel), um die Nummer des Sektors im Cluster zu erhalten, und dann
> kannst Du wie oben bereits beschrieben die Anzahl der genutzten Bytes in
> diesem Sektor ermitteln.

Da habe ich tatsächlich Unfug geschrieben.

Richtig ist:

Diesen Wert musst Du noch durch die Anzahl Bytes pro Sektor teilen ...

[Nachtrag]
Da die Sektorgröße selbst auch eine Zweierpotenz ist, wird das Teilen 
sehr einfach.

Autor: Bernhard B. (schluchti)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rufus t. Firefly schrieb:
> Richtig ist:
>
> Diesen Wert musst Du noch durch die Anzahl Bytes pro Sektor teilen ...

Damit geht die Berechnung tatsächlich um einiges weniger umständlich. 
Vielen Dank!

Rufus t. Firefly schrieb:
> [Nachtrag]
> Da die Sektorgröße selbst auch eine Zweierpotenz ist, wird das Teilen
> sehr einfach.

Aber man verwendet da weiterhin den Divisionsoperator, oder gibts da nen 
programmiertechnischen Kniff um den zu umgehen? Irgendwie liest sich 
dein abschließender Satz so, als wäre dem so...

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sofern der C-Compiler was taugt, muss man sich nicht darum kümmern, eine 
Alternative zum Divisionsoperator zu verwenden, jedenfalls nicht, wenn 
mit einer Konstanten als Divisor gearbeitet wird.

Die Alternative ist eine Schiebeoperation:

  x = y >> 1;

entspricht

  x = y / 2;

und

  x = y >> 9;

entspricht

  x = y / 512;


Wie gesagt, wenn der Compiler auch nur halbwegs was taugt, dann macht 
der das bei konstanten Divisoren, die Zweierpotenzen sind, sowieso 
selbst.

Autor: ... (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bernhard B. schrieb:
> Aber man verwendet da weiterhin den Divisionsoperator, oder gibts da nen
> programmiertechnischen Kniff um den zu umgehen? Irgendwie liest sich
> dein abschließender Satz so, als wäre dem so...

Normalerweise genau so mit Divisionsoperator. Man könnte auch den shift 
Operator nutzen, ist bei Zweierpotenzen schneller. Aber solange Du die 
Optimierungen im Compiler nicht abschaltest, ist der meist schlau genug 
daß auch selbst zu erkennen.

Autor: Bernhard B. (schluchti)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Alles klar. Wieder etwas gelernt :)

Danke euch zweien!

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wichtig ist dann aber mit unsigned werten (oder besser gleich den 
t_uint..) zu arbeiten, da für signed werte diese äquivalenz nicht gilt.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.