繁体   English   中英

如何在同一个文件中读写文本和数字?

[英]How to read and write text and numbers in the same file?

我遇到了一个非常烦人且令人难以置信的问题,因为这似乎根本不可能,但它正在发生!

我要做的就是写入和读取一个文件,该文件由一个字符串后跟一些无符号长整数组成(存储为数字,但未转换为显示它们的文本)。

我对 C/C++ 有点不习惯(但我现在正在重拾它),所以我只是想使用我习惯的文件管理,即 fprintf、fscanf、fread 和写。 您可能有更好的方法,如果您愿意,可以提出建议,但我已经用其他函数编写了代码,我可能不会全部重写。 我真的只是想让我现有的功能发挥作用,尽管它们可能很愚蠢。 您可能会使用 << 和 >> 运算符或其他东西,但我从来没有习惯这样做,因为就我个人的审美品味而言,运算符对于文件访问过程来说似乎很愚蠢,我宁愿只使用函数。 我提到的那些似乎对我来说总是很好,所以我坚持使用它们。 无论如何,我有两个主要优先事项:

  • 让事情发挥作用

  • 首先弄清楚为什么它给了我如此奇怪的结果,这样我就可以防止它再次发生!

所以首先我尝试使用 fprintf 打印文本字符串,使用 fwrite 打印 longs,然后使用 fscanf 读取字符串,使用 fread 读取 longs。 但是 fscanf 似乎没有工作所以我读了一些说它只读取到一个空格而不是 null 字符(WTF 是关于?,),所以改为:我实现了一个循环来读取它一个字符一次:

string text = "";
char* currentChar = new char(0);
while(true)
{
    fread(currentChar, sizeof(char), 1, file);
    if(*currentChar == 0)
    {
        break;
    }
    text += *currentChar;
}

我意识到这可能不是最简单或最有效的方法,但坦率地说我不在乎,因为它只是一个小字符串,所以它不会让系统陷入困境。 但关键是它至少应该正常工作,不是吗? 请注意,我用 null 字符终止了字符串,当我读完字符串时,我已经从文件中读取了 null 字符,所以当我接下来开始读取 longs 时,它们应该在null,对吗?

但后来我注意到我正在阅读的 long 不是我已经写入文件的内容,所以我决定用我可以有更多控制权的东西替换我的 fprintf,并且我实现了一个类似的写入循环:

unsigned int textLength = textString.length();
const char* text = textString.c_str();
for(unsigned int i = 0; i < textLength; i++)
{
    fwrite(&text[i], sizeof(char), 1, file);
}
const char* null = new char(0);
fwrite(&null, sizeof(char), 1, file);

但是当我运行它以将数据保存到文件中时,即使它正在写入所有文本,并且似乎要在最后写入 null 字符,当我后来使用另一个 function 读取文件时,它以某种方式拿起了一个null 之前文本末尾的额外字符,额外字符等于什么取决于它是哪个文件(文件格式相同但数据不同),尽管它似乎总是只有一个字符(但公平地说,我只用几个文本字符串尝试过。但每次都有许多不同的 long)。

我怀疑这可能是由于愚蠢的大/小端废话而间接导致的字节被翻转(为什么每个人都不能就标准达成一致?),但即使是这样,我也会读写null 字符在读/写任何 long 之前作为单个字节,所以我看不出如何用 null 字符转置字节。 尽管只是猜测它甚至可能与字节转置有关。

实际上,我只是再次对其进行了测试,并且我确定每次最后的额外字符都会随着出现在其后的不同长字符而变化,即使在开头具有相同文本字符串的两个文件之间进行比较也是如此,这似乎为了更加重视我的理论,即它可能正在转置长字节的字节,但我仍然不明白这是怎么可能的,因为我在尝试读/写任何长字节之前读/写了 null 字符!

此外,无论哪种方式都不能解释为什么当我仍在使用 fprintf 时(在我用我的写循环替换它之前),即使它没有在字符串的末尾添加一个额外的字符,它仍然以某种方式读取了错误的 longs , fread 和 fwrite 函数不匹配格式吗? 这样一个翻转字节而另一个不翻转,这可以解释奇怪的结果,但是鉴于这两个函数在同一个文件中,我会惊讶于任何人将它们编写为彼此不兼容的愚蠢!

