Bug in FileWriteString (MQL4)

 

Write string with FILE_UNICODE flag, as shown in the code, additional 7 bytes are written.

//+------------------------------------------------------------------+
//|                                     test_FileWriteString_bug.mq4 |
//|                                           Copyright 2021,fxMeter |
//|                            https://www.mql5.com/en/users/fxmeter |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021,fxMeter"
#property link      "https://www.mql5.com/en/users/fxmeter"
#property version   "1.00"
#property strict
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
{
//---
   string  str = "1234567";
   int     num = 32;//0x20
   string  file = WindowExpertName()+".bin";

//---write str and num
   int handle=FileOpen(file,FILE_BIN|FILE_WRITE|FILE_UNICODE);
   FileWriteString(handle,str,64);  //128 bytes
   printf("1. file pointer =%d",FileTell(handle));//135 ?  it should be 128, additional 7 bytes are filled
   FileWriteInteger(handle,num,INT_VALUE);
   printf("file size = %d",FileSize(handle)); //139
   FileClose(handle);

//---read
   printf("--------------");

   handle=FileOpen(file,FILE_BIN|FILE_READ|FILE_UNICODE);


   str=FileReadString(handle,64);
   printf("2. file pointer =%d",FileTell(handle));//128
   printf("str =%s",str);

   num=FileReadInteger(handle,INT_VALUE);
   printf("3. file pointer=%d",FileTell(handle));//132
   printf("num = %d",num); // num = 0

}
//+------------------------------------------------------------------+




 

It doesn't seem a bug, I believe the documentation should be modified, the current description says:

  • If you specify a size greater than the length of the string, the string is filled by the appropriate number of zeros.
The word 'appropriate' is ambiguous, in the code you provided, the length of 'str' is 7, the 'length' parameter is set to 64, which is greater than the length of the string, and the string is filled by 121 zeros. It is calculate by this formula: (('length' parameter) * 2) - (length of the string), ((64*2)-7) = 121.
 

Please note the file is created with FILE_UNICODE.

The length of "1234567" is 7 which means 14 bytes to write,and the length parameter is set to 64 which means 128 bytes to write, in this case,it should write 128 bytes,actually it wrote 135 bytes.

128 + 7 = 135, obviously the function added  additional 7 bytes 


https://docs.mql4.com/files/filewritestring

Note

Note that when writing to a file opened by the FILE_UNICODE flag (or without a flag FILE_ANSI), then the number of bytes written will be twice as large as the number of string characters written. When recording to a file opened with the FILE_ANSI flag, the number of bytes written will coincide with the number of string characters written.


FileWriteString - File Functions - MQL4 Reference
FileWriteString - File Functions - MQL4 Reference
  • docs.mql4.com
FileWriteString - File Functions - MQL4 Reference
 

Tested in MT5, the function FileWriteString works well.

//+------------------------------------------------------------------+
//|                                     test_FileWriteString_bug.mq5 |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
{
//---
   string  str = "1234567";
   int     num = 32;//0x20
   string  file = MQLInfoString(MQL_PROGRAM_NAME) + ".bin";
//---write str and num
   int handle = FileOpen(file,FILE_BIN | FILE_WRITE | FILE_UNICODE);
   FileWriteString(handle,str,64);  //128 bytes
   printf("1. file pointer =%d",FileTell(handle));//128
   FileWriteInteger(handle,num,INT_VALUE);
   printf("file size = %d",FileSize(handle)); //132
   FileClose(handle);
//---read
   printf("--------------");
   handle = FileOpen(file,FILE_BIN | FILE_READ | FILE_UNICODE);
   str = FileReadString(handle,64);
   printf("2. file pointer =%d",FileTell(handle));//128
   printf("str =%s",str);
   num = FileReadInteger(handle,INT_VALUE);
   printf("3. file pointer=%d",FileTell(handle));//132
   printf("num = %d",num); // num = 32
}
//+------------------------------------------------------------------+


 
Mohammad Hossein Sadeghi:

It doesn't seem a bug, I believe the documentation should be modified, the current description says:

  • If you specify a size greater than the length of the string, the string is filled by the appropriate number of zeros.
The word 'appropriate' is ambiguous, in the code you provided, the length of 'str' is 7, the 'length' parameter is set to 64, which is greater than the length of the string, and the string is filled by 121 zeros. It is calculate by this formula: (('length' parameter) * 2) - (length of the string), ((64*2)-7) = 121.


The total written bytes should be 128, the filled zero is 64*2 - 7*2 = 114 .

 
Ziheng Zhuang:

Please note the file is created with FILE_UNICODE.

The length of "1234567" is 7 which means 14 bytes to write,and the length parameter is set to 64 which means 128 bytes to write, in this case,it should write 128 bytes,actually it wrote 135 bytes.

128 + 7 = 135, obviously the function added  additional 7 bytes 

The length is different from bytes, the length of "1234567" is 7, but in case of bytes, it takes 14 bytes when encoded in UNICODE.

I agree that when the third parameter is greater than the length of the string, it should add zeros of the difference between the length of the string and the provided parameter, multiplied by 2 as it is to be encoded in UNICODE, like what is done in MT5, but I still think that the documentation needs clarification and the word "appropriate" is ambiguous, both in MQL4 and MQL5 documentation.

And current behavior of the function which is different in MQL4 compared to MQL5, should be changed to work the same.

 
If you want this issue to be fixed, it is required to post in Russian forum where Metaquotes developers usually read, and I'm not sure if they change it as the development of MT4 is stopped since long time ago, you should consider a work-around for this issue, like StringToShortArray and resize the array, add zeros of your choice, then write this array to the file.
 
Mohammad Hossein Sadeghi:
If you want this issue to be fixed, it is required to post in Russian forum where Metaquotes developers usually read, and I'm not sure if they change it as the development of MT4 is stopped since long time ago, you should consider a work-around for this issue, like StringToShortArray and resize the array, add zeros of your choice, then write this array to the file.

Thanks for your advice.

I have posted it in Russsian forum.

https://www.mql5.com/ru/forum/370000

Bug in FileWriteString (MQL4)
Bug in FileWriteString (MQL4)
  • 2021.05.25
  • www.mql5.com
// When write text into an unicode file, if the parameter length is specified, the written bytes should be the twice of the parameter length...
 
Ziheng Zhuang:

Thanks for your advice.

I have posted it in Russsian forum.

https://www.mql5.com/ru/forum/370000

When you post on Russian forum you should use the translation tool, it's more respectful for Russian readers.

And the appropriate topic to post bug reports is this one https://www.mql5.com/ru/forum/369007/page2

Новая версия платформы MetaTrader 4 build 1335: Улучшения для Wine/macOS
Новая версия платформы MetaTrader 4 build 1335: Улучшения для Wine/macOS
  • 2021.05.16
  • www.mql5.com
В пятницу 14 мая 2021 года будет выпущена обновленная версия платформы MetaTrader 4...
 
...
FileWriteString(handle,str, StringLen(str));
...
str=FileReadString(handle,StringLen(str));
everything works as it should ;-)
 
Alain Verleyen:

When you post on Russian forum you should use the translation tool, it's more respectful for Russian readers.

And the appropriate topic to post bug reports is this one https://www.mql5.com/ru/forum/369007/page2

Thanks. 

Good advice.

I have reedited the post with Russian using the translation tool.