gnu FORTRAN无格式文件记录标记存储为64位宽度?

时间:2015-08-17 15:24:13

标签: file fortran gnu

我有遗留代码和一些未读取的数据文件,并且它与gnu-4.1.2配合使用。我无权访问最初生成这些数据文件的方法。当我使用较新的gnu编译器(gnu-4.7.2)编译此代码并尝试在另一台计算机上加载旧数据文件时,它很难读取它们。我首先打开文件并读取包含三个32位整数的第一条记录:

open(unit, file='data.bin', form='unformatted', status='old')
read(unit) x,y,z

我希望这里的这三个整数描述x,y,z跨度,以便接下来它可以加载具有相同尺寸的float值的3D矩阵。但是,相反,它为第一个值加载0,然后接下来的两个是偏移的。

期待:

x=26, y=127, z=97    (1A, 7F, 61 in hex)

加载:

x=0, y=26, z=127     (0, 1A, 7F in hex)

当我在十六进制编辑器中检查数据文件时,我想我已经知道发生了什么。

hex editor

在这种情况下,第一个记录标记的值为12(十六进制为0C),因为它正在读取每个4个字节的三个整数。此标记存储在之前的记录之后的。但是,我注意到每个记录标记后面的32位是00000000。因此,记录标记被视为64位整数(little-Endian)或每个记录标记后有32位零填充。无论哪种方式,使用新编译器生成的代码都将记录标记读取为32位整数,而不期望任何填充。这有效地侵入/破坏了正在读取的数据。

有没有一种简单的方法来解决这个不可移植的问题?新旧硬件是64位架构,我编译的可执行文件也是如此。如果我再次尝试使用较旧的编译器版本,它会解决问题,还是依赖于硬件?我更喜欢使用较新的编译器,因为它们更有效率,我真的不想编辑源代码以打开所有文件access='stream'并手动读取尾随的0整数在每个记录之后,在每个记录之前和之后。

P.S。我可以写一个C ++代码来改变数据文件,如果没有更容易的替代方法,就删除这些零填充。

2 个答案:

答案 0 :(得分:2)

请参阅gfortran手册中的-frecord-marker =选项。使用-frecord-marker = 8,您可以读取旧版本gfortran生成的旧式无格式顺序文件。

答案 1 :(得分:0)

看到Fortran没有对此进行标准化,我选择将数据文件转换为使用32位宽记录长度而不是64位宽度的新格式。如果将来有人需要这样做,我在这里包含了一些对我有用的Visual C ++代码,应该可以很容易地修改为C或其他语言。我还上传了Windows executable (fortrec.zip) here

CFile OldFortFile, OutFile; 
const int BUFLEN = 1024*20;
char pbuf[BUFLEN];
int i, iIn, iRecLen, iRecLen2, iLen, iRead, iError = 0;

CString strInDir = "C:\folder\";
CString strIn = "file.dat";
CString strOutDir = "C:\folder\fortnew\"
system("mkdir \"" + strOutDir + "\""); //create a subdir to hold the output files
strIn = strInDir + strIn;
strOut = strOutDir + strIn;
if(OldFortFile.Open(strIn,CFile::modeRead|CFile::typeBinary)) {
    if(OutFile.Open(strOut,CFile::modeCreate|CFile::modeWrite|CFile::typeBinary)) {
        while(true) {
            iRead = OldFortFile.Read(&iRecLen, sizeof(iRecLen)); //Read the record's raw data
            if (iRead < sizeof(iRecLen)) //end of file reached
                break;
            OutFile.Write(&iRecLen, sizeof(iRecLen));//Write the record's raw data
            OldFortFile.Read(&iIn, sizeof(iIn));
            if (iIn != 0) {//this is the padding we need to ignore, ensure it's always zero
                //Padding not found
                iError++;
                break;
            }
            i = iRecLen;
            while (i > 0) {
                iLen = (i > BUFLEN) ? BUFLEN : i;
                OldFortFile.Read(&pbuf[0], iLen);
                OutFile.Write(&pbuf[0], iLen);
                i -= iLen;
            }
            if (i != 0) { //Buffer length mismatch  
                iError++;
                break;
            }
            OldFortFile.Read(&iRecLen2, sizeof(iRecLen2));
            if (iRecLen != iRecLen2) {//ensure we have reached the end of the record proeprly
                //Record length mismatch
                iError++;
                break;
            }
            OutFile.Write(&iRecLen2, sizeof(iRecLen));
            OldFortFile.Read(&iIn, sizeof(iIn));
            if (iIn != 0) {//this is the padding we need to ignore, ensure it's always zero
                    //Padding not found
                    break;
            }
        }
        OutFile.Close();
        OldFortFile.Close();
    }
    else { //Could not create the ouput file.
        OldFortFile.Close();
        return;
    }
}
else { //Could not open the input file

}
if (iError == 0)
    //File successfully converted
else
    //Encountered error