但无论如何,我整天都在研究这个问题,我希望今天能解决它,但我认为这不再可行了。 这个荒谬的问题怎么可能发生,我该如何解决?! 提前致谢!

It changes based on whether you are using C or C++ what you were using is how you would do it in C but in C++ you would want to look in to std::cin and std::cout. 这些就是您想要使用数据流(<< 或 >>)的目的。

我们是来帮忙的。

而且,我真的很抱歉答案来得这么晚。 我必须首先查找我 30 年前的 C 书籍并尝试重新理解 C 命令。 所以,我再次道歉。

您可能面临的最大问题之一是您存储了任意长度的字符串。

但是,当读回字符串时,你不知道它有多少字节。 因此,您必须将终止 0 写入文件,然后,为了回读,您需要逐字节读取,直到并包括终止 0。

此外。 如果您没有现代 C++ 字符串,那么您需要自己进行所有动态 memory 管理。 这意味着努力。 但没问题。

如果你有一个固定大小的字符串,那就更容易了。 然后您可以使用std::fwritestd::fread读取完整的字符串。

目前,我确实忽略了这不适用于非常长的数据,因为如果缓冲的 IO 缓冲区太小,则可能需要以块的形式读取文件。 这也没有问题。 如果你面对它,那么请反馈,我当然会为你写一些新的代码来展示如何做到这一点。

我还添加了许多评论,以使您更好地理解。

请首先查看具有全动态 memory 管理的解决方案。

#include <cstdio>
#include <cstring>

int main() {

    // 3 long test values. We will use this valuestobe ableto check problems wit endianess
    long value1a = 305419896;  // Which is equivalent to the hex number 0x12345678
    long value2a = 591751049;  // Which is equivalent to the hex number 0x23456789
    long value3a = 878082202;  // Which is equivalent to the hex number 0x3456789A

    // A test string with some arbitary length
    const char *testString = "abcdefghijklmnopqrstuvwxyz";

    // Part 1. Write data ------------------------------------------------------

    // Now, open a file and write the values. Open file in binary mode
#pragma warning(suppress : 4996)
    std::FILE* fptr = std::fopen("r:\\test.txt", "wb");

    // Check,if the file could be opened.
    if (fptr) {
        // Write values to file
        std::fwrite(testString, std::strlen(testString)+1, 1, fptr);
        std::fwrite(&value1a, sizeof(long), 1, fptr);
        std::fwrite(&value2a, sizeof(long), 1, fptr);
        std::fwrite(&value3a, sizeof(long), 1, fptr);

        // CLose the file and then try toreread data
        fclose(fptr);

        // Part 2. Read data ------------------------------------------------------
#pragma warning(suppress : 4996)
        fptr = std::fopen("r:\\test.txt", "r");

        // Check, if the file could be opened for reading
        if (fptr) {

            // Now read byte by byte and store result in dynamic memory. First create dynamic memory
            unsigned int reservedSpace = 2;
            char* myString = new char[reservedSpace];

            // This is theindex in our string
            unsigned int readIndex = 0;

            // We do not know the length of the string in the file, so, we will read until we find the terminating 0
            char c = ' ';
            while ((c != '\0') && (c != EOF)) {

                // Read character
                c = static_cast<char>(fgetc(fptr));

                // Before we can store the new character, we need to check, if we have enough space in our target string
                if (readIndex >= reservedSpace) {

                    // No, not enough space. Get more space, DOubele the previous size
                    reservedSpace = reservedSpace * 2;

                    // Get new space
                    char* temp = new char[reservedSpace];

                    // Copy old data to this space
                    for (unsigned k = 0; k < readIndex; ++k)
                        temp[k] = myString[k];

                    // Release old memory
                    delete []myString;

                    // And assign new memory to old variable. So, now we do have a bigger string
                    myString = temp;
                }

                // Now store the just read character
                myString[readIndex] = c;

                // And set the new read index
                ++readIndex;
            }
            // All read. Now set the string terminator
            myString[readIndex] = '\0';

            // Next. Try to read 3 longs and check result
            long value1b=0, value2b=0, value3b=0;
            unsigned int readValues = 0;
            readValues += std::fread(&value1b, sizeof(long), 1, fptr);
            readValues += std::fread(&value2b, sizeof(long), 1, fptr);
            readValues += std::fread(&value3b, sizeof(long), 1, fptr);

            if (readValues == 3) {
                // Show resulting output
                std::printf("String:\t\t%s\nValue 1:\t%ld\nValue 2:\t%ld\nValue 3:\t%ld\n", myString, value1b, value2b, value3b);
                if (!strcmp(testString, myString) && value1a == value1b && value2a == value2b && value3a == value3b) {
                    std::printf("\nEverything read correctly\n\n");
                }
                else {
                    std::printf("\n*** Error. Data could obviously not be read back correctly\n\n");
                }
            }
            else {
                std::printf("\n*** Error could not read long values\n\n");
            }
            // Close the file
            fclose(fptr);

            // Release memory
            delete[] myString;
        }
        else {
            // File could not be opened for reading. Show error message.
            std::printf("\n*** Error: could not open file for reading\n\n");
        }
    }
    else {
        // File could not be opened for writing. Show error message.
        std::printf("\n*** Error: could not open file for writing\n\n");
    }
}

