Как прочитать содержимое файла в строку в C? - PullRequest
73 голосов
/ 06 октября 2008

Каким самым простым способом (наименее подверженным ошибкам, наименьшим количеством строк кода, однако вы хотите его интерпретировать) открыть файл в C и прочитать его содержимое в строку (char *, char [] и т. Д.)?

Ответы [ 9 ]

114 голосов
/ 06 октября 2008

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

Это заглушка, которую я использую для этого. Вы также можете проверить коды ошибок для fseek, ftell и fread. (опущено для ясности).

char * buffer = 0;
long length;
FILE * f = fopen (filename, "rb");

if (f)
{
  fseek (f, 0, SEEK_END);
  length = ftell (f);
  fseek (f, 0, SEEK_SET);
  buffer = malloc (length);
  if (buffer)
  {
    fread (buffer, 1, length, f);
  }
  fclose (f);
}

if (buffer)
{
  // start to process your data / extract strings here...
}
22 голосов
/ 06 октября 2008

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

Код POSIX будет выглядеть так:

int fd = open("filename", O_RDONLY);
int len = lseek(fd, 0, SEEK_END);
void *data = mmap(0, len, PROT_READ, MAP_PRIVATE, fd, 0);

Windows, с другой стороны, немного сложнее, и, к сожалению, у меня нет перед собой компилятора для тестирования, но функциональность обеспечивается CreateFileMapping() и MapViewOfFile().

8 голосов
/ 06 октября 2008

Если «прочитать его содержимое в строку» означает, что файл не содержит символов с кодом 0, вы также можете использовать функцию getdelim (), которая либо принимает блок памяти и перераспределяет его при необходимости, либо просто выделяет весь буфер для вас и считывает файл в него, пока не встретит указанный разделитель или конец файла. Просто передайте '\ 0' в качестве разделителя, чтобы прочитать весь файл.

Эта функция доступна в библиотеке GNU C, http://www.gnu.org/software/libc/manual/html_mono/libc.html#index-getdelim-994

Пример кода может выглядеть так просто, как

char* buffer = NULL;
size_t len;
ssize_t bytes_read = getdelim( &buffer, &len, '\0', fp);
if ( bytes_read != -1) {
  /* Success, now the entire file is in the buffer */
5 голосов
/ 24 ноября 2013

Если вы читаете специальные файлы, такие как stdin или pipe, вы не сможете использовать fstat для получения размера файла заранее. Кроме того, если вы читаете двоичный файл, fgets потеряет информацию о размере строки из-за встроенных символов '\ 0'. Лучший способ прочитать файл - использовать read и realloc:

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

int main () {
    char buf[4096];
    ssize_t n;
    char *str = NULL;
    size_t len = 0;
    while (n = read(STDIN_FILENO, buf, sizeof buf)) {
        if (n < 0) {
            if (errno == EAGAIN)
                continue;
            perror("read");
            break;
        }
        str = realloc(str, len + n + 1);
        memcpy(str + len, buf, n);
        len += n;
        str[len] = '\0';
    }
    printf("%.*s\n", len, str);
    return 0;
}
5 голосов
/ 09 октября 2008

Если файл текстовый, и вы хотите получать текст построчно, проще всего использовать fgets ().

char buffer[100];
FILE *fp = fopen("filename", "r");                 // do not use "rb"
while (fgets(buffer, sizeof(buffer), fp)) {
... do something
}
fclose(fp);
1 голос
/ 06 января 2019

Примечание: это модификация принятого ответа выше.

Вот способ сделать это с проверкой ошибок.

Я добавил проверку размера, чтобы выйти, когда файл был больше 1 ГиБ. Я сделал это, потому что программа помещает весь файл в строку, которая может использовать слишком много оперативной памяти и сбить компьютер. Однако, если вас это не волнует, вы можете просто удалить его из кода.

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

#define FILE_OK 0
#define FILE_NOT_EXIST 1
#define FILE_TO_LARGE 2
#define FILE_READ_ERROR 3

char * c_read_file(const char * f_name, int * err, size_t * f_size) {
    char * buffer;
    size_t length;
    FILE * f = fopen(f_name, "rb");
    size_t read_length;

    if (f) {
        fseek(f, 0, SEEK_END);
        length = ftell(f);
        fseek(f, 0, SEEK_SET);

        // 1 GiB; best not to load a hole large file in one string
        if (length > 1073741824) {
            *err = FILE_TO_LARGE;

            return NULL;
        }

        buffer = (char *)malloc(length + 1);

        if (length) {
            read_length = fread(buffer, 1, length, f);

            if (length != read_length) {
                 *err = FILE_READ_ERROR;

                 return NULL;
            }
        }

        fclose(f);

        *err = FILE_OK;
        buffer[length] = '\0';
        *f_size = length;
    }
    else {
        *err = FILE_NOT_EXIST;

        return NULL;
    }

    return buffer;
}

И для проверки ошибок:

int err;
size_t f_size;
char * f_data;

f_data = c_read_file("test.txt", &err, &f_size);

if (err) {
    // process error
}
1 голос
/ 07 октября 2016

Если вы используете glib, то вы можете использовать g_file_get_contents ;

gchar *contents;
GError *err = NULL;

g_file_get_contents ("foo.txt", &contents, NULL, &err);
g_assert ((contents == NULL && err != NULL) || (contents != NULL && err == NULL));
if (err != NULL)
  {
    // Report error to user, and free error
    g_assert (contents == NULL);
    fprintf (stderr, "Unable to read file: %s\n", err->message);
    g_error_free (err);
  }
else
  {
    // Use file contents
    g_assert (contents != NULL);
  }
}
0 голосов
/ 09 ноября 2017

Только что изменено с принятого ответа выше.

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

char *readFile(char *filename) {
    FILE *f = fopen(filename, "rt");
    assert(f);
    fseek(f, 0, SEEK_END);
    long length = ftell(f);
    fseek(f, 0, SEEK_SET);
    char *buffer = (char *) malloc(length + 1);
    buffer[length] = '\0';
    fread(buffer, 1, length, f);
    fclose(f);
    return buffer;
}

int main() {
    char *content = readFile("../hello.txt");
    printf("%s", content);
}
0 голосов
/ 15 мая 2016
// Assumes the file exists and will seg. fault otherwise.
const GLchar *load_shader_source(char *filename) {
  FILE *file = fopen(filename, "r");             // open 
  fseek(file, 0L, SEEK_END);                     // find the end
  size_t size = ftell(file);                     // get the size in bytes
  GLchar *shaderSource = calloc(1, size);        // allocate enough bytes
  rewind(file);                                  // go back to file beginning
  fread(shaderSource, size, sizeof(char), file); // read each char into ourblock
  fclose(file);                                  // close the stream
  return shaderSource;
}

Это довольно грубое решение, потому что ничего не проверяется на ноль.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...