Поиск…


Синтаксис

  • #include <stdio.h> / * Включите это, чтобы использовать любой из следующих разделов * /
  • FILE * fopen (const char * path, const char * mode); / * Открыть поток по файлу по пути с указанным режимом * /
  • FILE * freopen (const char * path, const char * mode, FILE * stream); / * Повторно открыть существующий поток в файле по пути с указанным режимом * /
  • int fclose (поток FILE *); / * Закрыть открытый поток * /
  • size_t fread (void * ptr, size_t size, size_t nmemb, поток FILE *); / * Прочитайте максимум nmemb элементов байтов размера каждый из потока и напишите их в ptr . Возвращает количество элементов чтения. * /
  • size_t fwrite (const void * ptr, size_t size, size_t nmemb, поток FILE *); / * Напишите nmemb элементы байтов размера каждый из ptr в поток . Возвращает количество написанных элементов. * /
  • int fseek (поток FILE *, длинное смещение, int whence); / * Установите курсор потока для смещения относительно смещения , указанного командой whence , и вернет 0, если это удалось. * /
  • long ftell (поток FILE *); / * Возвращает смещение текущей позиции курсора от начала потока. * /
  • void rewind (поток FILE *); / * Установите позицию курсора в начало файла. * /
  • int fprintf (FILE * fout, const char * fmt, ...); / * Записывает строку формата printf в fout * /
  • FILE * stdin; / * Стандартный поток ввода * /
  • FILE * stdout; / * Стандартный выходной поток * /
  • FILE * stderr; / * Стандартный поток ошибок * /

параметры

параметр подробности
const char * mode Строка, описывающая режим открытия потока с файловой поддержкой. См. Замечания для возможных значений.
int откуда Может быть SEEK_SET для установки с начала файла SEEK_END для установки с его конца или SEEK_CUR для установки относительно текущего значения курсора. Примечание. SEEK_END не переносится.

замечания

Строки режима:

Модификации режима в fopen() и freopen() могут быть одним из следующих значений:

  • "r" : открыть файл в режиме только для чтения, при этом курсор установлен в начало файла.
  • "r+" : открыть файл в режиме чтения-записи, при этом курсор установлен в начало файла.
  • "w" : открыть или создать файл в режиме только для записи, при этом его содержимое обрезается до 0 байтов. Курсор установлен в начало файла.
  • "w+" : открыть или создать файл в режиме чтения-записи, при этом его содержимое обрезается до 0 байтов. Курсор установлен в начало файла.
  • "a" : открыть или создать файл в режиме только записи, при этом курсор установлен в конец файла.
  • "a+" : открыть или создать файл в режиме чтения-записи, при этом указатель чтения установлен в начало файла. Выход, однако, всегда будет добавлен в конец файла.

Каждый из этих файловых режимов может иметь b добавленный после начальной буквы (например, "rb" или "a+b" или "ab+" ). b означает, что файл следует рассматривать как двоичный файл вместо текстового файла в тех системах, где есть разница. Это не влияет на Unix-подобные системы; это важно для систем Windows. (Кроме того, Windows fopen позволяет явному t вместо b указывать «текстовый файл» и множество других параметров для конкретной платформы.)

C11
  • "wx" : создать текстовый файл в режиме только для записи. Файл может не существовать .
  • "wbx" : создать двоичный файл в режиме только для записи. Файл может не существовать .

x , если присутствует, должен быть последним символом в строке режима.

Открыть и записать в файл

#include <stdio.h>   /* for perror(), fopen(), fputs() and fclose() */
#include <stdlib.h>  /* for the EXIT_* macros */
 
int main(int argc, char **argv)
{
    int e = EXIT_SUCCESS;

    /* Get path from argument to main else default to output.txt */
    char *path = (argc > 1) ? argv[1] : "output.txt";

    /* Open file for writing and obtain file pointer */
    FILE *file = fopen(path, "w");
    
    /* Print error message and exit if fopen() failed */
    if (!file) 
    {
        perror(path);
        return EXIT_FAILURE;
    }

    /* Writes text to file. Unlike puts(), fputs() does not add a new-line. */
    if (fputs("Output in file.\n", file) == EOF)
    {
        perror(path);
        e = EXIT_FAILURE;
    }

    /* Close file */
    if (fclose(file)) 
    {
        perror(path);
        return EXIT_FAILURE;
    }
    return e;
}

Эта программа открывает файл с именем, указанным в аргументе main, по output.txt для output.txt если аргумент не указан. Если файл с тем же именем уже существует, его содержимое отбрасывается, и файл рассматривается как новый пустой файл. Если файлы еще не существуют, создается вызов fopen() .

Если по какой-либо причине вызов fopen() завершился с ошибкой, он возвращает значение NULL и устанавливает значение глобальной переменной errno . Это означает, что программа может проверить возвращаемое значение после вызова fopen() и использовать perror() если fopen() терпит неудачу.

Если вызов fopen() завершается успешно, он возвращает действительный указатель FILE . Этот указатель затем может использоваться для ссылки на этот файл до тех пор, пока на нем не будет fclose() .

Функция fputs() записывает данный текст в открытый файл, заменяя любое предыдущее содержимое файла. Аналогично функции fopen() функция fputs() также устанавливает значение errno если она терпит неудачу, хотя в этом случае функция возвращает EOF для указания отказа (иначе он возвращает неотрицательное значение).

Функция fclose() сбрасывает любые буферы, закрывает файл и освобождает память, на которую указывает FILE * . Возвращаемое значение указывает на завершение так же, как и fputs() (хотя при успешном завершении возвращает «0»), снова также устанавливая значение errno в случае сбоя.

fprintf

Вы можете использовать fprintf в файле так же, как на консоли с printf . Например, чтобы отслеживать выигрыши игр, потери и связи, которые вы могли бы написать

/* saves wins, losses and, ties */
void savewlt(FILE *fout, int wins, int losses, int ties)
{
    fprintf(fout, "Wins: %d\nTies: %d\nLosses: %d\n", wins, ties, losses);
}

Замечание: некоторые системы (печально, Windows) не используют то, что большинство программистов назвали бы «нормальными» окончаниями строк. Хотя UNIX-подобные системы используют \ n для завершения строк, Windows использует пару символов: \ r (возврат каретки) и \ n (строка). Эта последовательность обычно называется CRLF. Однако при использовании C вам не нужно беспокоиться об этих деталях, зависящих от платформы. AC-компилятор необходим для преобразования каждого экземпляра \ n в правильную конечную строку платформы. Поэтому компилятор Windows будет конвертировать \ n в \ r \ n, но компилятор UNIX сохранит его как есть.

Выполнить процесс

#include <stdio.h>

void print_all(FILE *stream)
{
    int c;
    while ((c = getc(stream)) != EOF)
        putchar(c);
}
int main(void)
{
    FILE *stream;

    /* call netstat command. netstat is available for Windows and Linux */
    if ((stream = popen("netstat", "r")) == NULL)
        return 1;
  
    print_all(stream);
    pclose(stream);
    return 0;
}

Эта программа запускает процесс ( netstat ) через popen() и считывает весь стандартный вывод процесса и выводит его на стандартный вывод.

Примечание: popen() не существует в стандартной библиотеке C , но это скорее часть POSIX C )

Получить строки из файла с помощью getline ()

Библиотека POSIX C определяет функцию getline() . Эта функция выделяет буфер для хранения содержимого строки и возвращает новую строку, количество символов в строке и размер буфера.

Пример программы, которая получает каждую строку из example.txt :

#include <stdlib.h>
#include <stdio.h>  


#define FILENAME "example.txt"

int main(void)
{
  /* Open the file for reading */
  char *line_buf = NULL;
  size_t line_buf_size = 0;
  int line_count = 0;
  ssize_t line_size;
  FILE *fp = fopen(FILENAME, "r");
  if (!fp)
  {
    fprintf(stderr, "Error opening file '%s'\n", FILENAME);
    return EXIT_FAILURE;
  }

  /* Get the first line of the file. */
  line_size = getline(&line_buf, &line_buf_size, fp);

  /* Loop through until we are done with the file. */
  while (line_size >= 0)
  {
    /* Increment our line count */
    line_count++;

    /* Show the line details */
    printf("line[%06d]: chars=%06zd, buf size=%06zu, contents: %s", line_count,
        line_size, line_buf_size, line_buf);

    /* Get the next line */
    line_size = getline(&line_buf, &line_buf_size, fp);
  }

  /* Free the allocated line buffer */
  free(line_buf);
  line_buf = NULL;

  /* Close the file now that we are done with it */
  fclose(fp);

  return EXIT_SUCCESS;
}

Входной файл example.txt

This is a file
  which has
multiple lines
    with various indentation,
blank lines



a really long line to show that getline() will reallocate the line buffer if the length of a line is too long to fit in the buffer it has been given,
  and punctuation at the end of the lines.

Выход

line[000001]: chars=000015, buf size=000016, contents: This is a file
line[000002]: chars=000012, buf size=000016, contents:   which has
line[000003]: chars=000015, buf size=000016, contents: multiple lines
line[000004]: chars=000030, buf size=000032, contents:     with various indentation,
line[000005]: chars=000012, buf size=000032, contents: blank lines
line[000006]: chars=000001, buf size=000032, contents: 
line[000007]: chars=000001, buf size=000032, contents: 
line[000008]: chars=000001, buf size=000032, contents: 
line[000009]: chars=000150, buf size=000160, contents: a really long line to show that getline() will reallocate the line buffer if the length of a line is too long to fit in the buffer it has been given,
line[000010]: chars=000042, buf size=000160, contents:  and punctuation at the end of the lines.
line[000011]: chars=000001, buf size=000160, contents: 

В этом примере getline() изначально вызывается без выделенного буфера. Во время этого первого вызова getline() выделяет буфер, считывает первую строку и помещает содержимое строки в новый буфер. При последующих вызовах getline() обновляет один и тот же буфер и перераспределяет буфер только тогда, когда он больше не достаточно большой, чтобы соответствовать всей строке. Затем временный буфер освобождается, когда мы закончили с файлом.

Другой вариант - getdelim() . Это то же самое, что и getline() за исключением указания символа окончания строки. Это необходимо, только если последний символ строки для вашего типа файла не является \ n. getline() работает даже с текстовыми файлами Windows, потому что с завершением многобайтовой строки ( "\r\n") '\ n'` по-прежнему остается последним символом в строке.

Пример реализации getline()

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <stdint.h>


#if !(defined _POSIX_C_SOURCE)
typedef long int ssize_t;
#endif

/* Only include our version of getline() if the POSIX version isn't available. */

#if !(defined _POSIX_C_SOURCE) || _POSIX_C_SOURCE < 200809L

#if !(defined SSIZE_MAX)
#define SSIZE_MAX (SIZE_MAX >> 1)
#endif

ssize_t getline(char **pline_buf, size_t *pn, FILE *fin)
{
  const size_t INITALLOC = 16;
  const size_t ALLOCSTEP = 16;
  size_t num_read = 0;

  /* First check that none of our input pointers are NULL. */
  if ((NULL == pline_buf) || (NULL == pn) || (NULL == fin))
  {
    errno = EINVAL;
    return -1;
  }

  /* If output buffer is NULL, then allocate a buffer. */
  if (NULL == *pline_buf)
  {
    *pline_buf = malloc(INITALLOC);
    if (NULL == *pline_buf)
    {
      /* Can't allocate memory. */
      return -1;
    }
    else
    {
      /* Note how big the buffer is at this time. */
      *pn = INITALLOC;
    }
  }

  /* Step through the file, pulling characters until either a newline or EOF. */

  {
    int c;
    while (EOF != (c = getc(fin)))
    {
      /* Note we read a character. */
      num_read++;

      /* Reallocate the buffer if we need more room */
      if (num_read >= *pn)
      {
        size_t n_realloc = *pn + ALLOCSTEP;
        char * tmp = realloc(*pline_buf, n_realloc + 1); /* +1 for the trailing NUL. */
        if (NULL != tmp)
        {
          /* Use the new buffer and note the new buffer size. */
          *pline_buf = tmp;
          *pn = n_realloc;
        }
        else
        {
          /* Exit with error and let the caller free the buffer. */
          return -1;
        }

        /* Test for overflow. */
        if (SSIZE_MAX < *pn)
        {
          errno = ERANGE;
          return -1;
        }
      }

      /* Add the character to the buffer. */
      (*pline_buf)[num_read - 1] = (char) c;

      /* Break from the loop if we hit the ending character. */
      if (c == '\n')
      {
        break;
      }
    }

    /* Note if we hit EOF. */
    if (EOF == c)
    {
      errno = 0;
      return -1;
    }
  }

  /* Terminate the string by suffixing NUL. */
  (*pline_buf)[num_read] = '\0';

  return (ssize_t) num_read;
}

#endif

Открыть и записать в двоичный файл

#include <stdlib.h>
#include <stdio.h>


int main(void)
{
   result = EXIT_SUCCESS;

   char file_name[] = "outbut.bin";
   char str[] = "This is a binary file example";
   FILE * fp = fopen(file_name, "wb");
   
   if (fp == NULL)  /* If an error occurs during the file creation */
   {
     result = EXIT_FAILURE;
     fprintf(stderr, "fopen() failed for '%s'\n", file_name);
   }
   else
   {
     size_t element_size = sizeof *str;
     size_t elements_to_write = sizeof str;

     /* Writes str (_including_ the NUL-terminator) to the binary file. */
     size_t elements_written = fwrite(str, element_size, elements_to_write, fp); 
     if (elements_written != elements_to_write)
     {
       result = EXIT_FAILURE;
       /* This works for >=c99 only, else the z length modifier is unknown. */
       fprintf(stderr, "fwrite() failed: wrote only %zu out of %zu elements.\n", 
         elements_written, elements_to_write);
       /* Use this for <c99: *
       fprintf(stderr, "fwrite() failed: wrote only %lu out of %lu elements.\n", 
         (unsigned long) elements_written, (unsigned long) elements_to_write);
        */
     }

     fclose(fp);
   }

   return result;
}

Эта программа создает и записывает текст в двоичной форме через функцию fwrite в файл output.bin .

Если файл с тем же именем уже существует, его содержимое отбрасывается, и файл рассматривается как новый пустой файл.

Бинарный поток представляет собой упорядоченную последовательность символов, которая может прозрачно записывать внутренние данные. В этом режиме байты записываются между программой и файлом без какой-либо интерпретации.

Чтобы записывать целые числа переносимым образом, необходимо знать, ожидает ли формат файла их в формате большой или малой длины, а также размер (обычно 16, 32 или 64 бита). Бит-сдвиг и маскирование могут затем использоваться для записи байтов в правильном порядке. Целые числа в C не гарантируют наличие двух дополняющих представлений (хотя почти все реализации выполняются). К счастью, преобразование в беззнаковый гарантированно использовать двойки комплемента. Поэтому код для записи знакового целого в двоичный файл немного удивителен.

/* write a 16-bit little endian integer */
int fput16le(int x, FILE *fp)
{
    unsigned int rep = x;
    int e1, e2;

    e1 = fputc(rep & 0xFF, fp);
    e2 = fputc((rep >> 8) & 0xFF, fp);

    if(e1 == EOF || e2 == EOF)
        return EOF;
    return 0;  
}

Другие функции следуют одному и тому же шаблону с незначительными изменениями для размера и порядка байтов.

fscanf ()

Предположим, у нас есть текстовый файл, и мы хотим прочитать все слова в этом файле, чтобы выполнить некоторые требования.

file.txt :

This is just
a test file
to be used by fscanf()

Это основная функция:

#include <stdlib.h>
#include <stdio.h>

void printAllWords(FILE *);

int main(void)
{
  FILE *fp;

  if ((fp = fopen("file.txt", "r")) == NULL) {
      perror("Error opening file");
      exit(EXIT_FAILURE);
  }

  printAllWords(fp);

  fclose(fp);
  
  return EXIT_SUCCESS;
}

void printAllWords(FILE * fp)
{
    char tmp[20];
    int i = 1;

    while (fscanf(fp, "%19s", tmp) != EOF) {
        printf("Word %d: %s\n", i, tmp);
        i++;
    }
}

Выход будет:

Word 1: This 
Word 2: is 
Word 3: just
Word 4: a 
Word 5: test
Word 6: file
Word 7: to
Word 8: be 
Word 9: used
Word 10: by
Word 11: fscanf()

Чтение строк из файла

Заголовок stdio.h определяет функцию fgets() . Эта функция считывает строку из потока и сохраняет ее в указанной строке. Функция прекращает чтение текста из потока, когда считывается n - 1 символ, читается символ новой строки ( '\n' ) или заканчивается конец файла (EOF).

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

#define MAX_LINE_LENGTH 80

int main(int argc, char **argv)
{
    char *path;
    char line[MAX_LINE_LENGTH] = {0};
    unsigned int line_count = 0;
    
    if (argc < 1)
        return EXIT_FAILURE;
    path = argv[1];
    
    /* Open file */
    FILE *file = fopen(path, "r");
    
    if (!file)
    {
        perror(path);
        return EXIT_FAILURE;
    }
    
    /* Get each line until there are none left */
    while (fgets(line, MAX_LINE_LENGTH, file))
    {
        /* Print each line */
        printf("line[%06d]: %s", ++line_count, line);
        
        /* Add a trailing newline to lines that don't already have one */
        if (line[strlen(line) - 1] != '\n')
            printf("\n");
    }
    
    /* Close file */
    if (fclose(file))
    {
        return EXIT_FAILURE;
        perror(path);
    }
}

Вызов программы с аргументом, который представляет собой путь к файлу, содержащему следующий текст:

This is a file
  which has
multiple lines
    with various indentation,
blank lines



a really long line to show that the line will be counted as two lines if the length of a line is too long to fit in the buffer it has been given,
  and punctuation at the end of the lines.

Результатом будет следующий вывод:

line[000001]: This is a file
line[000002]:   which has
line[000003]: multiple lines
line[000004]:     with various indentation,
line[000005]: blank lines
line[000006]: 
line[000007]: 
line[000008]: 
line[000009]: a really long line to show that the line will be counted as two lines if the le
line[000010]: ngth of a line is too long to fit in the buffer it has been given,
line[000011]:  and punctuation at the end of the lines.
line[000012]: 

Этот очень простой пример позволяет фиксированную максимальную длину строки, так что более длинные строки будут эффективно считаться двумя строками. Функция fgets() требует, чтобы вызывающий код предоставлял память, которая будет использоваться в качестве адресата для прочитанной строки.

POSIX делает доступной функцию getline() которая вместо этого внутренне выделяет память, чтобы увеличить буфер, если необходимо, для линии любой длины (при условии, что имеется достаточная память).



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow