开发过程中,未意识到文件可能大于int的最大值,所以埋下了隐患。今天被测试提了个bug。主要原因是 QJsonValue toInt() 返回的是4字节的 int 类型,拿来存一个大于有符号四字节整数的值会溢出。这种边界值界定不明确导致bug的情况还是比较常见,做个总结分享帮助大家避坑。

此外就是csdn上对于这块的教程属实是又少又粗略。

* 本程序是测试Qt 程序存储64位整数 至Json文件 并加载读出 # include <QtCore/QCoreApplication> # include <QJsonObject> # include <QJsonValue> # include <QDebug> # include <QDir> # include <QJsonDocument> # include <QByteArray> # include <iostream> # include <climits> # include <cfloat> # include <iomanip> void printTypeInfo ( ) ; Type Size(bytes) Minimum Maximum ------------------------------------------------------------------------------------------------------------ bool 1 char 1 -128 127 int 4 -2147483648 2147483647 uint 4 4294967295 short 2 -32768 32767 ushort 2 65535 long 4 -2147483648 2147483647 ulong 4 4294967295 ll 8 -9223372036854775808 9223372036854775807 ull 8 18446744073709551615 float 4 1.17549e-038 3.40282e+038 double 8 2.22507e-308 1.79769e+308 ldouble 8 2.22507e-308 1.79769e+308 ------------------------------------------------------------------------------------------------------------ int main ( int argc , char * argv [ ] ) QCoreApplication a ( argc , argv ) ; //printTypeInfo(); using namespace std ; /************************************************************************/ * 第一部分、往文件中写 /************************************************************************/ // 创建JSON对象 QJsonObject root ; // 创建fileList数组 QJsonObject obj ; obj [ "path" ] = "YangNaifeng" ; qint64 llData = 1 ; // LLONG_MAX; obj [ "size" ] = llData ; //最大15位 root . insert ( "fileList" , obj ) ; QJsonDocument doc ; doc . setObject ( root ) ; auto path = QCoreApplication :: applicationDirPath ( ) ; auto outJson = path + "/" + "sad.json" ; QDir dir ( path ) ; if ( dir . mkpath ( path ) ) QFile file ( outJson ) ; file . open ( QIODevice :: WriteOnly ) ; file . write ( doc . toJson ( ) ) ; file . close ( ) ; qCritical ( ) << QString :: fromStdWString ( L "创建文件夹失败!" ) ; /************************************************************************/ * 从文件中读 并解析 /************************************************************************/ QFile readFile ( outJson ) ; readFile . open ( QIODevice :: ReadOnly ) ; QByteArray data = readFile . readAll ( ) ; QJsonDocument docRead = QJsonDocument :: fromJson ( data ) ; if ( ! docRead . isNull ( ) && docRead . isObject ( ) ) { QJsonObject obj = docRead . object ( ) ; if ( obj . contains ( "fileList" ) && obj [ "fileList" ] . isObject ( ) ) { QJsonObject fileListObj = obj [ "fileList" ] . toObject ( ) ; QString path = fileListObj [ "path" ] . toString ( ) ; auto eDoubleType = QJsonValue :: Double ; cout << fileListObj [ "size" ] . type ( ) ; //QJsonValue::Double auto size = fileListObj [ "size" ] . toDouble ( ) ; qint64 nSize = QString :: number ( size , 'f' , 0 ) . toLongLong ( ) ; qDebug ( ) << "Path:" << path ; qDebug ( ) << "Size:" << size ; qDebug ( ) << "fileList not found" ; qDebug ( ) << "Invalid JSON document" ; return a . exec ( ) ; void printTypeInfo ( ) using namespace std ; // 设置表格样式 cout << left ; cout << setw ( 8 ) << "Type" ; cout << setw ( 22 ) << "Size(bytes)" ; cout << setw ( 22 ) << "Minimum" ; cout << setw ( 22 ) << "Maximum" ; cout << endl ; cout << "------------------------------------" ; cout << "------------------------------------" ; cout << "------------------------------------" ; cout << endl ; // bool cout << setw ( 8 ) << "bool" ; cout << setw ( 22 ) << sizeof ( bool ) ; cout << setw ( 22 ) ; cout << setw ( 22 ) ; cout << endl ; // char cout << setw ( 8 ) << "char" ; cout << setw ( 22 ) << sizeof ( char ) ; cout << setw ( 22 ) << ( int ) CHAR_MIN ; cout << setw ( 22 ) << ( int ) CHAR_MAX ; cout << endl ; // int cout << setw ( 8 ) << "int" ; cout << setw ( 22 ) << sizeof ( int ) ; cout << setw ( 22 ) << INT_MIN ; cout << setw ( 22 ) << INT_MAX ; cout << endl ; // unsigned int cout << setw ( 8 ) << "uint" ; cout << setw ( 22 ) << sizeof ( unsigned int ) ; cout << setw ( 22 ) ; cout << setw ( 22 ) << UINT_MAX ; cout << endl ; // short cout << setw ( 8 ) << "short" ; cout << setw ( 22 ) << sizeof ( short ) ; cout << setw ( 22 ) << SHRT_MIN ; cout << setw ( 22 ) << SHRT_MAX ; cout << endl ; // unsigned short cout << setw ( 8 ) << "ushort" ; cout << setw ( 22 ) << sizeof ( unsigned short ) ; cout << setw ( 22 ) ; cout << setw ( 22 ) << USHRT_MAX ; cout << endl ; // long cout << setw ( 8 ) << "long" ; cout << setw ( 22 ) << sizeof ( long ) ; cout << setw ( 22 ) << LONG_MIN ; cout << setw ( 22 ) << LONG_MAX ; cout << endl ; // unsigned long cout << setw ( 8 ) << "ulong" ; cout << setw ( 22 ) << sizeof ( unsigned long ) ; cout << setw ( 22 ) ; cout << setw ( 22 ) << ULONG_MAX ; cout << endl ; // long long cout << setw ( 8 ) << "ll" ; cout << setw ( 22 ) << sizeof ( long long ) ; cout << setw ( 22 ) << LLONG_MIN ; cout << setw ( 22 ) << LLONG_MAX ; cout << endl ; // unsigned long long cout << setw ( 8 ) << "ull" ; cout << setw ( 22 ) << sizeof ( unsigned long long ) ; cout << setw ( 22 ) ; cout << setw ( 22 ) << ULLONG_MAX ; cout << endl ; // float cout << setw ( 8 ) << "float" ; cout << setw ( 22 ) << sizeof ( float ) ; cout << setw ( 22 ) << FLT_MIN ; cout << setw ( 22 ) << FLT_MAX ; cout << endl ; // double cout << setw ( 8 ) << "double" ; cout << setw ( 22 ) << sizeof ( double ) ; cout << setw ( 22 ) << DBL_MIN ; cout << setw ( 22 ) << DBL_MAX ; cout << endl ; // long double cout << setw ( 8 ) << "ldouble" ; cout << setw ( 22 ) << sizeof ( long double ) ; cout << setw ( 22 ) << LDBL_MIN ; cout << setw ( 22 ) << LDBL_MAX ; cout << endl ; cout << "------------------------------------" ; cout << "------------------------------------" ; cout << "------------------------------------" ;

