Kapitel 10
Input/Output og Filer

Kurt Nørmark ©
Institut for Datalogi, Aalborg Universitet


Sammendrag
Forrige lektion
Stikord Referencer Indhold
I denne lektion beskriver vi filbegrebet og de forskellige operationer på filer. Vi slutter af med en diskussion af hvordan structures can udskrives på filer og indlæses fra filer.


Introduktion til filer

Oversigt over filbegreber
Slide Indhold Stikord
Referencer Lærebog 

Løst: En fil er en samling af data på et ekstert lagermedium

Konkret: En fil er en sekvens af data (bits) som er lagret i én enhed

  • Datatilgang:

    • Sekventiel

    • Random access

  • Dataindhold:

    • Tegn

      • Filer der indeholder bytes der tolkes som tegn fra ASCII alfabetet

    • Andre binære data

      • Filer der indeholder bitmønstre fra andre datatyper end tegn

Filer er ressourcer som administreres af operativsystemet

Fra et programmeringssprog er det muligt at knytte en forbindelse til en fil i operativsystemet

Sekventielle filer
Slide Indhold Stikord
Referencer Lærebog 

Sekventielle filer er modelleret efter egenskaberne af sekventielle medier, såsom magnetbånd

Begrebet sekventiel fil: En sekventiel fil læses altid i den rækkefølge den er skrevet. Rækkefølgen af enheder i en sekventiel fil afspejler direkte rækkefølgen af de udførte skriveoperationer på filen.

  • Mode of operation

    • En sekventiel fil tilgås enten i læse mode eller skrive mode

    • I det simple tilfælde kan man ikke både læse fra og skrive til en fil

  • Ydre enheder

    • Tastaturet modelleres typisk som en sekventiel fil i læse mode

      • Standard input

    • Skærmen modelleres typisk som en sekventiel fil i skrive mode

      • Standard output

Random access filer
Slide Indhold Stikord
Referencer Lærebog 

Filer på en harddisk er ikke af natur sekventielle filer

Det er muligt og naturligt at skrive og læse i en mere vilkårlig rækkefølge


Filer i C

Sekventielle filer i C
Slide Indhold Stikord
Referencer Lærebog 

Filer i C håndteres via biblioteket stdio.h

Sekventielle filer i C kan ses som abstraktioner over filerne i operativsystemet

Sådanne abstraktioner omtales ofte som streams

  • Åbning af en fil

    • Knytter forbindelsen til en fil i operativsystemets filhierarki

    • Angivelse af opening mode

    • Etablerer en pointer til en FILE struct

  • Processering af filen

    • stdio.h tilbyder et antal forskellige funktioner til sekventiel processering af en fil

  • Lukning af filen

    • Tømmer buffere og frigiver interne ressourcer

    • Bryder forbindelsen til filen i operativsystemet

Filbuffering
Slide Indhold Stikord
Referencer Lærebog 

En filbuffer er et lagerområde mellem anvendelsesprogrammet og det fysiske lager, hvor filen er gemt

Figur. En illustration af filbuffere mellem den ydre enhed og programmet

Strukturen FILE
Slide Indhold Stikord
Referencer Lærebog 

Strukturen FILE beskriver egenskaberne af en fil, herunder det afsatte bufferområde

  • Egenskaberne i FILE strukturen

    • Den nuværende filposition

    • Detaljer om filbufferen

    • Andre interne aspekter

Programmøren udnytter normalt ikke kendskab til detaljerne i FILE

FILE og de tilknyttede operationer er et eksempel på en abstrakt datatype

Simpel skrivning og læsning af en fil
Slide Indhold Stikord
Referencer Lærebog 

Vi viser her elementære eksempler på skrivning og læsning af tegn fra tekstfiler i C

Program: Skrivning af tegn fra en tekststreng på en tekstfil.
#include <stdio.h>

int main(void) {

  FILE *output_file_pointer;
  char *str = "0123456789abcdefghijklmnopqrstuvw";
  int i;

  output_file_pointer = fopen("first-file", "w");

  while (*str != '\0'){
    fputc(*str, output_file_pointer);
    str++;
  }

  fclose(output_file_pointer);
  return 0;
}

