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

如何在C中将文件内容读取为字符串?,c,string,file,C,String,File,用C打开一个文件并将其内容读入字符串(char*,char[],随便什么),最简单的方法是什么(最不容易出错,代码行数最少,不管您如何解释它)?我倾向于将整个缓冲区作为原始内存块加载到内存中,然后自己进行解析。这样我就可以更好地控制标准库在多个平台上的功能 这是我用的存根。您可能还需要检查fseek、ftell和fread的错误代码。(为清楚起见省略) 如果“将其内容读入字符串”表示文件不包含代码为0的字符,则还可以使用getdelim()函数,该函数可以接受内存块并在必要时重新分配内存,或者只

用C打开一个文件并将其内容读入字符串(char*,char[],随便什么),最简单的方法是什么(最不容易出错,代码行数最少,不管您如何解释它)?

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

这是我用的存根。您可能还需要检查fseek、ftell和fread的错误代码。(为清楚起见省略)

如果“将其内容读入字符串”表示文件不包含代码为0的字符,则还可以使用getdelim()函数,该函数可以接受内存块并在必要时重新分配内存,或者只为您分配整个缓冲区,并将文件读入其中,直到遇到指定的分隔符或文件结尾。只需传递“\0”作为分隔符即可读取整个文件

此函数在GNU C库中提供

示例代码可能看起来很简单

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 */

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

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()

提供的。如果文件是文本,并且您希望逐行获取文本,最简单的方法是使用fgets()


如果您正在读取特殊文件,如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;
}
#包括
#包括
#包括
#包括
int main(){
char-buf[4096];
(三);
char*str=NULL;
尺寸长度=0;
while(n=读取(标准文件号、buf、sizeof buf)){
if(n<0){
if(errno==EAGAIN)
继续;
佩罗(“阅读”);
打破
}
str=realloc(str,len+n+1);
memcpy(str+len,buf,n);
len+=n;
str[len]='\0';
}
printf(“%.*s\n”,len,str);
返回0;
}

这是一个非常粗糙的解决方案,因为没有对null进行任何检查

如果您使用的是
glib
,那么您可以使用


刚刚根据上面已接受的答案进行了修改。

#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);
}
#包括
#包括
#包括
char*readFile(char*filename){
文件*f=fopen(文件名,“rt”);
断言(f);
fseek(f,0,SEEK_END);
长长度=ftell(f);
fseek(f,0,SEEK_集);
char*buffer=(char*)malloc(长度+1);
缓冲区[长度]='\0';
fread(缓冲区,1,长度,f);
fclose(f);
返回缓冲区;
}
int main(){
char*content=readFile(“../hello.txt”);
printf(“%s”,内容);
}

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

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

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

#包括
#包括
#定义文件\u确定0
#定义文件\u不存在\u 1
#将文件\u定义为\u大2
#定义文件读取错误3
char*c_read_文件(const char*f_name,int*err,size_t*f_size){
字符*缓冲区;
尺寸与长度;
文件*f=fopen(f_名称,“rb”);
尺寸、读数、长度;
如果(f){
fseek(f,0,SEEK_END);
长度=ftell(f);
fseek(f,0,SEEK_集);
//1 GiB;最好不要在一个字符串中加载整个大文件
如果(长度>1073741824){
*err=文件大小;
返回NULL;
}
缓冲区=(字符*)malloc(长度+1);
if(长度){
read_length=fread(缓冲区,1,长度,f);
如果(长度!=读取长度){
自由(缓冲);
*err=文件读取错误;
返回NULL;
}
}
fclose(f);
*err=文件\u正常;
缓冲区[长度]='\0';
*f_尺寸=长度;
}
否则{
*err=文件不存在;
返回NULL;
}
返回缓冲区;
}
要检查错误,请执行以下操作:

int-err;
大小;
char*f_数据;
f_data=c_read_文件(“test.txt”、&err、&f_size);
如果(错误){
//过程错误
}
否则{
//过程数据
免费(f_数据);
}

我将根据这里的答案添加我自己的版本,仅供参考。我的代码考虑了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);
简单整洁(假设文件中的内容少于10000):


我还将检查fread的返回值,因为它可能由于错误而无法读取整个文件。正如rmeador所说,fseek将在大于4GB的文件上失败。True。对于大文件,这个解决方案很糟糕。因为这是一个登录页,我想指出,
fread
不会以零结尾字符串。这可能会导致一些问题。正如@Manbroski所说,缓冲区需要“\0”终止。所以我将改变
buffer=malloc(长度+1)和add:
缓冲区[length]='\0'(Valgrind验证)我以前用过这个!假设您正在读取的文件是文本(不包含\0),它工作得非常好。很好!在全文本文件中使用slurp时,可以避免很多问题。现在,如果有一种类似的超简单的方法来读取二进制文件流,直到EOF没有
// 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;
}
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);
  }
}
#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);
}
// 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);
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;
}