1. QJsonValue 存储整数是按照double类型存储的,即使是1这么一个很小的数。

2. QJsonValue toInt() 是提供了double到int的转换。而不是文件本身存的就是 int 类型的数据。

3. QJsonValue 之所以没有 tolonglong() 的接口是因为 double 类型是有精度损失的。 double 类型的有效数字位数:15-16位数字,double类型的有效数字位数是15位还是16位,主要取决于浮点数的值:a. 对于绝对值在1.0和 2^53 之间的正常值,double类型一般能表示15位有效数字。b. 当浮点数接近0时,指数部位全部为0,此时有效数字位数可以达到16位。3. 当浮点数接近 2^53 时,指数部位为最大值,此时有效数字位数只有15位。

4.为啥Qt存整数到Json不是按整形存,而是以double类型存?

为什么JSON不支持 int64 类型?

通过上面的介绍有两个关键点:

  1. JSON 是基于 JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999的一个子集
  2. JSON 支持number 类型

Javascript的数字存储使用了IEEE 754中规定的双精度浮点数数据类型,而这一数据类型能够安全存储 -(2^53-1) 到 2^53-1 之间的数值(包含边界值)。JSON 是 Javascript 的一个子集,所以它也遵守这个规则。

以下是rfc7159的说明:

Note that when such software is used, numbers that are integers and are in the range [-(2^53)+1, (2^53)-1] are interoperable in the sense that implementations will agree exactly on their numeric values.

这两个边界值可以通过 JavaScript 的 Number.MAX_SAFE_INTEGER 和 Number.MIN_SAFE_INTEGER 获取。

5. 对于特别大的数,保证精度首选字符串。

GMP是开源的数学运算库。当 Qt 自带的q int 64 (依赖系统位数)也满足不了长度时,可以用它进行 数据 计算。     最近写的下载器 ,当下载到2点几G时,突然出现startPo int 与endPo int 变为负数,导致http的Range请求头部出错。网上一查,原来是整数溢出。如下代码: q int 64 startPo int =0; q int 64 endPo int =0; int index=-
QFile file("file. json "); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { return; Q Json Document doc = Q Json Document::from Json (file.readAll()); Q Json Object json = doc.object(); // 读取字符串类型的值 QString str Value = json . value ("str_key").toString(); // 读取整数类型的值 int int Value = json . value (" int _key").to Int (); // 读取数组类型的值 Q Json Array array = json . value ("array_key").toArray(); for ( int i = 0; i < array.size(); ++i) { QString str = array.at(i).toString(); // Do something file.close(); 2. 修改 JSON 数据 ```cpp Q Json Object json ; json .insert("str_key", "new_ value "); // 修改整数类型的值 json .insert(" int _key", 100); // 修改数组类型的值 Q Json Array array; array.append("new_element"); json .insert("array_key", array); Q Json Document doc( json ); QFile file("file. json "); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { return; file.write(doc.to Json ()); file.close(); 注意:在修改 JSON 数据 时,需要先创建 一个 新的Q Json Object对象,然后插入/修改需要修改的键值对,最后再将新创建的Q Json Object对象转换成Q Json Document对象并写入文件