Program: Læsning af tegn fra en tekstfil til en tekststreng.
#include <stdio.h>
#define MAX_STR_LEN 100

int main(void) {

  FILE *input_file_pointer;
  char str[MAX_STR_LEN];
  int ch;
  int i = 0;

  input_file_pointer = fopen("first-file", "r");

  while ((ch = fgetc(input_file_pointer)) != EOF){
    str[i] = ch;
    i++;
  }
  str[i] = '\0';

  printf("Read from file: %s\n", str);

  fclose(input_file_pointer);
  return 0;
}

Henvisning

Program: Et program der laver dobbelt linieafstand i en tekstfil.
#include <stdio.h>
#include <stdlib.h>

void   double_space(FILE *ifp, FILE *ofp);
void   prn_info(char *pgm_name);

int main(int argc, char **argv)
{
   FILE   *ifp, *ofp;

   if (argc != 3) {
      prn_info(argv[0]);
      exit(1);
   }
   ifp = fopen(argv[1], "r");     /* open for reading */
   ofp = fopen(argv[2], "w");     /* open for writing */
   double_space(ifp, ofp);
   fclose(ifp);
   fclose(ofp);
   return 0;
}

void  double_space(FILE *ifp, FILE *ofp)
{
   int  c;

   while ((c = fgetc(ifp)) != EOF) {
      fputc(c, ofp);
      if (c == '\n')
       fputc('\n', ofp); /* found newline - duplicate it */
   }
}  

void prn_info(char *pgm_name)
{
   printf("\n%s%s%s\n\n%s%s\n\n",
      "Usage:  ", pgm_name, "  infile  outfile",
      "The contents of infile will be double-spaced ",
      "and written to outfile.");
}

Når en fil er læst til ende vil fgetc og andre tilsvarende funktioner returnere EOF værdien

Standard input, output og error
Slide Indhold Stikord
Referencer Lærebog 

De tre filer stdin, stdout, og stderr åbnes automatisk ved program start

Hver af stdin, stdout, og stderr er pointere til FILE

  • Standard input - stdin

    • Default knyttet til tastaturet

    • Kan omdirigeres til en fil med file redirection

  • Standard output - stdout

    • Default knyttet til skærmen

    • Kan omdirigeres til en fil med file redirection

  • Standard error - stderr

    • Default knyttet til skærmen

    • Benyttes typisk hvis stdout ikke tåler output af fejlmeddelelser

Henvisning

Der findes en række behændige filfunktioner, som implicit arbejder på stdin og stdout i stedet for at få overført en pointer til en FILE structure

Fil opening modes
Slide Indhold Stikord
Referencer Lærebog 

Foruden læse- og skrivemodes tilbydes yderligere et antal andre opening modes

Tabel. En tabel der beskriver betydningen af de forskellige opening modes af filer.
rÅbne eksisterende fil for input
wSkabe ny fil for output
aSkabe ny fil eller tilføje til eksisterende fil for output
r+Åbne eksisterende fil for både læsning og skrivning. Start ved begyndelse af fil.
w+Skabe en ny fil for både læsning og skrivning
a+Skabe en ny fil eller tilføje til eksisterende fil for læsning og skrivning
 

Program: Tilføjelse af tegn til en tekstfil.
#include <stdio.h>

int main(void) {

  FILE *output_file_pointer;
  char *str = "Another string";
  int i;

  output_file_pointer = fopen("first-file", "a");

  while (*str != '\0'){
    fputc(*str, output_file_pointer);
    str++;
  }

  fclose(output_file_pointer);
  return 0;
}

Program: Læsning og skrivning af fil med r+ (kun på Unix).
#include <stdio.h>
#define MAX_STR_LEN 100

int main(void) {

  FILE *input_file_pointer;
  char str[MAX_STR_LEN], ch;
  int i = 0;

  input_file_pointer = fopen("first-file", "r+");

  while ((ch = fgetc(input_file_pointer)) != EOF){
    str[i] = ch;

    fflush(input_file_pointer);  
    fputc('X', input_file_pointer);
    fflush(input_file_pointer);  

    i++;
  }
  str[i] = '\0';

  printf("Read from file: %s\n", str);

  fclose(input_file_pointer);
  return 0;
}

