将文件读入C中的字符数组

当您使用 C 编程语言时,您可能会遇到一些需要将文件读入字符数组的问题,例如分析每个字符的频率,或者将所有句子的每个起始词从小写转换为大写,反之亦然。该解决方案非常简单,但对于不太了解文件读取或写入的人来说可能并不那么简单。因此,在这篇文章中,您可以逐步学习如何在 C 中将文件读入字符数组。

在 C 中打开文件

在 C 语言中打开文件的最简单和最流行的方法是使用以下格式的“fopen”函数:

file = fopen(file_name, "open_mode"); //open the "file-name" file and store the file pointer in the variable 'file'

“fopen”函数的模式参数指定打开文件的模式。该模式可以是以下之一:

  • “ r ”:打开文件进行读取。
  • “ w ”:将文件截断为零长度或创建一个用于写入的文件。
  • “ a ”:追加到文件或创建一个文件(如果不存在)进行写入。
  • “ r+ ”:打开文件进行读写。
  • “ w+ ”:将文件截断为零长度或创建一个用于读写的文件。
  • “ a+ ”:追加到文件或创建文件以供读写。

但由于某种原因,该文件可能无法正常打开。为了在发生此类情况时做好准备,您应该始终检查“fopen”函数的返回值,以确保在尝试读取或写入文件之前已成功打开文件。像这样:

// If 'fopen' returns NULL,  print an error message and exit the program 
if (file == NULL) {
      printf("Error: Failed to open file '%s'.\n", file_name);
      return 1;
}

逐字符读取文件内容

在读取文件之前,您必须有一个字符数组来存储文件内容。让我们这样做吧

char buffer[1000]; //Initialize a char array named 'buffer' with size of 1000

现在,是时候使用“fgetc”读取文件了。该函数每次调用都会读取文件中的一个字符,如果重复调用,它将读取后续的每个字符,直到结束。因此,我们可以使用 while 循环来使过程变得更容易。

int i = 0, c; //c is the intermediate variable, i is the increment variable
while ((c = fgetc(file)) != EOF) {//Read contents until it reach the end of the file
      buffer[i] = c;
      i++;
}

上面的示例假设文件仅包含 ASCII 字符,并且文件大小小于 1000 个字符。

可调整大小的缓冲区

我们之前定义的缓冲区数组最多包含 1000 个字符。但在许多情况下,文件大小远大于此。我们可以通过将缓冲区变成可调整大小的缓冲区来解决这个问题。您可以通过 C 标准库提供的“malloc”、“realloc”和“realloc”函数使用动态内存分配。

char *buffer = NULL; // initialize buffer to NULL
int buffer_size = 0;
/*Open the file here*/
// Read file character by character
int c, i = 0;
while ((c = fgetc(file)) != EOF) {
    // If buffer is full, resize it
    if (i >= buffer_size) {
       buffer_size += 1000; // increase buffer size by 1000 bytes
       buffer = realloc(buffer, buffer_size); // resize buffer
       if (buffer == NULL) {
          printf("Error: Memory allocation failed.\n");
          return 1;
       }
    }
    buffer[i] = c;
    i++;
}

我们在上面的代码片段中使用“realloc”函数,这被证明是有用的,因为文件大小通常是事先未知的。对于“malloc”和“calloc”函数,它们可用于将指定大小的内存块分配给变量。在此示例中,您可以像下面这样使用:

buffer = (char*)malloc(1000); //is the same as define char buffer[1000]

在此示例中,您可能不需要使用“malloc”和“calloc”。我们稍后会再次见到他们。

文件包含非 ASCII 字符

在 C 中,字符串表示为字节序列,这些字节的解释取决于字符编码。如果文件包含非 ASCII 字符,则需要使用支持这些字符的字符编码,例如 UTF-8 或 UTF-16。

对于这个问题,您应该使用可以处理多字节字符的函数,例如“fgetwc”和“fgetws”。这些函数一次分别读取一个宽字符 (wchar_t) 或一个宽字符串 (wchar_t*)。

以下是对代码的一些修改,以使其在文件包含非 ASCII 字符时正常工作:

wchar_t buffer[100];
// Open file for reading
file = fopen(filename, "r,ccs=UTF-8");
// Read file contents
wchar_t c;
int i = 0;
while ((c = fgetwc(file)) != WEOF) {
   buffer[i] = c;
   i++;
}

另外,请确保输入和输出流设置为正确的编码,以正确显示或操作字符。在 MacOS 和 Linux 等 Unix 操作系统上,为了确保输出编码为 UTF-8,您可以使用 'setlocale' 函数:

#include 
int main()
{
    setlocale(LC_ALL, "en_US.utf8");

    // your code here

    return 0;
}

