Random File Access

From Nutwiki
Revision as of 09:21, 22 June 2009 by Joshua (Talk) (Reformatted for proper indentation)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Description

This example shows how to read from and write to arbitrary locations in a PHAT file.

Source Code

<source lang="c">

  1. include <dev/board.h>
  2. include <dev/nplmmc.h>
  3. include <fs/phatfs.h>
  4. include <stdio.h>
  5. include <io.h>
  6. include <fcntl.h>
  7. include <errno.h>
  8. include <string.h>

static char buff[32];

int main(void) {

   int hvol;
   FILE *fp;
   unsigned long baud = 115200;
   NutRegisterDevice(&DEV_DEBUG, 0, 0);
   freopen(DEV_DEBUG_NAME, "w", stdout);
   _ioctl(_fileno(stdout), UART_SETSPEED, &baud);
   puts("File random access test\n");
   if (NutRegisterDevice(&devPhat0, 0, 0)) {
       printf("PHAT file system error\n");
   }
   if (NutRegisterDevice(&DEV_MMCARD, 0, 0)) {
       printf("MMC block device error\n");
   }
   hvol = _open(DEV_MMCARD_NAME ":1/PHAT0", _O_RDWR | _O_BINARY);
   if (hvol == -1) {
       printf("Mount error %d\n", errno);
   }
   fp = fopen("PHAT0:/example.txt", "w");
   if (fp == NULL) {
       printf("Error reading file!");
   }
   strcpy(buff, "Ethernut");
   fseek(fp, 0, SEEK_SET);
   fwrite(buff, 1, sizeof(buff), fp);
   strcpy(buff, "Extreme");
   fseek(fp, 32, SEEK_SET);
   fwrite(buff, 1, sizeof(buff), fp);
   strcpy(buff, "Example");
   fseek(fp, 64, SEEK_SET);
   fwrite(buff, 1, sizeof(buff), fp);
   fclose(fp);
   fp = fopen("PHAT0:/example.txt", "r");
   /* first, read something from the beginning of the file */
   fseek(fp, 0, SEEK_SET);
   fread(buff, 1, 32, fp);
   puts(buff);
   /* same thing but we read only the last few bytes */
   fseek(fp, -32, SEEK_END);
   fread(buff, 1, 32, fp);
   puts(buff);
   /* and now we'll do the same thing from somewhere in the middle */
   fseek(fp, 32, SEEK_SET);
   fread(buff, 1, 32, fp);
   puts(buff);
   fclose(fp);
   _close(hvol);
   for (;;);

} </source>

Details

<source lang="c"> char buff[256]; </source>

defines an array of the type char of 256 bytes. A char array is also called string.

<source lang="c"> unsigned long baud = 115200;

NutRegisterDevice(&DEV_DEBUG, 0, 0);

freopen(DEV_DEBUG_NAME, "w", stdout); _ioctl(_fileno(stdout), UART_SETSPEED, &baud);

puts("File random access test\n"); </source>

First, we set up our stdout device so we can print things to the terminal and output a line with "File random access test!"

<source lang="c"> if (NutRegisterDevice(&devPhat0, 0, 0)) {

   printf("PHAT file system error\n");

}

if (NutRegisterDevice(&DEV_MMCARD, 0, 0)) {

   printf("MMC block device error\n");

} </source>

Then we register our device drivers for the MMCard and the Phat file system. We'll need both for our file access.

<source lang="c"> hvol = _open(DEV_MMCARD_NAME ":1/PHAT0", _O_RDWR | _O_BINARY);

if (hvol == -1) {

   printf("Mount error %d\n", errno);

} </source>

Now we mount our partition. If something went wrong, we display an error message containing the error number.

<source lang="c"> fp = fopen("PHAT0:/example.txt", "w");

if (fp == NULL) {

   printf("Error reading file!");

} </source>

After that we open our file example.txt (it will be created if it doesn't exist, don't worry) and display an error if something goes wrong.

<source lang="c"> strcpy(buff, "Ethernut");

fseek(fp, 0, SEEK_SET); fwrite(buff, 1, sizeof(buff), fp); </source>

With the file open, we can use the fseek command to set the position in the file that we want to access. SEEK_SET means that we specify a position relative to the start of the file. After choosing our position, we write a string to the file.

<source lang="c"> strcpy(buff, "Extreme");

fseek(fp, 32, SEEK_SET); fwrite(buff, 1, sizeof(buff), fp);

strcpy(buff, "Example");

fseek(fp, 64, SEEK_SET); fwrite(buff, 1, sizeof(buff), fp); </source>

This is basically the same, only with different positions and strings. We set a new position and write a string there.

<source lang="c"> fclose(fp);

fp = fopen("PHAT0:/example.txt", "r"); </source>

Our data is written. Now let's try reading it in the same way. We close the file since it was opened for writing and reopen it for reading.

<source lang="c"> /* first, read something from the beginning of the file */ fseek(fp, 0, SEEK_SET); fread(buff, 1, 32, fp); puts(buff); </source>

You'll notice this looks a lot like the above statements. We set our position in the file and read 32 characters into our buffer. Technically there's no need to set the position to the beginning of the file since it is there by default.

<source lang="c"> /* same thing but we read only the last few bytes */ fseek(fp, -32, SEEK_END); fread(buff, 1, 32, fp); puts(buff); </source>

Since reading things in order is kind of boring, we now skip the second string for the moment read 32 characters from the end of the file. SEEK_END allows us to specify a position relative to the end of the file as opposed to the SEEK_SET we used before. So: We start reading 32 characters before the end of the file and we read 32 characters.

<source lang="c"> /* and now we'll do the same thing from somewhere in the middle */ fseek(fp, 32, SEEK_SET); fread(buff, 1, 32, fp); puts(buff); </source>

This reads and outputs another string from the file, the one we wrote second. If you look at the output below, you'll notice that they're displayed in the order we read them but they're saved in the order we write them. Run the example and check the example.txt on your MMC.

<source lang="c"> fclose(fp); _close(hvol); </source>

Finally we close our open file and volume.

Output

File random access test

Ethernut
Example
Extreme

See also