【问题标题】:I am having more characters in the file that I am writing in C++ [closed]我在用 C++ 编写的文件中有更多字符 [关闭]
【发布时间】:2023-08-03 15:33:02
【问题描述】:

我正在使用 C++ 中的 ofstream 写入文件。每行都必须有一个相对时间、一个逗号和我正在写的值。这些值是std::vector<unsigned char>,以便写入我想要的任何值并以另一种方法读回。我的测试是写 3 个值。第一个值最后连接到一个奇怪的字节,即使我使用\0\n。但其他 2 个值都很好。

这是输出文件:

0,BAC�
1000,DEF
2000,GHI

第二个问题是当我读取值时。我不知道如何动态设置一个数组来只读取写在行上的值并与我之前写的前一个字符向量进行比较。

头文件:

class SensorRecorder {
private:
    std::ofstream outFile;
    std::ifstream infile;
    std::string path;
    long duration = -1;
public:
    const std::string OUTPUT_DIR = "out";
    const std::string EXTENSION = ".out";
    const char SEPARATOR = ',';
    SensorRecorder(const char *classNameType);
    ~SensorRecorder();
    int write(std::vector<unsigned char> value);
    std::vector<unsigned char> read(long relativeTime);
    void close();
    std::string getFileName();
};

实施:

#include "utils/SensorRecorder.h"
#include "utils/DateTools.h"
#include <cstring>
#include <iostream>
#include <boost/filesystem.hpp>

SensorRecorder::SensorRecorder(const char *classNameType) {
    boost::filesystem::path full_path(boost::filesystem::current_path());
    full_path.append(OUTPUT_DIR, boost::filesystem::path::codecvt());
    if (boost::filesystem::create_directory(full_path)) {
        std::cout << "Directory Created: " << full_path << std::endl;
    }
    std::string fileName = classNameType + ((std::string) "-") + DateTools::getPlainDate() + EXTENSION;
    full_path.append(fileName, boost::filesystem::path::codecvt());
    path = full_path.c_str();
    outFile.open(path);
}
int SensorRecorder::write(std::vector<unsigned char> value) {
    if (outFile.is_open()) {
        char *data = reinterpret_cast<char *>(value.data());
        auto now = std::chrono::system_clock::now();
        auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);
        auto value = now_ms.time_since_epoch();

        if (duration == -1) {
            duration = 0;
        } else {
            duration = value.count() - duration;
        }
        // write in the file
        outFile << duration << SEPARATOR << data << '\0' << '\n';
        duration = value.count();
    } else {
        return 0;
    }
    return 1;
}
std::vector<unsigned char> SensorRecorder::read(long relativeTime) {
    infile.open(path);
    if (infile.is_open()) {
        std::cout << "Reading from the file" << std::endl;
        long duration;
        char comma;
        unsigned char data[300];

        while (infile >> duration >> comma >> data) {
            std::cout << "duration: " << duration << std::endl;
            std::cout << "data: " << data << std::endl;
            if (duration == relativeTime) {
                std::cout << "INSIDE " << std::endl;
                infile.close();

                // cast the value
                std::vector<unsigned char> outputValues(data, data + sizeof(data));
                return outputValues;
            }
        }
        infile.close();
    }
    return std::vector<unsigned char>();
}

我的测试:

TEST_F(SensorRecorderTest, TestWriteOnFile) {
    std::vector<unsigned char> inputValues01 = {'B', 'A', 'C'};
    std::vector<unsigned char> inputValues02 = {'D', 'E', 'F'};
    std::vector<unsigned char> inputValues03 = {'G', 'H', 'I'};
    mySensorRecorder = new SensorRecorder("SensorRecorderTest");

    // write on the file
    int ret = mySensorRecorder->write(inputValues01);
    ASSERT_EQ(ret, 1);

    std::this_thread::sleep_for(std::chrono::seconds(1));
    ret = mySensorRecorder->write(inputValues02);
    ASSERT_EQ(ret, 1);

    std::this_thread::sleep_for(std::chrono::seconds(2));
    ret = mySensorRecorder->write(inputValues03);
    ASSERT_EQ(ret, 1);

    mySensorRecorder->close();

    // read from the file
    std::vector<unsigned char> outputValues01 = mySensorRecorder->read(0);
    ASSERT_EQ(inputValues01, outputValues01);
}

错误:

Expected equality of these values:
  inputValues01
    Which is: { 'B' (66, 0x42), 'A' (65, 0x41), 'C' (67, 0x43) }
  outputValues01
    Which is: { 'B' (66, 0x42), 'A' (65, 0x41), 'C' (67, 0x43), '\xE4' (228), '\x16' (22), '\x7F' (127), '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', ... }

【问题讨论】:

  • data 显然是一个非空终止的字符串,outFile &lt;&lt; duration &lt;&lt; SEPARATOR &lt;&lt; data &lt;&lt; '\0' &lt;&lt; '\n'; 不是你如何去写一个空终止的字符串到输出流。您显然认识到 data 必须以 null 结尾,以便正确地编写为 C 样式字符串,但这不是您这样做的方式。您必须将'\0' 附加到data 本身,然后只写data

标签: c++ ifstream ofstream


【解决方案1】:

问题在于以空字符结尾的字符串。

char *data = reinterpret_cast<char *>(value.data());
outFile << duration << SEPARATOR << data << '\0' << '\n';

char* 本身的约定是以\0 结尾(要知道要写入多少个字符,strlen 将查找第一个可用的\0)。在你的情况下,它没有。你应该使用一个真正的字符串,或者至少使用:

outFile << duration << SEPARATOR << std::string(data, data+3) << '\n';

在此指令上添加\0 不会使字符串 null 被魔法终止。你必须保持大小。

(读取也有同样的缺陷)。

【讨论】:

    【解决方案2】:

    我将 write 方法更改为不将向量转换为 char 数组,然后我只是 push_back \0 字符。

    int SensorRecorder::write(std::vector<unsigned char> value) {
        if (outFile.is_open()) {
            auto now = std::chrono::system_clock::now();
            auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);
            auto v = now_ms.time_since_epoch();
    
            if (duration == -1) {
                duration = 0;
            } else {
                duration = v.count() - duration;
            }
            // write in the file
            value.push_back('\0');
    
            std::cout << value.size() << " " << value.data() << std::endl;
            outFile << duration << SEPARATOR << value.data() << '\n';
    
            // evaluate duration time to the next write
            duration = v.count();
        } else {
            std::cerr << "error writing..." << std::endl;
            return 0;
        }
        return 1;
    }
    

    【讨论】: