未格式化的 I/O 给出了荒谬的值,或者我在 R 中错误地读取了它们
Either unformatted I/O is giving absurd values, or I'm reading them incorrectly in R
我有未格式化数据的问题,我不知道在哪里,所以我将 post 我的整个工作流程。
我正在将我自己的代码集成到现有的用 Fortran 语言编写的气候模型中,以从模型输出中生成自定义变量。我已经成功地获得了合理且可读的 formatted 输出(值高达数千),但是当我尝试编写 unformatted 输出时,值我得到的是荒谬的(在 1E10 的规模上)。
任何人都可以看看我的过程并看看我可能哪里出错了吗?
我无法对用于输出数据的整个代码进行功能复制,但相关片段是;
c write customvar to file [UNFORMATTED]
open (unit=10,file="~/output_test_u",form="unformatted")
write (10)customvar
close(10)
c write customvar to file [FORMATTED]
c open (unit=10,file="~/output_test_f")
c write (10,*)customvar
c close(10)
该模型 运行 两次,一次是注释掉了格式化代码,一次是注释掉了未格式化代码,尽管我现在意识到如果我使用的话我可以 运行 它一次不同的单位编号。无论哪种方式,不同的 运行 不应产生不同的值。
生成的文件可在此处获得;
为了解释这些文件,我使用了 R。以下代码是我用来读取每个文件并将它们整形为可比较矩阵的代码。
##Read in FORMATTED data
formatted <- scan(file="output_test_f",what="numeric")
formatted <- (matrix(formatted,ncol=64,byrow=T))
formatted <- apply(formatted,1:2,as.numeric)
##Read in UNFORMATTED data
to.read <- file("output_test_u","rb")
unformatted <- readBin(to.read,integer(),n=10000)
close(to.read)
unformatted <- unformatted[c(-1,-2050)] #to remove padding
unformatted <- matrix(unformatted,ncol=64,byrow=T)
unformatted <- apply(unformatted,1:2,as.numeric)
为了检查两个文件之间数据的一般结构是否相同,我检查了零值和非零值在每个矩阵中的相同位置(每个值代表一个网格方块,零代表有海的地方)使用;
as.logical(unformatted)-as.logical(formatted)
并且返回了一个零数组,表明这只是两者之间不同的值,而不是我塑造它们的方式。
为了了解这些值如何相互关联,我尝试绘制格式化值与未格式化值(注意所有零值都被删除)
如您所见,它们存在某种关系,因此值的 inflation 不是随机的。
我完全不明白为什么未格式化的数据值如此膨胀。我阅读和解释文件的方式有误吗? Fortran 是否有一些潜在的方式来写入改变值的未格式化数据?
Fortran写无格式文件常用的方法是:
- 一个前导记录标记,通常为四个字节,具有后面记录的长度
- 实际数据
- 尾随记录标记,字节数与前导记录标记相同,信息相同(用于退格)
记录标记中通常的字节数是四个字节,但也有人看到了八个字节(例如,用于 64 位系统的非常旧的 gfortran 版本)。
如果您不想处理这些复杂问题,只需使用流访问即可。在 Fortran 端,使用
打开文件
OPEN(unit=10,file="foo.dat",form="unformatted",access="stream")
这将为您提供面向流的 I/O 模型,如 C 的二进制流。
否则,您将不得不查看编译器的文档以了解未格式化 I/O 的具体实现方式,并从 R 端处理记录标记。在这里提醒一句:不同的编译器有不同的方法来处理超过 2^31 字节的超长记录,即使它们有四字节的记录标记也是如此。
根据@Stibu 和@IanH 的评论,我试验了 R 代码,发现错误的来源是 R 中对字节大小的不正确处理。明确指定字节大小为 4,即
unformatted <- readBin(to.read,integer(),size="4",n=10000)
让数据完美读入
我有未格式化数据的问题,我不知道在哪里,所以我将 post 我的整个工作流程。
我正在将我自己的代码集成到现有的用 Fortran 语言编写的气候模型中,以从模型输出中生成自定义变量。我已经成功地获得了合理且可读的 formatted 输出(值高达数千),但是当我尝试编写 unformatted 输出时,值我得到的是荒谬的(在 1E10 的规模上)。
任何人都可以看看我的过程并看看我可能哪里出错了吗?
我无法对用于输出数据的整个代码进行功能复制,但相关片段是;
c write customvar to file [UNFORMATTED]
open (unit=10,file="~/output_test_u",form="unformatted")
write (10)customvar
close(10)
c write customvar to file [FORMATTED]
c open (unit=10,file="~/output_test_f")
c write (10,*)customvar
c close(10)
该模型 运行 两次,一次是注释掉了格式化代码,一次是注释掉了未格式化代码,尽管我现在意识到如果我使用的话我可以 运行 它一次不同的单位编号。无论哪种方式,不同的 运行 不应产生不同的值。
生成的文件可在此处获得;
为了解释这些文件,我使用了 R。以下代码是我用来读取每个文件并将它们整形为可比较矩阵的代码。
##Read in FORMATTED data
formatted <- scan(file="output_test_f",what="numeric")
formatted <- (matrix(formatted,ncol=64,byrow=T))
formatted <- apply(formatted,1:2,as.numeric)
##Read in UNFORMATTED data
to.read <- file("output_test_u","rb")
unformatted <- readBin(to.read,integer(),n=10000)
close(to.read)
unformatted <- unformatted[c(-1,-2050)] #to remove padding
unformatted <- matrix(unformatted,ncol=64,byrow=T)
unformatted <- apply(unformatted,1:2,as.numeric)
为了检查两个文件之间数据的一般结构是否相同,我检查了零值和非零值在每个矩阵中的相同位置(每个值代表一个网格方块,零代表有海的地方)使用;
as.logical(unformatted)-as.logical(formatted)
并且返回了一个零数组,表明这只是两者之间不同的值,而不是我塑造它们的方式。
为了了解这些值如何相互关联,我尝试绘制格式化值与未格式化值(注意所有零值都被删除)
如您所见,它们存在某种关系,因此值的 inflation 不是随机的。
我完全不明白为什么未格式化的数据值如此膨胀。我阅读和解释文件的方式有误吗? Fortran 是否有一些潜在的方式来写入改变值的未格式化数据?
Fortran写无格式文件常用的方法是:
- 一个前导记录标记,通常为四个字节,具有后面记录的长度
- 实际数据
- 尾随记录标记,字节数与前导记录标记相同,信息相同(用于退格)
记录标记中通常的字节数是四个字节,但也有人看到了八个字节(例如,用于 64 位系统的非常旧的 gfortran 版本)。
如果您不想处理这些复杂问题,只需使用流访问即可。在 Fortran 端,使用
打开文件 OPEN(unit=10,file="foo.dat",form="unformatted",access="stream")
这将为您提供面向流的 I/O 模型,如 C 的二进制流。
否则,您将不得不查看编译器的文档以了解未格式化 I/O 的具体实现方式,并从 R 端处理记录标记。在这里提醒一句:不同的编译器有不同的方法来处理超过 2^31 字节的超长记录,即使它们有四字节的记录标记也是如此。
根据@Stibu 和@IanH 的评论,我试验了 R 代码,发现错误的来源是 R 中对字节大小的不正确处理。明确指定字节大小为 4,即
unformatted <- readBin(to.read,integer(),size="4",n=10000)
让数据完美读入