Program: Output fra ovenstående program (kørt på Unix).
0X2X4X6X8XaXcXeXgXiXkXmXoXqXsXuXwXnXtXeX XtXiXgX

C muliggør åbning af binære filer ved at tilføje et b til opening mode

I C på Unix er der ikke forskel på binære filer og tekstfiler

Funktioner på sekventielle filer
Slide Indhold Stikord
Referencer Lærebog 

Vi viser her en oversigt over udvalgte tegn-orienterede funktioner, som processerer filer sekventielt

  • int fgetc(FILE *stream)

    • Læser og returnerer næste tegn fra stream. Returnerer EOF hvis der er end of file.

  • int fputc(int c, FILE *stream)

    • Skriver tegnet c til stream.

  • int ungetc(int c, FILE *stream)

    • Omgør læsningen af c. Tegnet c puttes altså tilbage i stream så det kan læses endnu en gang. Kun én pushback understøttes generelt.

  • char *fgets(char *line, int size, FILE *stream)

    • Læser en linie ind i line, dog højst size-1 tegn. Stopper ved både newline og EOF. Afslutter line med '\0' tegnet.

  • int fputs(const char *s, FILE *stream)

    • Skriver strengen s til stream, uden det afsluttende '\0' tegn.

Funktioner på random access filer
Slide Indhold Stikord
Referencer Lærebog 

Begrebsligt kan man tilgå en random access fil på samme måde som et array

  • Random access funktioner:

    • int fseek(FILE *fp, long offset, int place)

      • Sætter filpositionen for næste læse- eller skriveoperation

      • offset er en relativ angivelse i forhold til place

      • place er SEEK_SET, SEEK_CUR, SEEK_END svarende til filstart, nuværende position, og filafslutning

    • long ftell(FILE *fp)

      • Returnerer den nuværende værdi af filpositionen relativ til filstart

    • void rewind(FILE *fp)

      • Ækvivalent til fseek(fp, 0L, SEEK_SET)

Program: Et program der læser en fil baglæns.
#include <stdio.h>

#define   MAXSTRING   100

int main(void){
   char   filename[MAXSTRING];
   int    c;
   FILE   *ifp;

   fprintf(stderr, "\nInput a filename:  ");
   scanf("%s", filename);
   ifp = fopen(filename, "r");     
   fseek(ifp, 0, SEEK_END); 
   fseek(ifp, -1, SEEK_CUR);
   while (ftell(ifp) > 0) {
      c = getc(ifp);        
      putchar(c);
      fseek(ifp, -2, SEEK_CUR); 
   }
   /*  The only character that has not been printed
       is the very first character in the file. */

   fseek(ifp, 0, SEEK_SET);
   c = getc(ifp);
   putchar(c);
   return 0;
}


Formateret output og input

Formateret output - printf familien (1)
Slide Indhold Stikord
Referencer Lærebog 

Familien af printf funktioner tilbyder tekstuel output af værdier i forskellige typer, og god kontrol af output formatet

Familien omfatter funktioner der skriver på en bestemt fil, på standard output, og i en streng

  • Formålet med printf

    • Pretty printing

    • Konvertering af værdier fra forskellige typer til tekst

    • Kontrol af det tekstuelle format

Mange detaljer, som knytter sig til de mulige typer af værdier, der håndteres af printf

Formateret output - printf familien (2)
Slide Indhold Stikord
Referencer Lærebog 

Vi ser her på fortolkningen af en kontrolstrengen

Figur. Nedbrydning af kontrolstrengen for %-#08.3hd. Denne figur er inspireret fra 'A C Reference Manual' af Harbison & Steele

  • %-#08.3hd

    • Conversion letter: d for heltalsformatering

    • Flags: - left justify, # use variant (ikke anvendelig her), 0 zero padding

    • Min. field width: 8. Mindste plads som afsættes

    • Precision: 3 Mindste antal cifre der udskrives - bruger 0 paddings om nødvendig

    • Size modifier: h short

Formateret output - printf familien (3)
Slide Indhold Stikord
Referencer Lærebog 

Lærebogen - og referencebøger om C - har mange detaljer om printf

  • Udvalgte bemærkninger om printf funktionerne

    • Returnerer antallet af udskrevne tegn

    • Man kan kontrollere højre og venstre justering i felt

      • Et - flag betyder venstrejustering

    • Field width og precision kan indlæses som input

      • Angivelse med *

