我想在不丢失任何数据的情况下最小化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
这将创建三个文件,每个文件一个记录。该计划的输出是:
-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
如果FORM ='UNFORMATTED',则每个记录都以INTEGER * 4计数开头并终止,使每个记录比正常情况长8个字符。此约定不与其他语言共享,因此仅对FORTRAN程序之间的通信有用。
我的问题是:
form1.txt
和form2.txt
之间存在16个字节(不是前面引用中提到的8个字节)的差异?请注意,file1.txt
的大小取决于格式(例如,如果我将行format(9i3)
更改为format(9i4)
,file1.txt
的文件大小会增加9个字节。)我的主要问题是:
我的一个类似问题是:Best way to write a large array to file in fortran? Text vs Other
答案 0 :(得分:3)
虽然没有直接解决您的问题,但我想指出,如果您使用二进制数据,文件大小有一个下限。即使最密集的存储表示没有任何校验和或关于例如的元信息。如果使用记录长度,则必须存储sizeof(数据类型)* num_entries字节。
您可以使用像blosc这样的快速压缩算法,甚至能够胜过C& RAM-to-RAM memcpy()
。效率和性能显然在很大程度上取决于数据的分布,但在实际应用中可以达到几十GB /秒。
100GB可能需要很多数据才能适应您机器的RAM。可以手动对文件进行分块,也可以使用HDF5之类的库。 HDF5为基本任意数量的高性能数据提供压缩分块存储。但是,即使存在HDF5 Fortran API,也可以合并大型库。
答案 1 :(得分:3)
基本上你的格式9i3
意味着每个数字在文件中只占用3个字节。这是27个字节再加上一个用于回车的28个字节。
但是你只能以这种格式存储最多999的数字,即使这样,超过99的数字也会混合在一起。
Direct Access存储整数的二进制表示,因此每个数字为32位或4个字节。这总共是36个字节。这超过了你的格式化版本的28,但它可以适用于所有整数,最高可达2,147,483,647,最低可达-2,147,483,648,但仍然是相同的大小。 (如果您希望格式化版本具有相同的灵活性,则需要格式9I11
,总共100个字节。)
未格式化的版本有点中间,它仍然存储一些元数据,这就是它比直接访问更大的原因,但是像直接访问一样,你可以在占用相同数量的同时存储所有整数太空了。
关于你的第二个问题,你应该使用什么取决于很多事情。正如您所注意到的,如果您的整数始终在0到99之间,那么它们的字符串表示形式小于它们的二进制表示形式。但是一旦你需要4位数(包括符号),二进制表示就会变小。我还应该指出,如果你的数字很小,你也可以将它们声明为8位或16位整数,这意味着它们只分别占用一个或两个字节。
二进制表示也更快,因为数字不需要在二进制和字符串之间转换。
但是对于您正在谈论的大小,调查其他文件格式可能很有价值,例如NetCDF有一些压缩数据的方法。