代码之家  ›  专栏  ›  技术社区  ›  Chris Bunch

如何在C中将文件内容读取为字符串?

  •  63
  • Chris Bunch  · 技术社区  · 18 年前

    9 回复  |  直到 8 年前
        1
  •  163
  •   Nils Pipenbrinck    18 年前

    我倾向于将整个缓冲区作为原始内存块加载到内存中,然后自己进行解析。这样我就可以更好地控制标准库在多个平台上的功能。

    这是我用的存根。您可能还需要检查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
  •  31
  •   Morgoth Jerry Coffin    8 年前

    不幸的是,另一个高度依赖操作系统的解决方案是内存映射文件。好处通常包括读取性能,以及减少内存使用,因为应用程序视图和操作系统文件缓存实际上可以共享物理内存。

    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
  •  16
  •   David Schumann Axnyff    11 年前

    此函数在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
  •  7
  •   Jake    12 年前

    如果您正在读取特殊文件,如stdin或管道,则无法使用fstat预先获取文件大小。此外,如果正在读取二进制文件,由于嵌入了“\0”字符,fgets将丢失字符串大小信息。读取文件的最佳方法是使用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
  •  5
  •   selwyn    18 年前

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

    注:这是对上述公认答案的修改。

    这里有一种方法,包括错误检查。

    我添加了一个大小检查器,当文件大于1 GiB时退出。我这样做是因为程序将整个文件放入一个字符串中,这可能会占用太多内存,导致计算机崩溃。但是,如果您不关心这一点,可以将其从代码中删除。

    #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 whole 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) {
                     free(buffer);
                     *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
    }
    else {
        // process data
        free(f_data);
    }
    
        7
  •  3
  •   SleepyCal    10 年前

    如果你正在使用 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
  •  2
  •   BaiJiFeiLong    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
  •  1
  •   Entalpi    10 年前
    // 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
  •  0
  •   Erik Campobadal Christophe Herreman    7 年前

    // 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
  •  -1
  •   Ahmed Ibrahim El Gendy    7 年前

    简单整洁(假设文件中的内容少于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;
    }