Program: Illustration af *.* field width og precision .
#include <stdio.h>

int main (int argc, char *argv []){

  int int_number, n, m, printf_res;
  double double_number;

  while (1){
   printf("Indtast heltal, min. field width, og præcision\n");
   scanf(" %d %d %d", &int_number, &n, &m);
   printf_res = printf("%*.*d\n", n, m, int_number);
   printf("printf returnerede: %d\n", printf_res);

   printf("Indtast double, min. field width, og præcision\n");
   scanf(" %lf %d %d", &double_number, &n, &m);
   printf_res = printf("%*.*f\n", n, m, double_number);
   printf("printf returnerede: %d\n", printf_res);

  }

}

Viden om printf tilegnes efter behov

Formateret input - scanf familien (1)
Slide Indhold Stikord
Referencer Lærebog 

Familien af scanf funktioner tilbyder tekstuel input (parsing, scanning) af værdier i forskellige typer

Familien omfatter funktioner der læser fra en bestemt fil, fra standard input, og fra en streng

  • Formålet med scanf

    • Fortolkning og parsing af tekst

    • Konvertering af tekstudsnit til værdier i forskellige typer

    • Assignment af værdier til parametre overført pr. reference - call by reference parametre

Parsning er vanskeligere end pretty printing

Ligesom printf, er der mange detaljer som knytter sig til de mulige typer, hvortil scanf kan konvertere

Formateret input - scanf familien (2)
Slide Indhold Stikord
Referencer Lærebog 

Begreber som knytter sig til formateret input med scanf

  • Kontrolstreng med et antal direktiver

  • Tre slags direktiver

    • Almindelige tegn: Matcher de angivne tegn

    • White space: Matcher så mange mellemrum, tabs, og linieskift som mulig

    • Konverteringsspecifikation: %...c:
      Matcher input efter givne regler og konverteres til en værdi som angivet af c

  • Scan field:

    • Et sammenhængende område i inputtet som forsøges konverteret med en given konverteringsspecifikation.

    • Scan width: En angivelse i konverteringsspecifikationen af den maksimale længde af et scan field

    • Består af et område uden white space (på nær for %c)

Program: Illustration af directives med almindelige tegn, samt brug af scan width.
#include <stdio.h>

int main (int argc, char *argv []){

  int scan_res;
  double double_number;
  char str[7];

  printf("Indtast et $ efterfulgt af en double.\n");
  scan_res = scanf("$%lf", &double_number);
  printf("Det indlæste tal: %f\n", double_number);
  printf("scanf returnerede: %d\n", scan_res);

  printf("Indtast en streng - der læses max 6 tegn\n");
  scan_res = scanf("%6s", str);
  printf("Den indlæste streng: %s\n", str);
  printf("scanf returnerede: %d\n", scan_res);
}

Formateret input - scanf familien (3)
Slide Indhold Stikord
Referencer Lærebog 

Nogle væsentlige bemærkninger om scanf funktionerne

  • Returværdi

    • EOF hvis input 'løber tør' - input failure

    • Antallet af gennemførte konverteringer (indtil evt. matching failure)

  • Assignment suppression *

    • Matching - men ingen assignment til pointervariable

    • Tæller ikke som en konvertering

  • Scan set af formen [cde]

    • Indlæsning af en streng fra alfabetet bestående af 'c', 'd' og 'e'.

  • Scan set af formen [^cde]

    • Indlæsning af en streng afsluttet af et tegn fra alfabetet bestående af 'c', 'd' og 'e'.

Formateret input - scanf familien (4)
Slide Indhold Stikord
Referencer Lærebog 

Vi viser et antal eksempler på brug af scanf

Program: Et program der læser ikke-blanke liner fra en fil og udskriver disse på standard output.
#include <stdio.h>

int main(int argc, char *argv[]) {

  FILE *ifp = fopen(argv[1],"r");

  char line[300];
  int i = 0;

  while (fscanf(ifp," %[^\n]", line) == 1){
    printf("%s\n", line);
    i++;
  }

  printf("\n\ni = %i\n",i);

  fclose(ifp);
  
  return 0;
}

