我想知道如何在Mathematica和C/C++之间使用管道交换数据。在Mathematica的tutorial中,它说“当您打开文件或管道时,Mathematica会创建一个“流对象”,指定与文件或管道关联的打开流”。
我知道如何在C和Mathematica中创建文件,并使每个程序读取和写入它们。但我仍然不知道如何通过管道从C发送输出到另一个程序,更不用说如何从Mathematica中做到这一点了。
下面是一个函数,在其中Mathematica将矩阵写入二进制文件,并读取以该格式编写的文件。
第一个函数将把2个整数(矩阵的大小)和矩阵的数据写入文件。我没有进行任何错误检查,因此假设要写入的数据特定形式为
接下来是我的C程序。该程序将读取存储在文件MathematicaData.bin中的数据,将此矩阵乘以2并将数据写入另一个文件。
这个程序没有任何错误检查。你需要小心使用它,否则程序可能无法检测到文件,甚至无法分配所需的内存量。无论如何,我们可以使用您选择的编译器编译程序。
现在我们可以尝试使用这些函数从Mathematica中与两种语言进行通信。
如果一切顺利,您应该得到的输出结果是:
这意味着我们必须像这样使用程序:
我一直在Mathematica文档中搜索,但我发现我只能通过管道外部命令来打开文件,例如
如果计算机系统支持管道,则
这意味着我可以直接将二进制输入传递给C程序。问题是我找不到一种重定向程序输出的方法。我的解决方法是,将数据写入文件,并创建一个包装器来运行外部命令并读取外部命令输出内容。这里我们假设之前存在
我知道如何在C和Mathematica中创建文件,并使每个程序读取和写入它们。但我仍然不知道如何通过管道从C发送输出到另一个程序,更不用说如何从Mathematica中做到这一点了。
下面是一个函数,在其中Mathematica将矩阵写入二进制文件,并读取以该格式编写的文件。
writeDoubleMatrix[obj_, fileName_] := Module[{file},
file = OpenWrite[fileName, BinaryFormat -> True];
BinaryWrite[file, Length@obj, "Integer32"];
BinaryWrite[file, Length@obj[[1]], "Integer32"];
BinaryWrite[file, Flatten[obj], "Real64"];
Close[file]
]
readDoubleMatrix[fileName_] := Module[{file, obj, m, n},
file = OpenRead[fileName, BinaryFormat -> True];
m = BinaryRead[file, "Integer32"];
n = BinaryRead[file, "Integer32"];
obj = BinaryReadList[file, "Real64", m*n];
Close[file];
Partition[obj, n]
]
第一个函数将把2个整数(矩阵的大小)和矩阵的数据写入文件。我没有进行任何错误检查,因此假设要写入的数据特定形式为
{{r11, r12, ..., r1n}, ...., {rm1, rm2, ..., rmn}}
。第二个函数可以读取二进制文件并返回矩阵。接下来是我的C程序。该程序将读取存储在文件MathematicaData.bin中的数据,将此矩阵乘以2并将数据写入另一个文件。
// genData.c
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char** argv){
int m, n, i;
double* matrix;
FILE* fin;
FILE* fout;
// Reading input file
fin = fopen(argv[1], "rb");
fread(&m, sizeof(int), 1, fin);
fread(&n, sizeof(int), 1, fin);
matrix = (double*)malloc(m*n*sizeof(double));
fread(matrix, sizeof(double), m*n, fin);
fclose(fin);
//Modifying data
for (i = 0; i < m*n; ++i) matrix[i] = 2*matrix[i];
// Writing output file
fout = fopen(argv[2], "wb");
fwrite(&m, sizeof(int), 1, fout);
fwrite(&n, sizeof(int), 1, fout);
fwrite(matrix, sizeof(double), m*n, fout);
fclose(fout);
// De-allocate memory used for matrix.
free(matrix);
return 0;
}
这个程序没有任何错误检查。你需要小心使用它,否则程序可能无法检测到文件,甚至无法分配所需的内存量。无论如何,我们可以使用您选择的编译器编译程序。
gcc -o genData genData.c
现在我们可以尝试使用这些函数从Mathematica中与两种语言进行通信。
matrix = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
writeDoubleMatrix[matrix, "MathematicaData.bin"];
Run["./genData MathematicaData.bin CData.bin"];
readDoubleMatrix["CData.bin"]
如果一切顺利,您应该得到的输出结果是:
{{2., 4., 6., 8.}, {10., 12., 14., 16.}, {18., 20., 22., 24.}}
是的,这是一种非常耗时的矩阵乘以2的方法,但这只是一个简单的示例,展示了如何从Mathematica到C,从C到Mathematica交换数据。
我不喜欢的是所有的数据都先存储到文件中,然后再在另一个程序中读取。有人能向我展示如何在不写入文件的情况下交换数据吗?我觉得管道可能是我需要的,但我不知道如何从任何一种语言中读取或写入它们。如果您可以修改此程序以适应管道,那将会很有帮助。
更新:
我发现如何使C程序“可管道化”。
//genDataPipe.c
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char** argv){
int m, n, i;
double* matrix;
// Reading input file
fread(&m, sizeof(int), 1, stdin);
fread(&n, sizeof(int), 1, stdin);
matrix = (double*)malloc(m*n*sizeof(double));
fread(matrix, sizeof(double), m*n, stdin);
//Modifying data
for (i = 0; i < m*n; ++i) matrix[i] = 2*matrix[i];
// Writing output file
fwrite(&m, sizeof(int), 1, stdout);
fwrite(&n, sizeof(int), 1, stdout);
fwrite(matrix, sizeof(double), m*n, stdout);
// Deallocate memory used for matrix.
free(matrix);
return 0;
}
这意味着我们必须像这样使用程序:
./genDataPipe < fileIn.bin > fileOut.bin
我一直在Mathematica文档中搜索,但我发现我只能通过管道外部命令来打开文件,例如
OpenWrite
:如果计算机系统支持管道,则
OpenWrite["!command"]
会运行指定的外部程序command
,并打开一个管道以将输入发送到该程序。这意味着我可以直接将二进制输入传递给C程序。问题是我找不到一种重定向程序输出的方法。我的解决方法是,将数据写入文件,并创建一个包装器来运行外部命令并读取外部命令输出内容。这里我们假设之前存在
writeDoubleMatrix
。getDataPipe[fileName_] := Module[{file, obj, m, n},
file = OpenRead["!./genDataPipe < " <> fileName,
BinaryFormat -> True];
m = BinaryRead[file, "Integer32"];
n = BinaryRead[file, "Integer32"];
obj = BinaryReadList[file, "Real64", m*n];
Close[file];
Partition[obj, n]
]
matrix = {{1, 2, 3}, {4, 5, 6}};
writeDoubleMatrix[matrix, "MData.bin"];
output = getDataPipe["MData.bin"]
这导致输出具有以下内容 {{2., 4., 6.}, {8., 10., 12.}}
。
现在唯一剩下的目标是找出如何消除writeDoubleMatrix
的需要,并直接传递数据而无需编写文件。