资料库: 无需 DLL 的文件映射 - 页 11

 
o_o:

不是关闭记录,而是关闭并删除文件

这就是为什么

你试图打开的东西已经不存在了。

通过查看库代码,我发现不仅在直接调用 CMemMapFile 类的 Close() 函数时文件会被删除,而且在删除指向该类对象的指针时文件也会被删除,因为该函数是在类的析构函数中调用的。我有点困惑。原来,如果在不同的调用上下文(作用域)中使用写文件和读取文件,就无法使用创建类对象的动态方法。例如,终端的一个图表向文件写入数据,第二个图表读取数据并删除该文件。事实证明,对象变量应始终保持在全局级别,这样文件才不会被强制删除。另外,我们还不清楚是否可以不指定读取数据的大小。也就是说,在写入数据时,我们知道数据的大小,但在另一个图表上读取数据时,我们可能事先不知道数据的大小,例如字符串值。可能是我误解了什么,也可能是库中还有其他需要调整的地方。

是我不好。我重新检查了一下,没有使用指针,因此也没有使用删除。在这种情况下,当离开作用域(从函数)时,类对象的局部变量将被销毁,而无需明确调用析构函数。

关于接收方接收数据的大小,还有一个问题。

 
fxsaber:

感谢作者提供该库!

我制作了用于传输任何数据的函数。下面的脚本展示了它们在刻度线示例中的工作情况


结果


超级棒!通过与您的代码进行类比,我简化了库的使用

 
MT4 价格转移示例

交易、自动交易系统和交易策略测试论坛

Metatrader 4 的命名管道

fxsaber, 2017.11.30 14:18

Exchange_Data.mqh

#include <MemMapLib.mqh>
#include <TypeToBytes.mqh>

template <typename T>
class EXCHANGE_DATA
{
private:
  CMemMapFile* FileMemory;

public:  
  // 为数据分配指定长度的内存 
  EXCHANGE_DATA( const int Amount, const bool ModeCreate = false, string FileName = "Local\\test" )
  {
// FileName += _Symbol;
    
    this.FileMemory = new CMemMapFile;
      
    if (this.FileMemory.Open(FileName, sizeof(T) * Amount + sizeof(int) + HEAD_MEM, ModeCreate ? modeCreate : modeOpen) != 0)
    {
      Alert("FileMemory.Open - ERROR!");
      
      delete &this;
    }
  }
  
  ~EXCHANGE_DATA( void )
  {
    this.FileMemory.Close();
    
    delete this.FileMemory;
  }

  // 将数据写入内存
  void DataSave( const T &Data[], const bool FromBegin = true  ) const
  {
    const int Size = ::ArraySize(Data) * sizeof(T);
    uchar Bytes[];
    
    _ArrayCopy(Bytes, _R(Size).Bytes);              // 记录数量 
    _ArrayCopy(Bytes, _R(Data).Bytes, sizeof(int)); // 记录数据
  
        if (FromBegin)
          this.FileMemory.Seek(0, SEEK_SET);
  
        this.FileMemory.Write(Bytes, ::ArraySize(Bytes)); // 将所有内容转入内存
    
    return;
  }
  
  // 从内存中读取数据
  int DataLoad( T &Data[], const bool FromBegin = true ) const
  {
        if (FromBegin)
          this.FileMemory.Seek(0, SEEK_SET);
  
        uchar Bytes[];
          
        this.FileMemory.Read(Bytes, sizeof(int));  // 从内存中读取数据量 
        this.FileMemory.Read(Bytes, _R(Bytes)[0]); // 获取数据本身
  
        _ArrayCopy(Data, Bytes);              // 将数据转入数组
    
    return(::ArraySize(Data));
  }  
};


PriceGiver.mq4

#property strict

#include "Exchange_Data.mqh"

#define  AMOUNT 100

EXCHANGE_DATA<MqlTick> ExchangeTicks(AMOUNT, true);

const bool Init = EventSetMillisecondTimer(100);

void OnTimer( void )
{
  static MqlTick Ticks[1];
  
  if (SymbolInfoTick(_Symbol, Ticks[0]))
    ExchangeTicks.DataSave(Ticks);
}


PriceTaker.mq4

#property strict

#include "Exchange_Data.mqh"

#define  AMOUNT 100

EXCHANGE_DATA<MqlTick> ExchangeTicks(AMOUNT);

const bool Init = EventSetMillisecondTimer(100);

#define  TOSTRING(A) (#A + " = " + (string)(A) + " ")

void OnTimer( void )
{  
  static MqlTick PrevTick = {0};  
  MqlTick Ticks[];
  
  if ((ExchangeTicks.DataLoad(Ticks) > 0) &&
      ((Ticks[0].bid != PrevTick.bid) || (Ticks[0].ask != PrevTick.ask)))
  {
    Print(TOSTRING(Ticks[0].time) + TOSTRING(Ticks[0].bid) + TOSTRING(Ticks[0].ask));
    
    PrevTick = Ticks[0];
  }
}


运行PriceGiver.ex4PriceTaker. ex4


结果

2017.11.30 15:13:55.101 Expert PriceGiver EURUSD,M1: removed
2017.11.30 15:13:55.091 PriceGiver EURUSD,M1: uninit reason 1
2017.11.30 15:13:51.006 Expert PriceTaker GBPAUD,M1: removed
2017.11.30 15:13:50.996 PriceTaker GBPAUD,M1: uninit reason 1
2017.11.30 15:13:49.168 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:41 Ticks[0].bid = 1.18483 Ticks[0].ask = 1.18487 
2017.11.30 15:13:48.838 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:41 Ticks[0].bid = 1.18484 Ticks[0].ask = 1.18489 
2017.11.30 15:13:48.186 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:40 Ticks[0].bid = 1.18483 Ticks[0].ask = 1.18487 
2017.11.30 15:13:47.751 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:40 Ticks[0].bid = 1.18484 Ticks[0].ask = 1.18488 
2017.11.30 15:13:42.178 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:34 Ticks[0].bid = 1.18485 Ticks[0].ask = 1.18489 
2017.11.30 15:13:41.633 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:34 Ticks[0].bid = 1.18484 Ticks[0].ask = 1.18488 
2017.11.30 15:13:37.588 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:30 Ticks[0].bid = 1.18483 Ticks[0].ask = 1.18487 
2017.11.30 15:13:36.175 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:28 Ticks[0].bid = 1.18481 Ticks[0].ask = 1.18485 
2017.11.30 15:13:30.717 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:23 Ticks[0].bid = 1.18482 Ticks[0].ask = 1.18486 
2017.11.30 15:13:29.514 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:22 Ticks[0].bid = 1.18483 Ticks[0].ask = 1.18487 
2017.11.30 15:13:27.324 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:19 Ticks[0].bid = 1.1848 Ticks[0].ask = 1.18484 
2017.11.30 15:13:26.994 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:19 Ticks[0].bid = 1.18482 Ticks[0].ask = 1.18486 
2017.11.30 15:13:26.012 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:18 Ticks[0].bid = 1.18481 Ticks[0].ask = 1.18485 
2017.11.30 15:13:25.584 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:18 Ticks[0].bid = 1.18482 Ticks[0].ask = 1.18486 
2017.11.30 15:13:25.254 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:16 Ticks[0].bid = 1.18481 Ticks[0].ask = 1.18485 
2017.11.30 15:13:25.147 PriceTaker GBPAUD,M1: initialized
2017.11.30 15:13:24.049 Expert Sparring\PriceTaker GBPAUD,M1: loaded successfully
2017.11.30 15:13:21.157 PriceGiver EURUSD,M1: initialized
2017.11.30 15:13:19.617 Expert Sparring\PriceGiver EURUSD,M1: loaded successfully
 

库中的 CMemMapFile::Open 方法有一个小错误,它应该返回文件句柄(HANDLE64 类型),但却返回 0 或错误代码

此外,读取和写入方法 CMemMapApi::Write 和 CMemMapApi::Read 由于某种原因会重复复制数据(字节被循环遍历!),而且文件会被整体覆盖/读取,尽管只需要指定的部分。

总的来说,我让它们看起来很正常,不必要的内容都注释掉了:

//------------------------------------------------------------------ Write
int CMemMapApi::Write(HANDLE64 hmem, const uchar &buf[], DWORD pos, int sz, DWORD &err) // 将指定字节数写入内存
{
  if (hmem==NULL) return(-1);
  PBYTE64 view=ViewFile(hmem, err);  if (view==0 || err!=0) return(-1); // 如果未打开
  DWORD size=GetSize(hmem, err);  if (pos+sz>size) { UnViewFile(view);  return(-2); }; // 如果尺寸较小,则退出
  /*
 uchar src[]; ArrayResize(src, size); memcpyX(src, view, size); // took bytebuffer
 for(int i=0. i<sz; i++);i<sz; i++) src[pos+i+HEAD_MEM]=buf[i]; // 写入内存
 memcpyX(view, src, size); // 复制回
 */    
  memcpyX(view+HEAD_MEM+pos, buf, sz);  
  UnViewFile(view); // 关闭视图
  return(0); // 返回 OK。
}
//------------------------------------------------------------------ Read
int CMemMapApi::Read(HANDLE64 hmem, uchar &buf[], DWORD pos, int sz, DWORD &err) // 从内存中读取指定的字节数
{
  if (hmem==NULL) return(-1);
  PBYTE64 view=ViewFile(hmem, err);  if (view==0 || err!=0) return(-1); // 如果未打开
  DWORD size=GetSize(hmem, err); // 得到了尺寸
  /*
 uchar src[]; ArrayResize(src, size); memcpyX(src, view, size); // took bytebuffer
 ArrayResize(buf, sz);
 int i=0; for(i=0; i<sz && pos+i<size; i++) buf[i]=src[pos+i+HEAD_MEM]; // 读取字节
 */    
  sz= fmin(sz, size-pos);
  ArrayResize(buf, sz);
  memcpyX(buf, view+HEAD_MEM+pos, sz);
  UnViewFile(view); // 关闭视图
  return sz; // 复制的字节数
}
为了使第一个函数能够编译,需要在memcpyXmemcpy 函数中为数组设置const,而作者并没有设置。
 

复制大尺寸时出错,原因是在 dwMaximumSizeHigh 中传递了 0

        if (mode==modeCreate) 
           hmem=CreateFileMappingWX(INVALID_HANDLE_VALUE64, NULL, PAGE_READWRITE, 0, size + HEAD_MEM, path); // 创建一个内存对象

这样修复:

if (mode==modeCreate) 
           hmem=CreateFileMappingWX(INVALID_HANDLE_VALUE64, NULL, PAGE_READWRITE, size + HEAD_MEM, size + HEAD_MEM, path); // 创建一个内存对象


该文件大小为 6 MB,传输没有问题:

void OnStart()
{
   int bars = Bars(_Symbol, _Period);
   MqlRates rates[]; 
   ArraySetAsSeries(rates, true); 
   CopyRates(NULL, 0, 0, bars, rates); 

   int size = ArraySize(rates) * sizeof(MqlRates);
   
   uchar data[];
   _ArrayCopy(data, rates);
   
   CMemMapFile *hmem = new CMemMapFile();
   hmem.Open("test", size, modeCreate);
   hmem.Write(data, size);
   hmem.Close(); 
   delete hmem;

   Print(size);
}


 
pushdib:

更正如下

正确传递 8 字节大小的高 4 字节。

 

好了,现在我们有了 C# 程序中的所有命令,我们可以使用 LINQ 分析我们需要的一切。

但有一个问题,如何组织终端和应用程序之间的命令机制。

从终端:新建蜡烛,新建数据--获取文件

从应用程序:计算完成,获取结果(在图表上绘图,打开交易)。


有谁在终端和代码之间的交互执行方面有经验?

 
pushdib:

好了,现在我们有了 C# 程序中的所有数据,可以使用 LINQ 完美地分析一切了。

但还有一个问题,那就是如何组织终端和应用程序之间的命令机制。

从终端:新建蜡烛、新建速率--获取文件

从应用程序:计算完成,获取结果(在图表上绘制,打开交易)。


有没有人有过这种实现终端和代码之间交互的经验?

我都是通过 pip 实现的--工作起来就像发条一样。
 
这真是太棒了,感谢您的辛勤劳动!-)).我不得不同时学习如何处理二进制文件,但这是值得的。
 

请告知在这种情况下该怎么办。

1. 我在内存中打开了一个 100 字节的新文件。

2.我向其中写入了 100 字节。

3.我在另一个智能交易系统中读取了 100 字节。一切正常。

4.现在如何向同一文件写入 50 或 200 字节?