Program: Et andet program der adskiller alfabetiske og numeriske afsnit i en tekst - læser fra stdin.
#include <stdio.h>

int main(void) {

  char alph[25], numb[25];
  int numres;

  printf("Enter input, such as \"aaa111bbb222\"\n");

  while (scanf("%[abcdefghijklmnopqrstuvwxyz]", alph) == 1){
    numres = scanf("%[0123456789]", numb);

    if (numres != 1) 
       printf("MISMATCH");
    else
       printf("Alphabetic: %s\n"
              "Numeric: %s\n\n",
              alph, numb);
  }
  
  return 0;
}

Program: Et andet program der adskiller alfabetiske og numeriske afsnit i en tekst - læser fra en streng - virker ikke.
#include <stdio.h>

int main(void) {

  char *str = "abc135def24681ghi3579";
  char alph[25], numb[25];
  int numres;

  while (sscanf(str,"%[abcdefghijklmnopqrstuvwxyz]", alph) == 1){
    numres = sscanf(str,"%[0123456789]", numb);

    if (numres != 1) 
       printf("MISMATCH");
    else
       printf("Alphabetic: %s\n"
              "Numeric: %s\n\n",
              alph, numb);
  }
  
  return 0;
}

Program: Et andet program der adskiller alfabetiske og numeriske afsnit i en tekst - læser fra en streng - virker!.
#include <stdio.h>

int main(void) {

  char *str = "abc135def24681ghi3579";
  char alph[25], numb[25];
  int numres;

  while (sscanf(str,"%[abcdefghijklmnopqrstuvwxyz]", alph) == 1){
    str += strlen(alph);

    numres = sscanf(str,"%[0123456789]", numb);
    str += strlen(numb);

    if (numres != 1) 
       printf("MISMATCH");
    else
       printf("Alphabetic: %s\n"
              "Numeric: %s\n\n",
              alph, numb);
  }
  
  return 0;
}


Input og output af structures

Input/Output af structures (1)
Slide Indhold Stikord
Referencer Lærebog 

Det er ofte nyttigt at udskrive en eller flere structs på en fil, og tilsvarende at kunne indlæse en eller flere structs fra en fil

Det er nyttigt at have en standard løsning - et mønster - for dette problem

Program: Programmet der udskriver bøger på en output fil.
#include <stdio.h>
#include "book-read-write.h"

int main(void) {

  book *b1, *b2;
  FILE *output_file;

  b1 = make_book("C by Dissection", "Kelly and Pohl", 
                  "Addison Wesley", 2002, 1);
  b2 = make_book("The C Programming Language", 
                  "Kernighhan and Ritchie",
                  "Prentice Hall", 1988, 1);

  output_file = fopen("books.dat", "w");

  print_book(b1, output_file);
  print_book(b2, output_file);

  fclose(output_file);

  return 0;

}

Program: Programmet der indlæses bøger fra en input fil.
#include <stdio.h>
#include "book-read-write.h"

int main(void) {

  book *b1, *b2;

  FILE *input_file;
  input_file = fopen("books.dat", "r");

  b1 = read_book(input_file);
  b2 = read_book(input_file);

  prnt_book(b1);   prnt_book(b2);

  fclose(input_file);

  return 0;

}

Program: Header filen book-read-write.h.
#define PROTECTED_SPACE '@'
#define PROTECTED_NEWLINE '$'
#define BUFFER_MAX 1000

struct book {
  char *title, *author, *publisher;
  int publishing_year;
  int university_text_book;
};

typedef struct book book;

book *make_book(const char *title, const char *author, 
                const char *publisher, 
		int year, int text_book);

void prnt_book(book *b);

void print_book(book *b, FILE *ofp);

book *read_book(FILE *ifp);

Program: Implementationen af biblioteket - book-read-write.c.
#include <stdio.h>
#include "book-read-write.h"

/* Allocated memory to a book, and allocate strings to initialized by the 
   string constants passed as parameter */