现在 function 用于固定大小的字符串。

#include <cstdio>
#include <cstring>

int main() {

    // 3 long test values. Wewill use this valuestobe ableto check problems wit endianess
    long value1a = 305419896;  // Which is equivalent to the hex number 0x12345678
    long value2a = 591751049;  // Which is equivalent to the hex number 0x23456789
    long value3a = 878082202;  // Which is equivalent to the hex number 0x3456789A

    const int StringSize = 50;

    // A test string with some arbitary length
    const char testString[StringSize] = "abcdefghijklmnopqrstuvwxyz";

    // Part 1. Write data ------------------------------------------------------

    // Now, open a file and write the values. Open file in binary mode
#pragma warning(suppress : 4996)
    std::FILE* fptr = std::fopen("r:\\test.txt", "wb");

    // Check,if the file could be opened.
    if (fptr) {
        // Write values to file
        std::fwrite(testString, StringSize, 1, fptr);
        std::fwrite(&value1a, sizeof(long), 1, fptr);
        std::fwrite(&value2a, sizeof(long), 1, fptr);
        std::fwrite(&value3a, sizeof(long), 1, fptr);


        // CLose the file and then try toreread data
        fclose(fptr);

        // Part 2. Read data ------------------------------------------------------
#pragma warning(suppress : 4996)
        fptr = std::fopen("r:\\test.txt", "r");

        // Check, if the file could be opened for reading
        if (fptr) {

            // Next. Try to read 3 longs and check result
            long value1b = 0, value2b = 0, value3b = 0;
            char myString[StringSize];

            unsigned int readValues = 0;
            readValues += std::fread(myString, StringSize, 1, fptr);
            readValues += std::fread(&value1b, sizeof(long), 1, fptr);
            readValues += std::fread(&value2b, sizeof(long), 1, fptr);
            readValues += std::fread(&value3b, sizeof(long), 1, fptr);

            if (readValues == 4) {
                // Show resulting output
                std::printf("String:\t\t%s\nValue 1:\t%ld\nValue 2:\t%ld\nValue 3:\t%ld\n", myString, value1b, value2b, value3b);
                if (!strcmp(testString, myString) && value1a == value1b && value2a == value2b && value3a == value3b) {
                    std::printf("\nEverything read correctly\n\n");
                }
                else {
                    std::printf("\n*** Error. Data could obviously not be read back correctly\n\n");
                }
            }
            else {
                std::printf("\n*** Error could not read long values\n\n");
            }
            // Close the file
            fclose(fptr);
        }
        else {
            // File could not be opened for reading. Show error message.
            std::printf("\n*** Error: could not open file for reading\n\n");
        }
    }
    else {
        // File could not be opened for writing. Show error message.
        std::printf("\n*** Error: could not open file for writing\n\n");
    }
}

请注意。 没有 C++ 程序员会这样做。

这基本上是 C 代码

而且我的编译器给出了很多警告,因为我使用了这些 C-Function。

最后但并非最不重要。 有许多不同的可能解决方案。

我希望我能帮助你至少一点。 如果您需要更多帮助,请通过评论告诉我。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM