所以我有this file和这段代码:

int main()
{
    FILE *file;
    file = fopen("fonts.dat", "rb");
    if (file == NULL)
        return 1;

    char readLineBuffer[200];

    if(readLineBuffer == NULL) { return 1; }
    if(readLineBuffer == 0) { return 1; }

    while (fgets(readLineBuffer, 200, file) != NULL)
    {
        readLineBuffer[strcspn(readLineBuffer, "\n")] = '\0';
        //if (readLineBuffer[0] == '\0' || readLineBuffer[0] == '#') {continue;}
        for(int i=0; readLineBuffer[i]!=00; i++)
        {
            if (readLineBuffer[i]=='#')
            {
                readLineBuffer[i] = 00;
                break;
            }
        }
        puts(readLineBuffer);
    }

    fclose(file);

    system("PAUSE");
    return 0;
}

它将删除以#开头的注释行。

但是,如何从[FONT_ID]之类的文件中读取并将其存储到变量中以供其他代码使用?

最佳答案

这段代码中有很多内容表明您在使用C / C++时遇到了困难,或者您正在从其他程序员/语言中学习坏习惯。

FILE *file;
file = fopen("fonts.dat", "rb");

尽可能尝试避免将声明和赋值分开。您说这是一个文本文件,因此您无需以“二进制”模式打开它。用二进制读取意味着您将不得不担心行尾类型的不同。以文本模式打开它,操作系统/ libc将为您进行翻译,以使行尾神奇地像应该的那样只是“\ n”。
char readLineBuffer[200];

if(readLineBuffer == NULL) { return 1; }
if(readLineBuffer == 0) { return 1; }

首先,以您刚才使用的方式使用固定大小的存储的优点之一是它永远无法评估为NULL。使用指针时,只需要空检查。的确,“readLineBuffer”可以用作指针,但它实际上也是一个数组。尝试以下简单程序:
#include <stdio.h>

int main(int argc, const char* argv[])
{
    char buffer[1234];
    char* bufPointer = buffer; // yes, it looks like a pointer.
    printf("the size of buffer is %u but the size of bufPointer is %u\n",
           sizeof(buffer),
           sizeof(bufPointer));
    return 0;
}

其次,“NULL”只是一个#define
#define NULL 0

(这就是为什么在C++ 11中他们添加了特殊的'nullptr'常量)。
while (fgets(readLineBuffer, 200, file) != NULL)

手动重复事物的大小很危险。使用“sizeof()”命令
while (fgets(readLineBuffer, sizeof(readLineBuffer), file)

您确定文件中的所有行都没有超过200个字节的长度吗?想象以下情况:
fgets(buffer, 20, file);

现在想象一下这行:

123456789012345678#这是评论

这些fget将读取“123456789012345678#”,并且您的代码将删除结尾的“#”并执行“puts”操作,该操作会将“123456789012345678 \ n”写入文件。然后,您将看到“这是注释”,找不到注释字符,然后在文件中写一行新行“这是注释\ n”。

其次,由于无论如何都要迭代该行,因此您可能要考虑以下任一情况:

一种。自己迭代缓冲区
for(int i = 0; i {
if(readLineBuffer [i] =='\ n'|| readLineBuffer [i] =='#')
{
readLineBuffer [i] = 0;
打破;
}
}

b。使用strpbrk
char * eol = strpbrk(“#\ n”,readLineBuffer);
if(eol!= NULL)//找到注释或行尾
* eol ='\ 0';

这会将您的代码减少到以下内容。尽管此代码可以在“C++”编译器上进行编译,但它几乎是纯“C”。
FILE *file = fopen("fonts.dat", "r");
if (file == NULL)
    return 1;

char readLineBuffer[200];
while (fgets(readLineBuffer, sizeof(readLineBuffer), file) != NULL)
{
    // find comment or end of line so we can truncate the line.
    char* eol = strpbrk(readLineBuffer, "#\n");
    if ( eol != NULL )
        *eol = '\0';
    puts(readLineBuffer);
}

fclose(file);

system("PAUSE");
return 0;

如果您要处理和存储正在运行的实际信息,则需要创建变量来存储它,编写代码以检查/“解析” readLineBuffer中每行经过的行,而您将需要学习使用“sscanf”,“atoi”,“strtoul”等命令,最终您将需要创建一些微型状态机。

另外,您可能想要研究专门为此类任务设计的脚本语言,例如“Perl”或“Python”。
# perl version

local $/ = /\n{2,}/;  # Read the file as paragraphs.
open(file, "font.dat") || die "Can't open font.dat";
my %data = ();
while ($line = <>) {
    $line =~ s/\s+#.*$//mg;    # Get rid of all the comments.
    $line =~ s/\n\n/\n/sg;     # Fix any blank lines we introduced.

    # Each data block starts with an ini-style label, that is a
    # line starting with a "[", followed by some word-characters (a-z, A-Z, 0-9)
    # and a closing "]", maybe with some whitespace after that.

    # Try to remove a label line, capturing the label, or skip this block.
    next unless $line =~ s/^ \[ (\w+) \] \s* \n+ //sx;

    # Store the remaining text into data indexed on the label.
    my ($label) = ($1);  # the capture
    $data{$label} = $line;
}

print("FONT_ID = $data{'FONT_ID'}\n");

或用perlier-perl编写
local $/ = /\n{2,}/;  # Read blocks separated by 2-or-more newlines (paragraphs)
die "Can't open file" unless open(file, "font.dat");
while (<>) {
    s/\s+#.*$//mg;
    s/\n{2,}/\n/sg;
    $data{$1} = $_ if (s/^\[(\w+)\][^\n]+\n+//s);
}
$fontId = ;
print("font_id = ", int($data{'FONT_ID'}), "\n");

08-24 18:41