Najprostszym sposobem, aby uzyskać zawartość pliku w C

głosy
52

Jaki jest najprostszy sposób (najmniej podatne na błędy, a już najmniej linie kodu, jednak chcesz zinterpretować to), aby otworzyć plik w C i odczytać jego zawartość na ciąg (char *, char [], cokolwiek)?

Utwórz 06/10/2008 o 15:32
źródło użytkownik
W innych językach...                            


11 odpowiedzi

głosy
80

Staram się po prostu załadować cały bufor jako surowy kawał pamięci do pamięci i wykonać parsowanie na własną rękę. W ten sposób mam najlepszą kontrolę nad tym, co średnia lib robi na wielu platformach.

To jest tylko zalążek używam do tego. można również sprawdzić kody błędów dla fseek, ftell i fread. (Pominięte dla jasności).

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...
}
Odpowiedział 06/10/2008 o 15:37
źródło użytkownik

głosy
18

Innym, niestety silnie zależne od OS, rozwiązanie to jest pamięć mapowanie pliku. Korzyści obejmują na ogół wydajność odczytu i zmniejszenie użycia pamięci jako przeglądać aplikacje i systemy operacyjne plik cache rzeczywiście może dzielić pamięć fizyczną.

Kod POSIX będzie wyglądać następująco:

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

Okna z drugiej strony jest trochę bardziej skomplikowane, a niestety nie mam kompilatora przede mną do przetestowania, ale funkcjonalność jest dostarczana przez CreateFileMapping()i MapViewOfFile().

Odpowiedział 06/10/2008 o 16:37
źródło użytkownik

głosy
7

Jeśli „odczytać jego zawartość na ciąg” oznacza, że ​​plik nie zawiera znaków z kodem 0, można również użyć getdelim () funkcji, które albo akceptuje blok pamięci i reallocates go, jeśli to konieczne, lub po prostu przydziela cały bufor dla ty i odczytuje plik do niego aż napotka określony separator lub koniec pliku. Wystarczy przejść „\ 0” jako ogranicznik, aby przeczytać cały plik.

Funkcja ta jest dostępna w GNU C Library, http://www.gnu.org/software/libc/manual/html_mono/libc.html#index-getdelim-994

Przykładowy kod może wyglądać tak proste, jak

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 */
Odpowiedział 06/10/2008 o 16:24
źródło użytkownik

głosy
6

Jeśli plik jest tekst, a chcesz uzyskać linię tekstu po linii, najprostszym sposobem jest użycie fgets ().

char buffer[100];
FILE *fp = fopen("filename", "r");                 // do not use "rb"
while (fgets(buffer, sizeof(buffer), fp)) {
... do something
}
fclose(fp);
Odpowiedział 08/10/2008 o 22:02
źródło użytkownik

głosy
5

Jeśli czytasz pliki specjalne takie jak stdin lub potoku, nie będą w stanie wykorzystać fstat aby uzyskać rozmiar pliku wcześniej. Ponadto, jeśli czytasz binarnego fgets plików straci informacje o rozmiarze ciąg bo wbudowanych „\ 0” znaków. Najlepszym sposobem, aby odczytać plik następnie jest użycie czytać i 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;
}
Odpowiedział 24/11/2013 o 20:40
źródło użytkownik

głosy
1

Uwaga: Jest to modyfikacja przyjętego odpowiedzi powyżej.

Oto sposób na to, wraz z sprawdzania błędów.

Dodałem sprawdzania rozmiaru, aby zakończyć, kiedy plik był większy niż 1 GiB. Zrobiłem to, ponieważ program kładzie cały plik do łańcucha, który może używać zbyt dużo pamięci RAM i awarii komputera. Jednakże, jeśli nie obchodzi, że można po prostu usunąć go z kodem.

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

I sprawdzić błędy:

int err;
size_t f_size;
char * f_data;

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

if (err) {
    // process error
}
Odpowiedział 06/01/2019 o 00:48
źródło użytkownik

głosy
1

Jeśli używasz glib, a następnie można użyć 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);
  }
}
Odpowiedział 07/10/2016 o 10:24
źródło użytkownik

głosy
0

proste i schludne (zakładając zawartość w pliku jest mniejsza niż 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;
}
Odpowiedział 15/08/2019 o 17:40
źródło użytkownik

głosy
0

Dodam własną wersję, na podstawie odpowiedzi tutaj, tylko w celach informacyjnych. Mój kod uwzględnia sizeof (char) i dodaje kilka uwag do niego.

// 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);
// Do something with the data.
// ...
// Free the allocated string space.
free(buffer);
Odpowiedział 07/07/2019 o 19:59
źródło użytkownik

głosy
0

Wystarczy modyfikowany zaakceptowanej odpowiedzi powyżej.

#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);
}
Odpowiedział 09/11/2017 o 07:10
źródło użytkownik

głosy
0
// 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;
}

Jest to dość surowy rozwiązaniem, ponieważ nic nie jest zaznaczone na null.

Odpowiedział 15/05/2016 o 17:49
źródło użytkownik

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more