什么是最简单的方法(最不容易出错,最少的代码行,但是你想要解释它)在C中打开一个文件并将其内容读入一个字符串(char*,char [],等等)?
Nil*_*nck 128
我倾向于将整个缓冲区作为原始内存块加载到内存中并自行进行解析.这样我就可以最好地控制标准库在多个平台上的功能.
这是我用于此的存根.您可能还想检查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...
}
Run Code Online (Sandbox Code Playgroud)
Jef*_* Mc 24
另一个不幸的是高度依赖操作系统的解决方案是内存映射文件.优点通常包括读取的性能和减少的内存使用,因为应用程序视图和操作系统文件缓存实际上可以共享物理内存.
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);
Run Code Online (Sandbox Code Playgroud)
另一方面,Windows稍微有点棘手,不幸的是我没有在我面前测试编译器,但功能是由CreateFileMapping()和提供的MapViewOfFile().
dmi*_*gov 11
如果"将其内容读入字符串"意味着该文件不包含代码为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 */
Run Code Online (Sandbox Code Playgroud)
如果文件是文本,并且您想逐行获取文本,最简单的方法是使用fgets().
char buffer[100];
FILE *fp = fopen("filename", "r"); // do not use "rb"
while (fgets(buffer, sizeof(buffer), fp)) {
... do something
}
fclose(fp);
Run Code Online (Sandbox Code Playgroud)
如果您正在读取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;
}
Run Code Online (Sandbox Code Playgroud)
注意:这是对上述已接受答案的修改。
这是一种方法,完成错误检查。
我添加了一个大小检查器以在文件大于 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;
}
Run Code Online (Sandbox Code Playgroud)
并检查错误:
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);
}
Run Code Online (Sandbox Code Playgroud)
在 C 中打开文件并将其内容读入字符串的最简单方法是什么(最不容易出错,代码行数最少,无论您想如何解释它)?
遗憾的是,即使过了很多年,答案仍然容易出错,并且许多答案缺乏正确的字符串形成和错误检查。
#include <stdio.h>
#include <stdlib.h>
// Read the file into allocated memory.
// Return NULL on error.
char* readfile(FILE *f) {
// f invalid? fseek() fail?
if (f == NULL || fseek(f, 0, SEEK_END)) {
return NULL;
}
long length = ftell(f);
rewind(f);
// Did ftell() fail? Is the length too long?
if (length == -1 || (unsigned long) length >= SIZE_MAX) {
return NULL;
}
// Convert from long to size_t
size_t ulength = (size_t) length;
char *buffer = malloc(ulength + 1);
// Allocation failed? Read incomplete?
if (buffer == NULL || fread(buffer, 1, ulength, f) != ulength) {
free(buffer);
return NULL;
}
buffer[ulength] = '\0'; // Now buffer points to a string
return buffer;
}
Run Code Online (Sandbox Code Playgroud)
请注意,如果文本文件包含空字符,则分配的数据将包含所有文件数据,但字符串会显得很短。更好的代码还会返回长度信息,以便调用者可以处理该信息。
char* readfile(FILE *f, size_t *ulength_ptr) {
...
if (ulength_ptr) *ulength_ptr == *ulength;
...
}
Run Code Online (Sandbox Code Playgroud)
分配字符串时,请务必在完成后释放返回的指针。
| 归档时间: |
|
| 查看次数: |
115538 次 |
| 最近记录: |