Origin自帶的Origin C語言允許用戶通過編程來更高效地完成大批量的作圖和數據處理。應該看到,Origin C本身有著較大的局限:不支持自定義函數返回結構體類型的數據( "Origin C doesn't support external functions that return a struct type variable", http://ocwiki.originlab.com/index.php?title=OCGuide:Calling_GNU_Scientific_Library ),在循環結構里的執行速度很慢,等。
因此,在必要的時候,我會自己寫個DLL供Origin C調用。如在這個帖子里:http://emuch.net/bbs/viewthread.php?tid=5432435,我給出的是Origin C寫的程序,現在稍加修改以便記錄執行耗時:
#include <Origin.h>
int imp_one_line()
{
string pstrOut;
okutil_FileDialog(&pstrOut, FALSE);
string pstrOut2;
struct tm *nowtime;
time_t aclock;
time(&aclock);
nowtime = localtime(&aclock);
pstrOut2 = pstrOut + "-" + (nowtime->tm_year + 1900) + "-" + (nowtime->tm_mon + 1) + "-" + (nowtime->tm_mday);
pstrOut2 = pstrOut2 + "-" + nowtime->tm_hour + "-" + nowtime->tm_min + "-" + nowtime->tm_sec + ".asc";
FILE *fp1,*fp2;
fp1 = fopen( pstrOut, "r" ) ;
fp2 = fopen(pstrOut2, "w" ) ;
fseek(fp1, 0L, SEEK_END ) ;
int f_end = ftell(fp1);
fseek(fp1, 0L, SEEK_SET ) ;
char *chrAll = (char*)calloc(f_end+1,sizeof(char) ) ;
if(!chrAll)
return -1;
fgets(chrAll,f_end,fp1 ) ; // only ONE line of data
MessageBox(GetWindow(), "Just for the first line of data. Please click OK to continue.","Warning!" ) ;
Sleep(300 ) ;
LT_execute("type -a Converting...." ) ;
DWORD dw1 = GetTickCount();
int lchrAll = lstrlen(chrAll ) ;
for(int i=0;i<lchrAll;i++)
if(44==(int)chrAll [ i ])
chrAll [ i ]=(char)10;
fputs(chrAll,fp2 ) ;
DWORD dw2 = GetTickCount();
Sleep(300 ) ;
LT_execute("type -a ....Done" ) ;
printf("%d ms\n",dw2-dw1);
fclose(fp1 ) ;
fclose(fp2 ) ;
Worksheet wks;
wks.Create("origin" ) ;
if(!wks)
return -2;
ASCIMP ai;
if( 0 == AscImpReadFileStruct(pstrOut2, &ai) )
if( 0 == wks.ImportASCII(pstrOut2, ai) )
out_str("Import data successful." ) ;
return 0;
}
執行結果顯示:
1> imp_one_line()=
Converting....
....Done
49407 ms
Import data successful.
imp_one_line()=0
下面用調用DLL的方法來看看執行效果如果:
1. 編譯生成DLL
先新建項目,名稱為ocDLL:
應用程序設置見:
在解決方案資源管理器里可以看到已經有好個文件準備好了,把源文件里的文件類型全部由".cpp"改為".c",見下圖:
需要編輯的各文件的內容見下:
ocDLL.h
// ocDLL.h
#ifdef OCDLL_EXPORTS
#define OCDLL_API __declspec(dllexport)
#else
#define OCDLL_API __declspec(dllimport)
#endif
OCDLL_API int o_delimiter_replace(FILE * fpSrc, FILE * fpDst, const char chSrc, const char chDst);
stdafx.h
// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件
//
#pragma once
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的信息
// Windows 头文件:
#include <windows.h>
// TODO: 在此处引用程序需要的其他头文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
ocDLL.c
#include "stdafx.h"
#include "ocDLL.h"
OCDLL_API int o_delimiter_replace(FILE * fpSrc, FILE * fpDst, const char chSrc, const char chDst)
{
long f_end;
long f_now;
long f_tmp;
unsigned long i;
unsigned long len_chAll;
char * chAll;
if( !(fpSrc && fpDst) )
return -1;
fseek( fpSrc, 0L, SEEK_END );
f_end = ftell( fpSrc );
fseek( fpSrc, 0L, SEEK_SET );
chAll = (char*)calloc( f_end+3, sizeof(char) );
if( !chAll )
return -2;
do{
f_tmp = ftell( fpSrc );
fgets( chAll, f_end+3, fpSrc );
f_now = ftell( fpSrc );
len_chAll = strlen(chAll);
for( i = 0; i < len_chAll; i++ )
if( chSrc == chAll[i] )
chAll[i] = chDst;
fputs( chAll, fpDst );
chAll[0] = 0;
}while(f_tmp < f_now );
return 0;
}
在解決方案配置為Release下,生成解決方案。如果生成成功,將在輸出窗口中看到大概如下的信息:
1>------ 已启动生成: 项目: ocDLL, 配置: Release Win32 ------
1> stdafx.c
1> dllmain.c
1> ocDLL.c
1> 正在创建库 d:\My Documents\Visual Studio 2010\Projects\ocDLL\Release\ocDLL.lib 和对象 d:\My Documents\Visual Studio 2010\Projects\ocDLL\Release\ocDLL.exp
1> 正在生成代码
1> 已完成代码的生成
1> ocDLL.vcxproj -> d:\My Documents\Visual Studio 2010\Projects\ocDLL\Release\ocDLL.dll
========== 生成: 成功 1 个,失败 0 个,最新 0 个,跳过 0 个 ==========
把生成的ocDLL.dll複製到Origin安裝目錄下的\OriginC\system\,再在該目錄里新建一個頭文件ocDLL.h:
#pragma dll(ocDLL,header)
int o_delimiter_replace(FILE * fpSrc, FILE * fpDst, char chSrc, char chDst);
把本文第一個程序代碼改為:
#include <origin.h>
#include <ocDLL.h>
int imp_one_line()
{
string pstrOut;
okutil_FileDialog(&pstrOut, FALSE);
string pstrOut2;
struct tm *nowtime;
time_t aclock;
time(&aclock);
nowtime = localtime(&aclock);
pstrOut2 = pstrOut + "-" + (nowtime->tm_year + 1900) + "-" + (nowtime->tm_mon + 1) + "-" + (nowtime->tm_mday);
pstrOut2 = pstrOut2 + "-" + nowtime->tm_hour + "-" + nowtime->tm_min + "-" + nowtime->tm_sec + ".asc";
FILE *fp1,*fp2;
fp1 = fopen( pstrOut, "r" ) ;
fp2 = fopen(pstrOut2, "w" ) ;
fseek(fp1, 0L, SEEK_END ) ;
int f_end = ftell(fp1);
fseek(fp1, 0L, SEEK_SET ) ;
char *chrAll = (char*)calloc(f_end+1,sizeof(char) ) ;
if(!chrAll)
return -1;
fgets(chrAll,f_end,fp1 ) ; // only ONE line of data
MessageBox(GetWindow(), "Just for the first line of data. Please click OK to continue.","Warning!" ) ;
Sleep(300 ) ;
LT_execute("type -a Converting...." ) ;
DWORD dw1 = GetTickCount();
/*
int lchrAll = lstrlen(chrAll ) ;
for(int i=0;i<lchrAll;i++)
if(44==(int)chrAll [ i ])
chrAll [ i ]=(char)10;
fputs(chrAll,fp2 ) ;
*/
o_delimiter_replace(fp1,fp2,',','\n');
DWORD dw2 = GetTickCount();
Sleep(300 ) ;
LT_execute("type -a ....Done" ) ;
printf("%d ms\n",dw2-dw1);
fclose(fp1 ) ;
fclose(fp2 ) ;
Worksheet wks;
wks.Create("origin" ) ;
if(!wks)
return -2;
ASCIMP ai;
if( 0 == AscImpReadFileStruct(pstrOut2, &ai) )
if( 0 == wks.ImportASCII(pstrOut2, ai) )
out_str("Import data successful." ) ;
return 0;
}
需要注意的是,上面的代碼在處理返回值方面有待改進。
編譯,執行,得:
2> imp_one_line()=
Converting....
....Done
188 ms
Import data successful.
imp_one_line()=0
儘管這樣子的比較不是很科學,但前後兩次所用時間差別很大,效率的提升相當明顯。