Подтвердить что ты не робот

Как прочитать содержимое файла в строку в C?

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

4b9b3361

Ответ 1

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

Это заглушка, которую я использую для этого. вы также можете проверить коды ошибок для 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...
}

Ответ 2

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

Код 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().

Ответ 3

Если "прочитать его содержимое в строку" означает, что файл не содержит символов с кодом 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 */

Ответ 4

Если файл является текстовым, и вы хотите получить текст за строкой, самый простой способ - использовать fgets().

char buffer[100];
FILE *fp = fopen("filename", "r");                 // do not use "rb"
while (fgets(buffer, sizeof(buffer), fp)) {
... do something
}
fclose(fp);

Ответ 5

Если вы читаете специальные файлы, такие как 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;
}

Ответ 6

Примечание: это изменение принятого ответа выше.

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

Я добавил проверку размера, чтобы выйти, когда файл был больше 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
}

Ответ 7

Если вы используете 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);
  }
}

Ответ 8

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

#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);
}

Ответ 9

// 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;
}

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

Ответ 10

Я добавлю свою версию, основываясь на ответах здесь, просто для справки. Мой код учитывает sizeof (char) и добавляет к нему несколько комментариев.

// Open the file in read mode.
FILE *file = fopen(file_name, "r");
// Check if there was an error.
if (file == NULL) {
    fprintf(stderr, "Error: Can't open file '%s'.", file_name);
    exit(EXIT_FAILURE);
}
// Get the file length
fseek(file, 0, SEEK_END);
long length = ftell(file);
fseek(file, 0, SEEK_SET);
// Create the string for the file contents.
char *buffer = malloc(sizeof(char) * (length + 1));
buffer[length] = '\0';
// Set the contents of the string.
fread(buffer, sizeof(char), length, file);
// Close the file.
fclose(file);
// Do something with the data.
// ...
// Free the allocated string space.
free(buffer);

Ответ 11

легко и аккуратно (при условии, что содержимое файла меньше 10000):

void read_whole_file(char fileName[1000], char buffer[10000])
{
    FILE * file = fopen(fileName, "r");
    if(file == NULL)
    {
        puts("File not found");
        exit(1);
    }
    char  c;
    int idx=0;
    while (fscanf(file , "%c" ,&c) == 1)
    {
        buffer[idx] = c;
        idx++;
    }
    buffer[idx] = 0;
}