book *make_book(const char *title, const char *author, const char *publisher, 
               int year, int text_book){
  static book *result;
  result = (book*)malloc(sizeof(book));
  //  strcpy(result->title,title);

  /* Copy string constants to dynamically allocated strings */
  result->title = strcpy((char *)calloc(strlen(title)+1,sizeof(char)), 
                         title);
  result->author = strcpy((char *)calloc(strlen(author)+1,sizeof(char)), 
                         author);
  result->publisher = strcpy((char *)calloc(strlen(publisher)+1,sizeof(char)), 
                         publisher); 
  result->publishing_year = year;
  result->university_text_book = text_book;
 
  return result;
}

/* print book b to standard output */
void prnt_book(book *b){
  char *yes_or_no;

  yes_or_no = (b->university_text_book ? "yes" : "no"); 
  printf("Title: %s\n"
         "Author: %s\n"
         "Publisher: %s\n"
         "Year: %4i\n"
         "University text book: %s\n\n",
         b->title, b->author, b->publisher, 
         b->publishing_year, yes_or_no);
}

char *white_space_protect(char *str){
  int str_lgt = strlen(str), i, j;
  for(i = 0; i < str_lgt; i++){
    if (str[i] == ' ')
      str[i] = PROTECTED_SPACE;
    else if (str[i] == '\n')
      str[i] = PROTECTED_NEWLINE;
  } 
  return str;
} 

char *white_space_deprotect(char *str){
  int str_lgt = strlen(str), i;
  for(i = 0; i < str_lgt; i++){
    if (str[i] == PROTECTED_SPACE)
      str[i] =  ' ';
    else if (str[i] == PROTECTED_NEWLINE)
      str[i] = '\n';
  }
  return str;
} 

/* Encode the book pointed to by p in the string str */
void encode_book(book *b, char *str){
  sprintf(str, "%s %s %s %i %i\n", 
          white_space_protect(b->title), 
          white_space_protect(b->author), 
          white_space_protect(b->publisher), 
          b->publishing_year, b->university_text_book);
} 

book *decode_book(char *str){
  char book_title[100], book_author[100], book_publisher[100];
  int book_year, book_uni;

  sscanf(str, "%s %s %s %i %i", 
         book_title, book_author, book_publisher,
         &book_year, &book_uni);
    
  return make_book(white_space_deprotect(book_title), 
                   white_space_deprotect(book_author),
                   white_space_deprotect(book_publisher), 
                   book_year, book_uni);
}


void print_book(book *b, FILE *ofp){
  char buffer[BUFFER_MAX];
  encode_book(b, buffer);
  fprintf(ofp, "%s", buffer);
}

book *read_book(FILE *ifp){
  char buffer[BUFFER_MAX];
  fgets(buffer, BUFFER_MAX, ifp);
  return decode_book(buffer);
}

Program: Compilering af programmerne.
gcc -c book-read-write.c

gcc book-write-prog.c book-read-write.o -o book-write-prog

gcc book-read-prog.c book-read-write.o -o book-read-prog

Opgave 10.2. Input og Output af structsVi vil antage at vi har en struct som beskriver data om en person, så som
  struct person {
    char *name;
    int age;
    char sex;
  }
hvor sex er enten tegnet 'm' eller 'f'. I denne øvelse bliver du bedt om at programmere funktioner, som kan udskrive et antal personer på en fil, og som efterfølgende kan indlæse disse igen.

Konkret, skal der skrives to funktioner

    print_person(person *p, FILE *ofp)
    person *read_person(FILE *ifp)

Du kan vælge en tekst-baseret og linie-orienteret fremgangsmåde, som illustreret ved forelæsningen. Som et noget lettere alternativ kan du vælge at anvende en binær fremgangsmåde ved brug af fwrite og fread.

Input/Output af structures (2)
Slide Indhold Stikord
Referencer Lærebog 

Vi ser nu på generelle problemstillinger af struct IO

  • Problemstillinger:

    • Kun felter af taltyper, char, og string håndteres

    • Pointers til andre typer end strenge kan ikke udskrives og indlæses

    • Evt. nestede structs og arrays kræver specialbehandling

    • Vi vælger en løsning med én struct per linie i en tekst fil

      • Newline tegn må derfor ikke indgå i strenge

      • Det er behændigt hvis en streng altid kan læses med scanf og %s

En mere generel anvendelig løsning ville være ønskelig

Nogle sprog understøtter en meget simpel, binær file of records for dette behov

