我是C ++文件io的新手,所以前几天我决定编写一个小程序,只读取一个UTF-8编码的字符串和一个二进制文件中的配对浮点数。模式是字符串浮点数,没有额外的数据或对之间的间距。 编辑我根据几个答案修改了代码。但是,输出保持不变(“RoommateAp 0”);
string readString (ifstream* file)
{
//Get the length of the upcoming string
uint16_t stringSize = 0;
file->read(reinterpret_cast<char*>(&stringSize), sizeof(char) * 2);
//Now that we know how long buffer should be, initialize it
char* buffer = new char[stringSize + 1];
buffer[stringSize] = '\0';
//Read in a number of chars equal to stringSize
file->read(buffer, stringSize);
//Build a string out of the data
string result = buffer;
delete[] buffer;
return result;
}
float readFloat (ifstream* file)
{
float buffer = 0;
file->read(reinterpret_cast<char*>(&buffer), sizeof(float));
return buffer;
}
int main()
{
//Create new file that's open for reading
ifstream file("movies.dat", ios::in|ios::binary);
//Make sure the file is open before starting to read
if (file.is_open())
{
while (!file.eof())
{
cout << readString(&file) << endl;
cout << readFloat(&file) << endl;
}
file.close();
}
else
{
cout << "Unable to open file" << endl;
}
}
来自文件的数据样本(可读性空间):
000C 54686520526F6F6D6D617465 41700000
可以看出,前两个字节是字符串的长度(本例中为12),后跟12个字符(拼写为“The Roommate”),最后四个字节是浮点数。
当我运行此代码时,唯一发生的事情是终端挂起,我必须手动关闭它。我想这可能是因为我正在阅读文件的结尾,但我不知道为什么会这样。我做错了什么?
答案 0 :(得分:5)
至少有两个问题。第一,行:
file->read(reinterpret_cast<char*>(stringSize), sizeof(char) * 2);
可能应该使用stringSize
的地址:
file->read(reinterpret_cast<char*>(&stringSize), sizeof(stringSize));
第二,行:
char* buffer = new char[stringSize];
没有分配足够的内存,因为它不考虑NUL
终结符。该代码应该像:
//Now that we know how long buffer should be, initialize it
char* buffer = new char[stringSize + 1];
//Read in a number of chars equal to stringSize
file->read(buffer, stringSize);
buffer[stringSize] = '\0';
最后,行:
return static_cast<string>(buffer);
从缓存中delete[]
实例化后,失败到string
,这将导致内存泄漏。
另请注意,std::string
的UTF-8支持开箱即用。幸运的是,有solutions。
答案 1 :(得分:2)
您的代码存在一些严重问题:
file->read(reinterpret_cast<char*>(stringSize), sizeof(char) * 2);
在此部分中,您将stringSize
的当前值转换为
一个指针。你的想法最有可能是传递地址
stringSize
变量。
char* buffer = new char[stringSize];
这会分配一个字符数组,但没有人会释放它。使用
std::vector<char> buffer(stringSize);
而不是记忆
管理将为您正确完成。
要获取缓冲区的地址,您可以使用&buffer[0]
。
return static_cast<string>(buffer);
你可能想要的是接受的字符串构造函数
指向第一个和最后一个字符的指针。换一种说法:
return std::string(&buffer[0], &buffer[0]+stringSize);
答案 2 :(得分:0)
您转换为字符数组。文件中的字符串大小编号是否包含空字符的空格?如果没有,你可能会在字符数组的末尾运行并在cout write上永远循环。
答案 3 :(得分:0)
您的代码存在一些问题。
您声明字符串的大小由4个字节指定,这意味着您应该使用uint32_t而不是uint16_t。
分配字符串缓冲区时,不释放使用的内存。
string readString(std::ifstream* file)
{
// Get the length of the upcoming string.
// The length of the string is specified with 4 bytes: use uint32_t, not uint16_t
uint32_t stringSize = 0;
file->read(reinterpret_cast<char*>(&stringSize), sizeof(uint32_t));
// Now that we know how long buffer should be, initialize it
char* buffer = new char[stringSize + 1];
buffer[stringSize] = '\0'; // null terminate the string
//Read in a number of chars equal to stringSize
file->read(buffer, stringSize);
string result = buffer;
delete[] buffer;
return result;
}