读取自定义 (.ndev) Json 类文件结构
Reading custom (.ndev) Json-like file structure
我目前正在创建自定义文件结构(文件扩展名为 .ndev),以提高我在 C++ 中处理文件的技能。我可以以特定方式将值保存到文件中(见下文)
{
"username": "Nikkie",
"password": "test",
"role": "Developer",
"email": "test@gmail.com"
}
This doesn't have anything to do with actual JSON, it's just
structured like it.
我的问题是,如何使用 C++ 读取其中一个变量的值,而不像下面的屏幕截图那样显示出来:
我当前写入文件的代码:
void user::RegisterUser(string username, string password, string role, string email)
{
string filename = "E:\Coding\C\test\data\" + username + ".ndev";
ifstream CheckFile(filename);
if (CheckFile.good())
{
printf("User already exists!");
}
else {
ofstream UserDataFile(filename);
UserDataFile << "{\n\t\"username\": \"" << username << "\",\n\t\"password\": \"" << password << "\",\n\t\"role\": \"" << role << "\",\n\t\"email\": \"" << email << "\"\n}";
UserDataFile.close();
}
CheckFile.close();
}
Don't bludgeon me about the password encryption, I will add that later. I'm currently
trying to actually let it read the values before I do anything else
我当前读取文件的代码:
void user::LoginUser(string username)
{
string filename = "E:/Coding/C/test/data/" + username + ".ndev";
ifstream UserFile(filename, ios_base::in);
if (UserFile.good())
{
string name;
string passw;
string role;
string email;
while (UserFile >> name >> passw >> role >> email)
{
cout << name << passw << endl;
cout << role << email << endl;
}
}
else
{
printf("User doesn't exist!");
}
}
我似乎无法让它正确显示值,控制台和 VS 调试版本中也没有列出任何错误。
从实用的角度来看,没有理由以这种格式存储您的结构。还有更简单的方法。
无论如何,这是一个起点(demo):
#include <iostream>
#include <string>
#include <map>
#include <iomanip>
#include <fstream>
using namespace std;
// your structure
struct person
{
string name, pass, role, mail;
};
// the tokens your format is using
enum class token : char
{
lb = '{',
rb = '}',
sc = ':',
comma = ',',
str,
end
};
token tk; // current token
string str; // if the current token is token::str, str is its value
// get_token breaks the input stream into tokens - this is the lexer, or tokenizer, or scanner
token get_token(istream& is)
{
char c;
if (!(is >> c))
return tk = token::end;
switch (c)
{
case '{':
case '}':
case ':':
case ',':
return tk = token(c);
case '"':
is.unget();
is >> quoted(str);
return tk = token::str;
default: throw "unexpected char";
}
}
// throws if the current token is not the expected one
void expect(istream& is, token expected, const char* error)
{
if (tk != expected)
throw error;
get_token(is);
}
// throws if the current token is not a string
string expect_str(istream& is, const char* error)
{
if (tk != token::str)
throw error;
string s = str;
get_token(is);
return s;
}
// the actual parser; it extracts the tokens one by oneand compares them with the expected order.
// if the order is not what it expects, it throws an exception.
void read(istream& is, person& p)
{
get_token(is); // prepare the first token
expect(is, token::lb, "'{' expected");
map<string, string> m; // key/values storage
while (tk == token::str)
{
string k = expect_str(is, "key expected");
expect(is, token::sc, "':' expected");
string v = expect_str(is, "value expected");
if (m.find(k) == m.end())
m[k] = v;
else
throw "duplicated key";
if (tk == token::comma)
get_token(is);
else
break; // end of of key/value pairs
}
expect(is, token::rb, "'}' expected");
expect(is, token::end, "eof expected");
// check the size of m & the keys & copy from m to p
// ...
}
int main()
{
ifstream is{ "c:/temp/test.txt" };
if (!is)
return -1;
try
{
person p;
read(is, p);
}
catch (const char* e)
{
cout << e;
}
}
我目前正在创建自定义文件结构(文件扩展名为 .ndev),以提高我在 C++ 中处理文件的技能。我可以以特定方式将值保存到文件中(见下文)
{
"username": "Nikkie",
"password": "test",
"role": "Developer",
"email": "test@gmail.com"
}
This doesn't have anything to do with actual JSON, it's just structured like it.
我的问题是,如何使用 C++ 读取其中一个变量的值,而不像下面的屏幕截图那样显示出来:
我当前写入文件的代码:
void user::RegisterUser(string username, string password, string role, string email)
{
string filename = "E:\Coding\C\test\data\" + username + ".ndev";
ifstream CheckFile(filename);
if (CheckFile.good())
{
printf("User already exists!");
}
else {
ofstream UserDataFile(filename);
UserDataFile << "{\n\t\"username\": \"" << username << "\",\n\t\"password\": \"" << password << "\",\n\t\"role\": \"" << role << "\",\n\t\"email\": \"" << email << "\"\n}";
UserDataFile.close();
}
CheckFile.close();
}
Don't bludgeon me about the password encryption, I will add that later. I'm currently trying to actually let it read the values before I do anything else
我当前读取文件的代码:
void user::LoginUser(string username)
{
string filename = "E:/Coding/C/test/data/" + username + ".ndev";
ifstream UserFile(filename, ios_base::in);
if (UserFile.good())
{
string name;
string passw;
string role;
string email;
while (UserFile >> name >> passw >> role >> email)
{
cout << name << passw << endl;
cout << role << email << endl;
}
}
else
{
printf("User doesn't exist!");
}
}
我似乎无法让它正确显示值,控制台和 VS 调试版本中也没有列出任何错误。
从实用的角度来看,没有理由以这种格式存储您的结构。还有更简单的方法。
无论如何,这是一个起点(demo):
#include <iostream>
#include <string>
#include <map>
#include <iomanip>
#include <fstream>
using namespace std;
// your structure
struct person
{
string name, pass, role, mail;
};
// the tokens your format is using
enum class token : char
{
lb = '{',
rb = '}',
sc = ':',
comma = ',',
str,
end
};
token tk; // current token
string str; // if the current token is token::str, str is its value
// get_token breaks the input stream into tokens - this is the lexer, or tokenizer, or scanner
token get_token(istream& is)
{
char c;
if (!(is >> c))
return tk = token::end;
switch (c)
{
case '{':
case '}':
case ':':
case ',':
return tk = token(c);
case '"':
is.unget();
is >> quoted(str);
return tk = token::str;
default: throw "unexpected char";
}
}
// throws if the current token is not the expected one
void expect(istream& is, token expected, const char* error)
{
if (tk != expected)
throw error;
get_token(is);
}
// throws if the current token is not a string
string expect_str(istream& is, const char* error)
{
if (tk != token::str)
throw error;
string s = str;
get_token(is);
return s;
}
// the actual parser; it extracts the tokens one by oneand compares them with the expected order.
// if the order is not what it expects, it throws an exception.
void read(istream& is, person& p)
{
get_token(is); // prepare the first token
expect(is, token::lb, "'{' expected");
map<string, string> m; // key/values storage
while (tk == token::str)
{
string k = expect_str(is, "key expected");
expect(is, token::sc, "':' expected");
string v = expect_str(is, "value expected");
if (m.find(k) == m.end())
m[k] = v;
else
throw "duplicated key";
if (tk == token::comma)
get_token(is);
else
break; // end of of key/value pairs
}
expect(is, token::rb, "'}' expected");
expect(is, token::end, "eof expected");
// check the size of m & the keys & copy from m to p
// ...
}
int main()
{
ifstream is{ "c:/temp/test.txt" };
if (!is)
return -1;
try
{
person p;
read(is, p);
}
catch (const char* e)
{
cout << e;
}
}