ThInf-HOME

  1. Einführung

  2. Dateien Lesen und Schreiben

  3. Beispiel zum Dateien Lesen

  4. Fehlervariable 'errno'

  5. Beispiel zum Anhängen von Daten an eine Datei

  6. Entfernen und Umbenennen von Dateien

  7. Übungsaufgaben


I-PROGRAMMIEREN1 WS 0203 - Vorlesung mit Übung
VL7: Dateien Lesen und Schreiben


AUTHOR: Gerd Döben-Henisch
DATE OF FIRST GENERATION: Nov-10, 2002
DATE OF LAST CHANGE: Nov-11, 2002
EMAIL: Gerd Döben-Henisch



1. Einführung


Bisher wurden drei Möglichkeiten vorgestellt, wie ein C-Programm mit seiner Umgebung Daten austauschen kann:

Eine vierte Möglichkeit, mit der Umgebung Daten auszutauschen, ist jene über das Lesen und Schreiben von Dateien. Dies soll Gegenstand der heutigen Vorlesung sein.




START

2. Dateien Lesen und Schreiben


Bei der Behandlung der Dateioperationen unter C muss man sich vor Augen halten, dass in C der Austausch von Daten zwischen Geräten wie Tastatur, Bildschirm, Plattenspeichern, und allen anderen peripheren Geräten in einheitlicher Weise mit dem Konzept der Streams beschrieben wird. Dies bedeutet, ob Datei, Device oder was auch immer, in C wird ein Stream geöffnet (mit fopen()), und zwar entweder zum

Fügt man ein "b" an, dann bedeutet dies beim Modus, dass der Stream nicht als Text-Stream geöffnet werden soll, sondern als Bit-Stream.

Es gibt drei Standard-Streams, die immer geöffnet werden:

Man kann allerdings weitere Streams erzeugen und sie mit einem Namen belegen. Dabei muss man beachten, dass man die maximale Länge von Namen (FILENAME_MAX) nicht überschreitet.

Liefert fopen einen NULL-Pointer zurück, dann ist etwas falsch gelaufen und man sollte sofort klären (mit der Funktion ferror), was geschehen ist. Andernfalls kann man weiter arbeiten. Der Filepointer fp, der verschieden ist von NULL, ist ein Filedescriptor, der von anderen Funktionen als Name des Streams solange benutzt werden kann, bis die Funktion fclose(fp) ihn wieder 'ausser Kraft setzt'.

Ist es gelungen, einen Stream erfolgreich z.B. zum Lesen zu öffnen, dann kann man mit der Funktion fgetc(fp) oder dem Makro getc(fp) den Inhalt des Streams zeichenweise auslesen (die C-Bibliothek hällt weitere Funktionen zum Lesen bereit). Entdecken fgetc() oder getc() das Ende des Streams oder einen Fehler, dann liefern sie EOF= -1 als Ergebnis zurück, andernfalls den Integerwert des gelesenen Zeichens.



FILES

Dateien in C (Anmerkung: die Position des Zeichens '+' im Feld 'MODE' von fopen() ist 'zwischen' den beiden anderen Optionen, nicht davor, wie im Bild fälschlich angegeben)



Wer genauere Informationen zu den einzelnen Funktionen haben will, kann unter UNIX bzw. LINUX diese einfach per 'man FUNKTIONSNAME' abfragen. Auf die Frage 'man fopen' z.B. bekommt man folgende Informationen:


NAME
       fopen, fdopen, freopen - stream open functions

SYNOPSIS
       #include <stdio.h>

       FILE *fopen(const char *path, const char *mode);
       FILE *fdopen(int fildes, const char *mode);
       FILE *freopen(const char *path, const char *mode, FILE *stream);

DESCRIPTION
       The  fopen  function opens the file whose name is the string pointed to by path and
       associates a stream with it.

       The argument mode points to a string beginning with one of the following  sequences
       (Additional characters may follow these sequences.):

       r      Open  text  file  for reading.  The stream is positioned at the beginning of
              the file.

       r+     Open for reading and writing.  The stream is positioned at the beginning  of
              the file.

       w      Truncate file to zero length or create text file for writing.  The stream is
              positioned at the beginning of the file.

       w+     Open for reading and writing.  The file is created if  it  does  not  exist,
              otherwise it is truncated.  The stream is positioned at the beginning of the
              file.

       a      Open for appending (writing at end of file).  The file is created if it does
              not exist.  The stream is positioned at the end of the file.

       a+     Open  for  reading and appending (writing at end of file).  The file is cre­
              ated if it does not exist.  The stream is positioned at the end of the file.

       The  mode string can also include the letter ``b'' either as a last character or as
       a character between the characters in any of the  two-character  strings  described
       above.   This  is strictly for compatibility with ANSI X3.159-1989 (``ANSI C'') and
       has no effect; the ``b'' is ignored on  all  POSIX  conforming  systems,  including
       Linux.   (Other  systems  may  treat  text  files and binary files differently, and
       adding the ``b'' may be a good idea if you do I/O to a binary file and expect  that
       your program may be ported to non-Unix environments.)

       Any  created  files  will have mode S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH
       (0666), as modified by the process' umask value (see umask(2).

       Reads and writes may be intermixed on read/write streams in any order.   Note  that
       ANSI  C  requires  that  a  file  positioning function intervene between output and
       input, unless an input operation encounters end-of-file.  (If this condition is not
       met,  then  a  read  is  allowed to return the result of writes other than the most
       recent.)  Therefore it is good  practice  (and  indeed  sometimes  necessary  under
       Linux)  to  put  an fseek or fgetpos operation between write and read operations on
       such a stream.  This operation may be an  apparent  no-op  (as  in  fseek(...,  0L,
       SEEK_CUR) called for its synchronizing side effect.

       Opening  a file in append mode (a as the first character of mode) causes all subse­
       quent write operations to this stream to occur at end-of-file, as if preceded by an
              fseek(stream,0,SEEK_END);
       call.

       The  fdopen function associates a stream with the existing file descriptor, fildes.
       The mode of the stream (one of the values "r", "r+", "w", "w+", "a", "a+") must  be
       compatible  with  the  mode of the file descriptor.  The file position indicator of
       the new stream is set to that belonging to fildes, and the  error  and  end-of-file
       indicators  are  cleared.   Modes  "w" or "w+" do not cause truncation of the file.
       The file descriptor is not dup'ed, and will be closed when the  stream  created  by
       fdopen is closed.  The result of applying fdopen to a shared memory object is unde­
       fined.

       The freopen function opens the file whose name is the string pointed to by path and
       associates  the  stream  pointed  to by stream with it.  The original stream (if it
       exists) is closed.  The mode argument is used just as in the fopen  function.
       The file descriptor is not dup'ed, and will be closed when the  stream  created  by
       fdopen is closed.  The result of applying fdopen to a shared memory object is unde­
       fined.

       The freopen function opens the file whose name is the string pointed to by path and
       associates  the  stream  pointed  to by stream with it.  The original stream (if it
       exists) is closed.  The mode argument is used just as in the fopen  function.   The
       primary  use  of the freopen function is to change the file associated with a stan­
       dard text stream (stderr, stdin, or stdout).

RETURN VALUE
       Upon successful completion fopen, fdopen and freopen return a FILE pointer.  Other­
       wise,  NULL is returned and the global variable errno is set to indicate the error.

ERRORS
       EINVAL The mode provided to fopen, fdopen, or freopen was invalid.

       The fopen, fdopen and freopen functions may also fail and set errno for any of  the
       errors specified for the routine malloc(3).

       The  fopen function may also fail and set errno for any of the errors specified for
       the routine open(2).

       The fdopen function may also fail and set errno for any of the errors specified for
       the routine fcntl(2).

       The  freopen  function  may also fail and set errno for any of the errors specified
       for the routines open(2), fclose(3) and fflush(3).

CONFORMING TO
       The fopen and freopen functions conform to  ANSI  X3.159-1989  (``ANSI  C'').   The
       fdopen function conforms to IEEE Std1003.1-1988 (``POSIX.1'').

Frage nach 'fclose' mit 'man fclose':

NAME
       fclose - close a stream

SYNOPSIS
       #include <stdio.h>

       int fclose(FILE *stream);

DESCRIPTION
       The fclose function dissociates the named stream from its underlying file or set of
       functions.  If the stream was being used for output, any buffered data  is  written
       first, using fflush(3).

RETURN VALUE
       Upon  successful  completion  0  is  returned.   Otherwise, EOF is returned and the
       global variable errno is set to indicate the error.  In  either  case  any  further
       access  (including  another  call  to  fclose()) to the stream results in undefined
       behaviour.

ERRORS
       EBADF  The filedescriptor underlying stream is not valid.

       The fclose function may also fail and set errno for any of the errors specified for
       the routines close(2), write(2) or fflush(3).

NOTES
       Note  that fclose only flushes the user space buffers provided by the C library. To
       ensure that the data is physically stored  on  disk  the  kernel  buffers  must  be
       flushed too, e.g. with sync(2) or fsync(2).

CONFORMING TO
       The fclose function conforms to ANSI X3.159-1989 (``ANSI C'').

SEE ALSO
       close(2), fcloseall(3), fflush(3), fopen(3), setbuf(3)

 

Auf die Frage 'man fgetc' z.B. bekommt man folgende Informationen:

NAME
       fgetc, fgets, getc, getchar, gets, ungetc - input of characters and strings

 SYNOPSIS
       #include <stdio.h>

       int fgetc(FILE *stream);
       char *fgets(char *s, int size, FILE *stream);
       int getc(FILE *stream);
       int getchar(void);
       char *gets(char *s);
       int ungetc(int c, FILE *stream);

DESCRIPTION
       fgetc()  reads  the  next  character from stream and returns it as an unsigned char
       cast to an int, or EOF on end of file or error.

       getc() is equivalent to fgetc() except that it may be implemented as a macro  which
       evaluates stream more than once.

       getchar() is equivalent to getc(stdin).

       gets()  reads a line from stdin into the buffer pointed to by s until either a ter­
       minating newline or EOF, which it replaces with '\0'.  No check for buffer  overrun
       is performed (see BUGS below).

       fgets()  reads in at most one less than size characters from stream and stores them
       into the buffer pointed to by s.  Reading stops after an EOF or a  newline.   If  a
       newline  is  read,  it  is stored into the buffer.  A '\0' is stored after the last
       character in the buffer.

       ungetc() pushes c back to stream, cast to unsigned char, where it is available  for
       subsequent  read  operations.  Pushed - back characters will be returned in reverse
       order; only one pushback is guaranteed.
    ungetc() pushes c back to stream, cast to unsigned char, where it is available  for
       subsequent  read  operations.  Pushed - back characters will be returned in reverse
       order; only one pushback is guaranteed.

       Calls to the functions described here can be mixed with each other and  with  calls
       to other input functions from the stdio library for the same input stream.

       For non-locking counterparts, see unlocked_stdio(3).

RETURN VALUE
       fgetc(), getc() and getchar() return the character read as an unsigned char cast to
       an int or EOF on end of file or error.

       gets() and fgets() return s on success, and NULL on  error  or  when  end  of  file
       occurs while no characters have been read.

       ungetc() returns c on success, or EOF on error.

CONFORMING TO
       ANSI - C, POSIX.1

BUGS
       Never  use  gets().   Because  it is impossible to tell without knowing the data in
       advance how many characters gets() will read, and because gets() will  continue  to
       store  characters past the end of the buffer, it is extremely dangerous to use.  It
       has been used to break computer security.  Use fgets() instead.

       It is not advisable to mix calls to input functions from the stdio library with low
       -  level  calls to read() for the file descriptor associated with the input stream;
       the results will be undefined and very probably not what you want.

       


START

3. Beispiel zum Dateien Lesen


Das folgende einfache Beispiel demonstriert das Öffnen einer Textdatei zum Lesen mittels der Funktion fgetc().


/*************************
 *
 * i-progr1-th7-dateiread.c
 *
 * author: gdh
 * first: ws01
 * last: nov-11,02
 *
 * idea: Öffnen einer Datei zum Lesen im Textmodus
 *       Ausgabe auf Bildschirm
 *
 * - Das Programm erfragt vom Benutzer einen Dateinamen mit fgets()
 * - Mit diesem Dateinamen wird dann die Datei zum Lesen geöfnet
 * - Die geöffnete Datei wird mit fgetc() asugelesen und die gelesenen Werte werden in
 *   auf dem Bildschirm ausgegeben
 *
 * compilation: gcc -o dateiread dateiread.c
 * usage: dateiread
 *
 ***************************/


#include <stdio.h>
#include <string.h>
#include <errno.h>

main(void){

  int c;
  FILE *fp;                       /* Zeiger vom Typ FILE für Dateioperationen */
  char dname[FILENAME_MAX];     /* Feld für Dateinamen mit maximal möglicher Länge */


  /*****************************************/
  /* ECKWERTE ZU FILENAME_MAX und FOPEN_MAX*/
  /*****************************************/

  printf("FOPEN_MAX = %d\n",FOPEN_MAX);
  printf("FILENAME_MAX = %d\n",FILENAME_MAX);


  /*********************************/
  /* EINGABE DATEINAME */
  /*********************************/

  printf("BITTE DATEINAMN eingeben: ");
 fgets(dname, FILENAME_MAX, stdin);

 dname[strlen(dname)-1]='\0';             /* Steuerzeichen '\n' von fgets() durch '\0' ersetzen */


  /*********************************/
  /* DATEI WIRD ZUM LESEN GEOEFFNET */
   /*********************************/

 errno = 0;                            /* errno ist Fehlervariable; wird vom System gesetzt, wenn Fehler */
  fp = fopen(dname, "r");

  if (errno != 0 ){
    /******************************/
    /* FEHLERBEHANDLUNG */
    /******************************/

     fprintf(stderr,  "open_file(\"%s\") failed: %s\n", dname, strerror(errno));
  }                                    /* strerror() ist eine Fehlerfunktion, die die Fehlernummer kommentiert ausgibt */
  else{
  /*********************************/
  /* AUSLESEN DER DATEI            */
   /*********************************/

      c = fgetc(fp);

      while (c != EOF){

         printf("%c",c);

         c = fgetc(fp);
      }
  }/* End of else */

  /*********************************/
  /* DATEI WIRD GESCHLOSSEN         */
   /*********************************/
  printf("VOR SCHLIESSUNG DATEI\n");


  errno =0;

  if (fclose(fp) != 0) {  fprintf(stderr, "close_file failed: %s\n", strerror(errno)); return (1); }
  else { return (0); }

}





START

4. Fehlervariable 'errno'


Im Programm wird die Fehlervariable 'errno' benutzt. Im Nicht-Fehlerfall hat sie den Wert '0' bzw. sie muss vor Benutzung von Funktionen, die Fehlermeldungen erzeugen können, explizit auf 0 gesetzt werden. Nach Aufruf einer Funktion, die Fehlermeldungen in errno setzen kann, ist errno abzufragen. Dazu kann man die Funktion strerror() benutzen; diese übersetzt die Fehlernummer in einen kurzen erklärenden Text und gibt diesen auf dem Bildschirm aus. Weitere erklärungen zu 'errno' und 'strerror()' kann man wieder über 'man ...' abfragen.

NAME        errno - number of
last error

SYNOPSIS
       #include <errno.h>

       extern int errno;

DESCRIPTION
       The  integer  errno is set by system calls (and some library functions) to indicate
       what went wrong.  Its value is significant only when the  call  returned  an  error
       (usually  -1), and a library function that does succeed is allowed to change errno.

       Sometimes, when -1 is also a legal return value one has to zero  errno  before  the
       call in order to detect possible errors.

       errno  is  defined by the ISO C standard to be a modifiable lvalue of type int, and
       must not be explicitly declared; errno may be a macro.  errno is thread-local; set­
       ting it in one thread does not affect its value in any other thread.

       Valid  error  numbers  are  all non-zero; errno is never set to zero by any library
       function.  All the error names specified by POSIX.1 must have distinct values.

       POSIX.1 (1996 edition) lists the following symbolic error names.   Of  these,  EDOM
       and  ERANGE  are  in  the ISO C standard.  ISO C Amendment 1 defines the additional
       error number EILSEQ for coding errors in multibyte or wide characters.


       E2BIG  Arg list too long

       EACCES Permission denied

       EAGAIN Resource temporarily unavailable

       EBADF  Bad file descriptor

       EBADMSG
              Bad message

       EBUSY  Resource busy

       ECANCELED
              Operation canceled

       ECHILD No child processes

       EDEADLK
              Resource deadlock avoided

       EDOM   Domain error

       EEXIST File exists

       EFAULT Bad address

       EFBIG  File too large

       EINPROGRESS
              Operation in progress

       EINTR  Interrupted function call

       EINVAL Invalid argument

       EIO    Input/output error

       EISDIR Is a directory

       EMFILE Too many open files

       EMLINK Too many links

       EMSGSIZE
              Inappropriate message buffer length

       ENAMETOOLONG
              Filename too long

       ENFILE Too many open files in system

       ENODEV No such device

       ENOENT No such file or directory

       ENOEXEC
              Exec format error

       ENOLCK No locks available

       ENOMEM Not enough space

       ENOSPC No space left on device

       ENOSYS Function not implemented

       ENOTDIR
              Not a directory

       ENOTEMPTY
              Directory not empty

       ENOTSUP
              Not supported

       ENOTTY Inappropriate I/O control operation

       ENXIO  No such device or address

       EPERM  Operation not permitted

       EPIPE  Broken pipe

       ERANGE Result too large
      ENOTEMPTY
              Directory not empty

       ENOTSUP
              Not supported

       ENOTTY Inappropriate I/O control operation

       ENXIO  No such device or address

       EPERM  Operation not permitted

       EPIPE  Broken pipe

       ERANGE Result too large

       EROFS  Read-only file system

       ESPIPE Invalid seek

       ESRCH  No such process

       ETIMEDOUT
              Operation timed out

       EXDEV  Improper link

       Many other error numbers are returned by various Unix  implementations.   System  V
       returns  ETXTBSY  (Text  file busy) if one tries to exec() a file that is currently
       open for writing.  Linux also returns this error if one tries to have a  file  both
       memory mapped with VM_DENYWRITE and open for writing.


SEE ALSO
       perror(3), strerror(3)

Die Anfrage 'man strerror' liefert:

NAME
       strerror, strerror_r - return string describing error code

SYNOPSIS
       #include <string.h>

       char *strerror(int errnum);
       int strerror_r(int errnum, char *buf, size_t n);

DESCRIPTION
       The  strerror()  function  returns a string describing the error code passed in the
       argument errnum, possibly using the LC_MESSAGES  part  of  the  current  locale  to
       select  the appropriate language.  This string must not be modified by the applica­
       tion, but may be modified by a subsequent  call  to  perror()  or  strerror().   No
       library function will modify this string.

       The  strerror_r() function is similar to strerror(), but is thread safe. It returns
       the string in the user-supplied buffer buf of length n.


RETURN VALUE
       The strerror() function returns the appropriate error  description  string,  or  an
       unknown  error  message  if  the  error code is unknown.  The value of errno is not
       changed for a successful call, and is set to a nonzero value upon error.  The  str­
       error_r() function returns 0 on success and -1 on failure, setting errno.


ERRORS
       EINVAL The value of errnum is not a valid error number.

       ERANGE Insufficient storage was supplied to contain the error description string.


CONFORMING TO
       SVID 3, POSIX, BSD 4.3, ISO/IEC 9899:1990 (C89).
SEE ALSO
       errno(3), perror(3), strsignal(3)



START

5. Beispiel zum Anhängen von Daten an eine Datei


In diesem Beispiel betrachten wir den Fall, dass man Text an eine Datei anhängen will. Falls die angegebene Datei noch nicht existiert, wird sie neu angelegt. Existiert sie, wird der Text automatisch an das aktuelle Ende der Datei angehängt. Nach der Eingabe wird ein Kontrollausdruck der neuen kompletten Datei gegeben. Zu diesem Zweck muss aber der Filepointer zunächst auf den Anfang der Datei zurückgesetzt werdem, damit der Kontrollausdruck vom Anfang der Datei liest. Die hierbei benutzten Befehle sinddie folgenden:

  1. fgets(dname, FILENAME_MAX, stdin) zum Einlesen des Dateinamens von der Tastatur


  2. fgets(texteingabe, TEXT_MAX, stdin) zum Einlesen der texteingabe von der Tastatur


  3. fp = fopen(dname, "a+") zum Öffnen einer Datei im Modus 'Anhängen ('append') mit dem Zusatz ('+'), dass sie auch lesbar sein soll


  4. fputs(texteingabe, fp) Schreiben des Textes aus der Variablen 'texteingabe' in die Datei


  5. rewind(fp) Zurücksetzen des Filepointers auf den Anfang der Datei


Für mehr Informationen zu den Funktionen fputs() und rewind() siehe wieder die man-Einträge:

 NAME
fputc, fputs, putc, putchar, puts - output of characters and strings

SYNOPSIS
       #include <stdio.h>

       int fputc(int c, FILE *stream);
       int fputs(const char *s, FILE *stream);
       int putc(int c, FILE *stream);
       int putchar(int c);
       int puts(const char *s);

DESCRIPTION
       fputc() writes the character c, cast to an unsigned char, to stream.

       fputs() writes the string s to stream, without its trailing '\0'.

       putc()  is equivalent to fputc() except that it may be implemented as a macro which
       evaluates stream more than once.

       putchar(c); is equivalent to putc(c,stdout).

       puts() writes the string s and a trailing newline to stdout.

       Calls to the functions described here can be mixed with each other and  with  calls
       to other output functions from the stdio library for the same output stream.

       For non-locking counterparts, see unlocked_stdio(3).

RETURN VALUE
       fputc(), putc() and putchar() return the character written as an unsigned char cast
       to an int or EOF on error.

       puts() and fputs() return a non-negative number on success, or EOF on error.

CONFORMING TO
       ANSI - C, POSIX.1

BUGS
       It is not advisable to mix calls to output functions from the  stdio  library  with
       low  - level calls to write() for the file descriptor associated with the same out­
       put stream; the results will be undefined and very probably not what you want.

SEE ALSO
       write(2),   ferror(3),   fopen(3),   fseek(3),   fwrite(3),   gets(3),    scanf(3),
       unlocked_stdio(3)

 
NAME
       fgetpos, fseek, fsetpos, ftell, rewind - reposition a stream

SYNOPSIS
       #include <stdio.h>

       int fseek(FILE *stream, long offset, int whence);
       long ftell(FILE *stream);
       void rewind(FILE *stream);
       int fgetpos(FILE *stream, fpos_t *pos);
       int fsetpos(FILE *stream, fpos_t *pos);

DESCRIPTION
       The  fseek  function  sets the file position indicator for the stream pointed to by
       stream.  The new position, measured in bytes, is obtained by adding offset bytes to
       the  position  specified  by  whence.   If  whence is set to SEEK_SET, SEEK_CUR, or
       SEEK_END, the offset is relative to the start of the  file,  the  current  position
       indicator,  or  end-of-file, respectively.  A successful call to the fseek function
       clears the end-of-file indicator for the stream  and  undoes  any  effects  of  the
       ungetc(3) function on the same stream.

       The ftell function obtains the current value of the file position indicator for the
       stream pointed to by stream.

       The rewind function sets the file position indicator for the stream pointed  to  by
       stream to the beginning of the file.  It is equivalent to:

              (void)fseek(stream, 0L, SEEK_SET)

       except that the error indicator for the stream is also cleared (see clearerr(3)).

       The  fgetpos and fsetpos functions are alternate interfaces equivalent to ftell and
       fseek (with whence set to SEEK_SET), setting and storing the current value  of  the
       file offset into or from the object referenced by pos.  On some non-UNIX systems an
       fpos_t object may be a complex object and these routines may be  the  only  way  to
       portably reposition a text stream.

RETURN VALUE
       The  rewind function returns no value.  Upon successful completion, fgetpos, fseek,
       fsetpos return 0, and ftell returns the current offset.  Otherwise, -1 is  returned
       and the global variable errno is set to indicate the error.

ERRORS
       EBADF  The stream specified is not a seekable stream.

       EINVAL The whence argument to fseek was not SEEK_SET, SEEK_END, or SEEK_CUR.

       The function fgetpos, fseek, fsetpos, and ftell may also fail and set errno for any
       of the errors specified for the routines fflush(3), fstat(2),  lseek(2),  and  mal­
       loc(3).

CONFORMING TO
       The   fgetpos,  fsetpos,  fseek,  ftell,  and  rewind  functions  conform  to  ANSI
       X3.159-1989 (``ANSI C'').

SEE ALSO
       lseek(2), fseeko(3)






/*************************
 *
 * i-progr1-th7-dateiappend.c
 *
 * author: gdh
 * first: -
 * last: nov-12,02
 *
 * idea: Öffnen einer Datei zum Anhängen von Daten im Textmodus
 *
 * - Das Programm erfragt vom Benutzer einen Dateinamen mit fgets()
 * - Dann wird eine Texteingabe angefordert
 * - Mit dem Dateinamen wird dann die Datei zum Anhängen geöffnet
 * - und der eingelesene Text wird an die Datei angehängt
 *
 * compilation: gcc -o dateiappend dateiappend.c
 * usage: dateiappend
 *
 ***************************/


#include <stdio.h>
#include <string.h>
#include <errno.h>
#define TEXT_MAX 1000

main(void){

  int c,i;
  FILE *fp;                       /* Zeiger vom Typ FILE für Dateioperationen */
  char dname[FILENAME_MAX];     /* Feld für Dateinamen mit maximal möglicher Länge */
  char texteingabe[TEXT_MAX];     /* Feld für TEXTEINGABE  mit maximal möglicher Länge */


  /*****************************************/
  /* ECKWERTE ZU FILENAME_MAX und FOPEN_MAX*/
  /*****************************************/

  printf("FOPEN_MAX = %d\n",FOPEN_MAX);
  printf("FILENAME_MAX = %d\n",FILENAME_MAX);


  /*********************************/
  /* EINGABE DATEINAME */
  /*********************************/

  printf("BITTE DATEINAMN eingeben: ");
 fgets(dname, FILENAME_MAX, stdin);

 dname[strlen(dname)-1]='\0';             /* Steuerzeichen '\n' von fgets() durch '\0' ersetzen */


 /*********************************/
  /* EINGABE TEXT */
  /*********************************/

  printf("BITTE TEXT eingeben: ");
 fgets(texteingabe, TEXT_MAX, stdin);

 texteingabe[strlen(texteingabe)-1]='\0';             /* Steuerzeichen '\n' von fgets() durch '\0' ersetzen */


 /***************************************/
  /* DATEI WIRD ZUM ANHAENGEN GEOEFFNET */
 /***************************************/

 errno = 0;                            /* errno ist Fehlervariable; wird vom System gesetzt, wenn Fehler */
 fp = fopen(dname, "a+");             /* Datei wird zum Anhängen und Lesen geöffnet */

  if (errno != 0 ){
    /******************************/
    /* FEHLERBEHANDLUNG */
    /******************************/

    fprintf(stderr,  "open_file(\"%s\") failed: %s\n", dname, strerror(errno));
  }                                    /* strerror() ist eine Fehlerfunktion, die die Fehlernummer kommentiert ausgibt */
  else{

  /************************************/
  /* ANHAENGEN DER DATEN AN DIE DATEI */
  /************************************/

    printf("TEXT WIRD JETZT ABGESPEICHERT\n\n");

    if( fputs(texteingabe, fp) == EOF ) printf("\n.\nERROR on writing the file\n\n");


    /************************************/
  /* AUSLESEN DER DATEI ZUR KONTROLLE   */
    /*************************************/

    printf("AUSLESEN DER DATEI ZUR KONTROLLE\n\n");

    rewind(fp);                      /* Setzt den Filepointer wieder auf den Anfang */

      c = fgetc(fp);

      while (c != EOF) {

         printf("%c",c);

         c = fgetc(fp);
        }


  }/* End of else */

  /*********************************/
  /* DATEI WIRD GESCHLOSSEN         */
   /*********************************/
  printf("\n\nVOR SCHLIESSUNG DATEI\n");


  errno =0;

  if (fclose(fp) != 0) {  fprintf(stderr, "close_file failed: %s\n", strerror(errno)); return (1); }
  else {  printf("\n\nNACH  SCHLIESSUNG DER DATEI\n"); return (0); }

}








START

6. Entfernen und Umbenennen von Dateien


Es soll an dieser stelle nur darauf hingewiessen werden, dass man von C aus auch Dateien mit remove() entfernen bzw. mit rename() auch umbenennen kann.

NAME
       rename - change the name or location of a file

SYNOPSIS
       #include <stdio.h>

       int rename(const char *oldpath, const char *newpath);

DESCRIPTION
       rename renames a file, moving it between directories if required.

       Any other hard links to the file (as created using link(2)) are unaffected.

       If  newpath  already exists it will be atomically replaced (subject to a few condi­
       tions - see ERRORS below), so that there is  no  point  at  which  another  process
       attempting to access newpath will find it missing.

       If  newpath  exists  but  the  operation fails for some reason rename guarantees to
       leave an instance of newpath in place.

       However, when overwriting there will probably be a window in which both oldpath and
       newpath refer to the file being renamed.

       If  oldpath  refers  to a symbolic link the link is renamed; if newpath refers to a
       symbolic link the link will be overwritten.

RETURN VALUE
       On success, zero is returned.  On error, -1 is returned, and errno is set appropri­
       ately.

ERRORS
       EISDIR newpath is an existing directory, but oldpath is not a directory.

       EXDEV  oldpath and newpath are not on the same filesystem.
    ENOTEMPTY or EEXIST
              newpath  is a non-empty directory, i.e., contains entries other than "." and
              "..".

       EBUSY  The rename fails because oldpath or newpath is a directory that is in use by
              some process (perhaps as current working directory, or as root directory, or
              because it was open for reading) or is in use by the system (for example  as
              mount point), while the system considers this an error.  (Note that there is
              no requirement to return EBUSY in such cases - there is nothing  wrong  with
              doing  the  rename  anyway - but it is allowed to return EBUSY if the system
              cannot otherwise handle such situations.)

       EINVAL The new pathname contained a path prefix of the old, or, more generally,  an
              attempt was made to make a directory a subdirectory of itself.

       EMLINK oldpath already has the maximum number of links to it, or it was a directory
              and the directory containing newpath has the maximum number of links.

       ENOTDIR
              A component used as a directory in oldpath or newpath is  not,  in  fact,  a
              directory.   Or,  oldpath  is  a  directory, and newpath exists but is not a
              directory.

       EFAULT oldpath or newpath points outside your accessible address space.

       EACCES Write access to the directory containing oldpath or newpath is  not  allowed
              for  the  process's  effective  uid, or one of the directories in oldpath or
              newpath did not allow search (execute) permission, or oldpath was  a  direc­
              tory and did not allow write permission (needed to update the ..  entry).

       EPERM or EACCES
              The  directory  containing  oldpath has the sticky bit set and the process's
              effective uid is neither that of root nor the uid of the file to be  deleted
              nor  that of the directory containing it, or newpath is an existing file and
              the directory containing it has the sticky bit set and the process's  effec­
              tive  uid is neither that of root nor the uid of the file to be replaced nor
              that of the directory containing it, or the filesystem  containing  pathname
              does not support renaming of the type requested.

       ENAMETOOLONG
              oldpath or newpath was too long.

       ENOENT A  directory  component  in oldpath  or  newpath does not exist or is a dan­
              gling symbolic link.

       ENOMEM Insufficient kernel memory was available.

       EROFS  The file is on a read-only filesystem.

       ELOOP  Too many symbolic links were encountered in resolving oldpath or newpath.

       ENOSPC The device containing the file has no room for the new directory entry.

CONFORMING TO
       POSIX, 4.3BSD, ANSI C

BUGS
       On NFS filesystems, you can not assume that if the operation failed  the  file  was
       not  renamed.   If  the  server  does  the  rename  operation and then crashes, the
       retransmitted RPC which will be processed when the server  is  up  again  causes  a
       failure.  The application is expected to deal with this.  See link(2) for a similar
       problem.

SEE ALSO
       link(2), unlink(2), symlink(2), mv(1)

 NAME
       remove - delete a name and possibly the file it refers to

SYNOPSIS
       #include <stdio.h>

       int remove(const char *pathname);

DESCRIPTION
       remove  deletes  a  name from the filesystem.  It calls unlink for files, and rmdir
       for directories.

       If the removed name was the last link to a file and no processes have the file open
       the file is deleted and the space it was using is made available for reuse.

       If  the name was the last link to a file but any processes still have the file open
       the file will remain in existence until the last file descriptor referring to it is
       closed.

       If the name referred to a symbolic link the link is removed.

       If  the  name  referred  to a socket, fifo or device the name for it is removed but
       processes which have the object open may continue to use it.

RETURN VALUE
       On success, zero is returned.  On error, -1 is returned, and errno is set appropri­
       ately.

ERRORS
       EFAULT pathname points outside your accessible address space.

       EACCES Write  access  to  the  directory containing pathname is not allowed for the
              process's effective uid, or one of the directories in pathname did not allow
              search (execute) permission.
     EACCES Write  access  to  the  directory containing pathname is not allowed for the
              process's effective uid, or one of the directories in pathname did not allow
              search (execute) permission.

       EPERM  The  directory  containing pathname has the sticky-bit (S_ISVTX) set and the
              process's effective uid is neither the uid of the file  to  be  deleted  nor
              that of the directory containing it.

       ENAMETOOLONG
              pathname was too long.

       ENOENT A  directory  component in pathname does not exist or is a dangling symbolic
              link.

       ENOTDIR
              A component used as a directory in pathname is not, in fact, a directory.

       ENOMEM Insufficient kernel memory was available.

       EROFS  pathname refers to a file on a read-only filesystem.

CONFORMING TO
       ANSI C, SVID, AT&T, POSIX, X/OPEN, BSD 4.3

BUGS
       Infelicities in the protocol underlying NFS can cause the unexpected  disappearance
       of files which are still being used.

NOTE
       Under  libc4  and libc5, remove was an alias for unlink (and hence would not remove
       directories).

SEE ALSO
       unlink(2), rename(2),  open(2),  rmdir(2),  mknod(2),  mkfifo(3),  link(2),  rm(1),
       unlink(8)




START


START

7. Übungsaufgaben

  1. Bilden sie ein Team von 3 Mitgliedern


  2. Erstellung Sie gemeinsam einen Texte mit Namen und Matr.Nr. der AutorenInnen. Abgabe einer Kopie des Textes an den Dozenten vor Beginn der Vorlesung am Di (1 Woche nach Aufgabenstellung). Falls die Aufgabe ausführbaren Programmcode enthält wäre die zusätzliche Übergabe des Quelltextes auf Diskette oder per email wünschenswert, aber nicht verbindlich. Im Falle von Programmcode muss im Programmtext auch nochmals Name und Matr.Nr. erscheinen.


  3. Präsentation der Lösung als Team vor der gesamten Gruppe. Präsentationszeit (abhängig von der Gesamtzahl der Teams) 3-5 Min. Mögliche Punkte: 1-2 im Normalfall. Bei besonders guten Leistungen bis zu 3 Punkten.


  4. Versuchen Sie in dem Text Antworten auf folgende Aufgaben zu formulieren:


  5. Das Thema Sicherheit ist heutzutage sehr wichtig. Ein Teilbereich in diesem Thema sind z.B. 'sichere' Passwörter. Es soll ein einfaches Programm geschrieben werden, das demonstrieren soll, wie leicht bzw. wie schwer es ist, ein Passwort zu knacken. Realisieren Sie folgenden experimentellen Aufbau:


    1. Legen sie eine Textdatei an, in der sie eine Reihe von Passwörter hineinschreiben, getrennt durch SPACE (=Leerzeichen, ASCII-Kode dezimal 32). Benutzen sie nur Kleinbuchstaben 'a,b, ..., z'. Beginnen sie mit der Länge 2, und steigern Sie die Länge bis zu einer Zahl, die Ihren Computer eine von Ihnen festgelegte maximale Zeit rechnen lässt.


    2. Das Programm selbst soll folgende Aufgaben erfüllen:


      1. Sie lesen das nächste Wort w aus Ihrer Testdatei mit den Passwörtern


      2. Mit dem Zufallsgenerator rand() erzeugen Sie ein hypothetisches Wort w' von der gleichen Länge wie das Testwort w


      3. Falls (w' == w) WAHR, dann schreiben Sie die Anzahl der Versuche, die der Zufallsgenerator benötigt hat, um w zu 'erkennen', in eine Ergabnisdatei mit folgendem Format: TESTWORT : BENÖTIGTE ANZAHL VON VERSUCHEN;


      4. Falls (w' == w) FALSCH, dann erzeugen Sie ein neues hypothetisches Wort w' von der gleichen Länge wie das Testwort w und prüfen auf Erfolg.


      5. Wenn sie alle Testworte aus Ihrer Datei abgearbeitet haben bzw. bis Ihr Computer die maximale Anzahl von Durchgängen erreicht hat, die Sie zulassen wollen, dann geben Sie die Ergebnisdatei mit allen Ergebissen auf dem Bildschirm aus.



START