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



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

1168   9  

9 ответов:

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

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

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

если "читать его содержимое в строку" означает, что файл не содержит символов с кодом 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, '', fp);
if ( bytes_read != -1) {
  /* Success, now the entire file is in the buffer */

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

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

если Вы читаете специальные файлы, такие как stdin или канал, вы не сможете использовать 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] = '';
    }
    printf("%.*s\n", len, str);
    return 0;
}

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

просто изменен из принятого ответа выше.

#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] = '';
    fread(buffer, 1, length, f);
    fclose(f);
    return buffer;
}

int main() {
    char *content = readFile("../hello.txt");
    printf("%s", content);
}

Если вы хотите решение на основе стека:

  FILE* f = fopen(file, "r");
  if (!f) {
    fprintf(stderr, "fopen failed\n");
  }

  if (fseek(f, 0, SEEK_END)) {
    fprintf(stderr, "fseek failed\n");
  }

  const long len = ftell(f);
  if (len < 0) {
    fprintf(stderr, "ftell failed\n");
  }

  if (fseek(f, 0, SEEK_SET)) {
    fprintf(stderr, "fseek failed\n");
  }

  char buf[len + 1];
  if (fread(buf, sizeof(char), len, f) != len) {
    fprintf(stderr, "fread failed\n");
  }

  buf[len] = '';

  if (fclose(f)) {
    fprintf(stderr, "fclose failed\n");
  }

Comments

    Ничего не найдено.