在 Windows 上,您可以使用 '_setmode' 和 '_O_U8TEXT' 函数将输出编码设置为 UTF-8:

#include  //_O_U8TEXT
#include  //_setmode()
int main()
{
    _setmode(_fileno(stdout), _O_U8TEXT);

    // your code here

    return 0;
}

以下是包含越南语单词“Xin chào!”的文件示例 (Hello) 带重音符号(非 ASCII 字符),以 UTF-8 编码保存:

Xin chào!

这是我们的程序在在线 C 编译器上运行后的输出:

Xin chào!

...Program finished with exit code 0
Press ENTER to exit console.

读取整个文件内容

如果您不熟悉 C,那么您可以跳过此步骤,但我仍然建议将其作为高级练习来阅读。我想介绍另一种方法来解决“如何在 C 中将文件读入字符数组”问题。新的思路是不再逐个字符地读取文件,而是整体读取文件,在读取之前确定文件大小。这是一个更复杂的解决方案,但也更有效。

首先,您应该定义常用变量:用于打开文件的文件指针和用于包含字符数组的缓冲区。请记住,您还需要文件大小:

FILE *fp;
long file_size;
char *buffer;

然后就可以打开文件来读取:

fp = fopen("example.txt", "r");

要了解文件的大小,可以使用“ftell”函数。它将告诉文件指针中当前位置的字节位置:
current_byte = ftell(fp);

但是等等,文件读取总是从文件的开头开始。没问题,“fseek”函数会将读取控件移动到文件中的不同位置:

fseek(fp, 0, SEEK_END);

您现在可以正确获取文件大小。之后,我们再次将读取控件设置为开头,开始读取文件内容:

file_size = ftell(fp);
rewind(fp); move the control to the file's beginning
 
// Allocate memory for the char array
buffer = (char*) malloc(file_size + 1);

这里“malloc”函数的使用非常简单:分配内存来创建一个未初始化的 char 数组,其大小为 (file_size+1) 乘以 1 字节(char 类型的大小)。

如果您想使用“calloc”函数,请按以下步骤操作:

buffer = (char*) calloc(file_size + 1, sizeof(char));

“malloc”和“calloc”之间的主要区别在于,“malloc”仅分配内存而不初始化其内容,而“calloc”既分配内存又将内存初始化为零。使用“calloc”的主要优点是分配的内存已经被清零,如果您打算稍后将 char 数组用作字符串,这会很有帮助。

// Read the file into the char array
fread(buffer, file_size, 1, fp);

创建缓冲区后,您可以使用“fread”函数读取整个文件,该函数获取文件指针、要读取的每个元素的大小、要读取的元素的数量以及目标数组。

// Add a null terminator at the end of the char array
buffer[file_size] = '\0';

您可能想知道为什么需要为“缓冲区”分配额外的字节。为什么不只是(file_size)而是(file_size + 1)?在这里,将在 char 数组的末尾添加 null 终止符,以指示字符串的结束。实际上,如果您唯一的任务是将文件读入数组,那么这一步是不必要的。但稍后如果您想将此数组打印为字符串,那么这是一个要求。C 中的字符串被定义为将最后一个字符作为空终止符“\0”。

清理你的代码

您已经打开并使用了该文件,因此请记住随后将其关闭。只需使用“fclose”函数来释放您分配的“文件”指针变量。

fclose(file);

谈到释放指针,还记得用来存储字符的“缓冲区”数组吗?如果您将其定义为已分配的内存(指针),那么最好立即释放它以避免内存泄漏。

free(buffer);

以下是您的解决方案的概述:

#include 
#include 

int main() {
   FILE *file;
   char filename[] = "example.txt";
   char *buffer = NULL; // initialize buffer to NULL
   int buffer_size = 0;
   int i = 0;

   //Open file for reading
   file = fopen(filename, "r");

   //Check if file opened successfully
   if (file  == NULL) {
      printf("Error: Failed to open file '%s'.\n", filename);
      return 1;
   }

   // Read file character by character
   int c;
   while ((c = fgetc(file)) != EOF) {
      // If buffer is full, resize it
      if (i >= buffer_size) {
         buffer_size += 1000; // increase buffer size by 1000 bytes
         buffer = realloc(buffer, buffer_size); // resize buffer
         if (buffer == NULL) {
            printf("Error: Memory allocation failed.\n");
            return 1;
         }
      }
      buffer[i] = c;
      i++;
   }

   // Close file
   fclose(file);

   // Print the character array
   printf("%s", buffer);

   // Free the dynamically allocated buffer
   free(buffer);

   return 0;
}

你可能感兴趣的:(c语言,c++,c语言,c++,算法)