You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

FORTRAN输出文件大小优化:差异原因及大数据存储方案咨询

关于Fortran输出文件大小的测试与问题解答

为了在不丢失数据的前提下减小Fortran输出文件的体积,我写了下面这个测试程序来对比不同输出方式的效果:

program test
    character(len=255) format
1   format(9i3)
    c FORMATTED
    open(99,file='form1.txt',form='formatted')
    do i=1,1
        write(99,1) 1, 2, 3, 4, 5, 6, 7, 8, 9
    enddo
    close(99)
    c UNFORMATTED
    open(98,file='form2.txt',form='unformatted')
    do i=1,1
        write(98) 1, 2, 3, 4, 5, 6, 7, 8, 9
    enddo
    close(98)
    c DIRECT ACCESS
    nrec=sizeof(i)*9
    open(97,file='form3.txt',form='unformatted', &
         access='direct',recl=nrec)
    do i=1,1
        write(97,rec=i) 1, 2, 3, 4, 5, 6, 7, 8, 9
    enddo
    close(97)
    call system('ls -lh form?.txt')
end

这个程序生成了三个各包含一条记录的文件,用ls -lh查看的结果如下:

-rw-r--r--. 1 user users 28 May 27 17:10 form1.txt
-rw-r--r--. 1 user users 44 May 27 17:10 form2.txt
-rw-r--r--. 1 user users 36 May 27 17:10 form3.txt

根据Oracle的文档说明:

If FORM='UNFORMATTED', each record is preceded and terminated with an INTEGER*4 count, making each record 8 characters longer than normal. This convention is not shared with other languages, so it is useful only for communicating between FORTRAN programs.

接下来针对两个问题逐一解答:


问题1:为何form1.txt(格式化输出)与form2.txt(无格式输出)的文件大小差值为16字节,而非文档提及的8字节?

首先得明确两个文件的大小计算逻辑:

  • form1.txt(格式化):用format(9i3)输出,每个整数占3个字符(比如" 1"这种带空格的形式),9个整数就是9*3=27字节,再加上换行符占1字节,总大小正好是28字节。你提到把格式改成format(9i4)后文件大小增加9字节,这也完全符合文本格式的特性——每个整数多占1字符,9个就多9字节。
  • form2.txt(默认无格式):根据文档,这种模式下每条记录的首尾各有一个4字节的INTEGER4计数(用来标记记录长度),总共多8字节。而9个INTEGER4类型的整数本身占9*4=36字节,加上首尾的8字节标记,总大小就是36+8=44字节。

文档里说的"比正常多8字节",这里的"正常"指的是不带首尾计数的纯二进制存储(也就是测试里form3.txt的模式),而不是和格式化文本输出对比。你现在拿带标记的无格式文件和文本文件比,差值是44-28=16,这是两种完全不同存储方式的本质差异导致的:一个是把数字转成字符存储(文本),一个是带记录标记的二进制存储,两者的大小差自然不是文档里说的8字节。


问题2:针对包含5列、数百万行、大小超100G的大数据文件,Fortran中减小输出文件大小的最优方法是什么?

针对这种大规模数据,我推荐按优先级选择以下方案:

  • 首选直接访问的无格式文件(Direct Access Unformatted)
    就像测试里的form3.txt,它去掉了默认无格式输出的首尾记录计数,直接存储纯二进制数据,文件体积最小,读写速度也最快。需要注意正确设置recl参数:最好用sizeof()函数计算单条记录的字节数(比如你的5列数据如果都是INTEGER*4,那recl=sizeof(your_var)*5),避免因编译器差异导致的记录长度问题。这种方式唯一的小缺点是跨语言读取稍麻烦,但如果只是Fortran程序之间交互,完全没问题。

  • 配合压缩工具进一步减小体积
    纯二进制文件本身已经很小,但如果还想压缩,可以在写完文件后调用系统工具(比如gzipxz)进行压缩。数值数据的压缩率通常非常高,能把100G的文件压到几十G甚至更小。你可以在Fortran里用call system('xz -z your_file.bin')来自动化这个过程,读取的时候先解压即可。

  • 考虑使用科学数据格式(HDF5/NetCDF)
    如果你的数据需要和其他语言(Python、C++等)交互,或者需要存储元数据(比如列名、单位、采样时间等),HDF5或NetCDF是更好的选择。这些格式原生支持压缩、分块存储,既能减小文件大小,又能提升数据的可维护性和共享性。虽然学习成本比纯二进制稍高,但长期来看很值得。

  • 优化数据类型
    检查你的数据是否真的需要当前的精度:比如如果整数范围在-32768到32767之间,可以用INTEGER2代替INTEGER4,直接把文件大小减半;如果是浮点数,单精度REAL4能满足需求的话,就不要用双精度REAL8。这是最直接的减小体积的方法,前提是数据范围和精度允许。

  • 绝对避免格式化输出
    格式化文本输出不仅文件体积大,读写速度也极慢,对于数百万行的数据,会浪费大量的IO时间和存储空间,完全不适合大规模数据场景。


内容的提问来源于stack exchange,提问作者builder-7000

火山引擎 最新活动