I C er funktionerne fread og fwrite nyttige for læsning og skrivning af binære filer

Binær input/output med fread og fwrite
Slide Indhold Stikord
Referencer Lærebog 

Structures i C med simple aritmetiske typer kan let udskrives og indlæses binært med fwrite og fread

Program: Skrivning af en struct til en binær fil.
#include <stdio.h>

struct str {
  int f1;
  double f2;
  char f3;
  char f4[4];
};

int main(void){
  FILE *ofp;
  struct str rec= {5, 13.71, 'c', "xyz"};
  ofp = fopen("data", "w");

  fwrite(&rec, sizeof(struct str), 1, ofp);  
  fclose(ofp);
  return 0;
}

Program: Tilsvarende læsning af en struct fra en binær fil.
#include <stdio.h>

struct str {
  int f1;
  double f2;
  char f3;
  char f4[4];
};

int main(void){
  FILE *ifp;
  struct str rec;
  ifp = fopen("data", "r");

  fread(&rec, sizeof(struct str), 1, ifp);  

  printf("f1=%d, f2= %f, f3 = %c, f4 = %s\n",
         rec.f1, rec.f2, rec.f3, rec.f4);
  fclose(ifp);
  return 0;
}

Det giver ikke mening at udskrive og genindlæse pointere med fwrite og fread

Dette betyder at dynamisk allokerede strenge ikke kan håndteres af fread og fwrite

Program: Skrivning af en struct med et pointer felt til en binær fil.
#include <stdio.h>

struct str {
  int f1;
  double f2;
  char f3;
  char *f4;
};

int main(void){
  FILE *ofp;
  struct str rec= {5, 13.71, 'c', "xyz"};
  ofp = fopen("data", "w");

  fwrite(&rec, sizeof(struct str), 1, ofp);  
  fclose(ofp);
  return 0;
}

Program: Tilsvarende læsning af en struct fra en binær fil - virker ikke.
#include <stdio.h>

struct str {
  int f1;
  double f2;
  char f3;
  char *f4;
};

int main(void){
  FILE *ifp;
  struct str rec;
  ifp = fopen("data", "r");

  fread(&rec, sizeof(struct str), 1, ifp);  

  printf("f1=%d, f2= %f, f3 = %c, f4= %s\n", rec.f1, rec.f2, rec.f3, rec.f4);
  fclose(ifp);
  return 0;
}


Bemærkninger til Eksamensopgaven

Arbejdsprocessen
Slide Indhold Stikord
Referencer 

  • Overblik og forståelse

    • Fuld forståelse af opgaveformuleringen

    • Spørg nu og her.

    • Gør om nødvendig nogle antagelser

  • Design og planlægning

    • Hvilke "moduler"?

    • Fastlæg grænseflader af funktioner (prototyperne)

    • Skriv header filer (.h filer)

  • Den egentlige programmering

    • Implementering af .c filer svarende til .h filer

    • Implementering af selve applikationen (hangman) og main

    • Sædvanlig del og hersk. Problemer opdeles i delproblemer. Delproblemer programmeres i funktioner

    • Test og prøvekør de enkelte dele. Skriv små main metoder til dette formål

  • Samling af delene til en helhed

    • Overkommelig når man ved at delene faktisk fungerer

Praktiske forhold og Redelighed
Slide Indhold Stikord
Referencer 

Aflever et velformateret program uden afskårne eller ombrudte linier

Hver studerende medbringer ved eksamen en nøjagtig kopi af det afleverede.

Fortæl os senest 28. april - sidste kursusgang - hvis I ikke selv medbringer en PC med demo til eksamen

Brug gerne nyhedsgruppen aau.basis.programmering hvis der opstår problemer

Redelighed hvad angår kilder og hjælp udefra, herunder hjælp fra 'den anden halvgruppe'.


Samlede referencer
Indhold Stikord
Læsning og skrivning af tegn fra tidligere lektion
File Redirection

 

Kapitel 10: Input/Output og Filer
Kursets hjemmeside     Forfatteren's hjemmeside     Om frembringelsen af disse sider     Forrige lektion (top)     Næste lektion (top)     Forrige lektion (bund)     Næste lektion (bund)     
Genereret: 7. Juli 2010, 15:13:09