将文本文件转化为二进制文件,然后再转出来
小弟最近在做一个文本文件转化为二进制文件的问题,希望可以将文件的大小实现压缩,然后需要的时候再转为文本文件读取,现在这个文件是这样的,就是前面的19行均为长度不一得字符串,后面是几行小数,具体小数的行数就是第19行字符串中的整数,如此循环,我编了一个程序,编译没什么问题,但是一运行就卡着半天不动了,不知道问题出在哪了,我的思路是想先把前面19行循环读取,然后再把第19行的字符串转化为整数,然后循环读取小数,但是这样的话出现很多空格,文件反而更大了,希望各位大佬能不吝赐教。program jack01implicit none
character(len = 66) buffer
integer :: num = 0
real(kind = 4) :: a, b
integer :: status = 0
integer countera,counterb
integer, parameter :: lines = 19
integer :: r = 1
logical alive
inquire(file = 'new.txt',exist = alive)
if(alive)then
!打开输入输出文件
open(unit = 12, file = 'new.txt')
open(unit = 13, file = 't.bin', access = 'direct', form = 'unformatted', recl = 20 )
do while(.true.)
!转存前面19行的内容
docountera = 1, lines, 1
read(14, fmt = "(A66)",iostat = status) buffer
if(status /= 0) exit
write(15, rec = r) buffer
r = r + 1
end do
countera = 1
!转存实数部分的内容
docounterb = 1, num, 1
read(14, *, iostat = status) a, b
if(status /= 0) exit
write(15, rec = r) a, b
r = r + 1
end do
counterb = 1
end do
else
write(*,*)'new.txt',"does not exist"
end if
!关闭输入输出文件
close(12)
close(13)
stop
end 为啥不能先把所有的txt文件打包成单个zip、gz格式的压缩文件,然后按照规则抽取需要的txt文件呢? 本帖最后由 楚香饭 于 2017-10-30 12:53 编辑
你这种问题不太容易用二进制存储,因为每个 block 的文本头部都不一样长。
后面用二进制读取的时候,不知道读多少文本头部。
如果你非要转二进制,看下面代码的修改
program jack01
implicit none
character(len = 66) buffer
integer :: num = 0
real(kind = 4) :: a, b
integer :: status = 0
integer i
integer, parameter :: lines = 18 !//文本只算18行
logical alive
inquire(file = 'new.txt',exist = alive)
if(.not.alive) then
write(*,*) "new.txt does not exist"
stop
end if
!打开输入输出文件
open(unit = 14, file = 'new.txt')
open(unit = 15, file = 't.bin', access = 'stream')!//stream是一个很霸道的二进制读写方式
CY: Do!//命名循环
!转存前面19行的内容
doi = 1, lines
read(14, fmt = "(A66)",iostat = status) buffer
if(status /= 0) exit CY
write(15) trim(buffer) !//trim一下以便减小尺寸
end do
read(14,*,iostat=status) num !//获得行数
if(status /= 0) exit CY
!转存实数部分的内容
doi = 1, num
read(14, *, iostat = status) a, b
if(status /= 0) exit CY
write(15) a, b
end do
End Do CY
close(12)
close(13)
end program jack01
pasuka 发表于 2017-10-30 12:34
为啥不能先把所有的txt文件打包成单个zip、gz格式的压缩文件,然后按照规则抽取需要的txt文件呢? ...
导师要求的,要我那这个先练习练习,然而一直报错:-L 肖邦的SK 发表于 2017-10-30 14:31
导师要求的,要我那这个先练习练习,然而一直报错
gzip就是一种无损压缩的二进制存储格式
https://en.wikipedia.org/wiki/Gzip
https://en.wikipedia.org/wiki/DEFLATE
若是配合Python,处理起来很方便
https://docs.python.org/3/library/gzip.html#module-gzip
楚香饭 发表于 2017-10-30 12:46
你这种问题不太容易用二进制存储,因为每个 block 的文本头部都不一样长。
后面用二进制读取的时候,不知道 ...
万分感谢,是可以转出来了。不过就是转换回去的时候如果用流文件的处理是要读取指定字节数的,但是这边的头文件区域的字节数都是不固定的,所以之前我在一开始转的时候想把他弄成一条条的记录去做,然后转成文本文件的时候直接一条条的读,但是好像这样的话弄出来的二进制文件反而更大了。 pasuka 发表于 2017-10-30 14:37
gzip就是一种无损压缩的二进制存储格式
https://en.wikipedia.org/wiki/Gzip
https://en.wikipedia.org/wi ...
谢谢帮助,这个很有用。我会继续学习的,因为现在是刚学习Fortran阶段,所以老师也是希望我通过这个练习熟悉熟悉Fortran语言,可能后续的课题也会使用。 本帖最后由 楚香饭 于 2017-10-31 08:42 编辑
可以把文本的大小也写在二进制文件里。
以下代码在windows上运行。如果要在其他操作系统上运行,建议修改 crlf 的定义。
program jack02
implicit none
integer :: status , n , i
Real :: a , b
character(len=1) , allocatable :: text(:)
open(unit = 15, file = 't.bin', access = 'stream')!//stream是一个很霸道的二进制读写方式
open(unit = 14, file = 'newback.txt')
Do
Read(15,iostat=status) n !//得到文本大小
if(status/= 0) exit
if(n==0) exit
Allocate(text(n))
Read(15) text
Write(14,'(a,\)') text
Deallocate(text)
Read(15,iostat=status) n !//得到二进制大小
if(status/= 0) exit
write(14,*) n
Do i = 1 , n
Read(15) a , b
Write(14,*) a , b
End Do
End Do
End Program jack02
program jack01
implicit none
character(len = 66) buffer
integer :: num = 0
real(kind = 4) :: a, b
integer :: status = 0
integer i , locBegin , locEnd
integer, parameter :: lines = 18 !//文本只算18行
character(len=*) , parameter :: crlf = char(z'd') // char(z'a')!//换行符,不同操作系统不一样
logical alive
inquire(file = 'new.txt',exist = alive)
if(.not.alive) then
write(*,*) "new.txt does not exist"
stop
end if
!打开输入输出文件
open(unit = 14, file = 'new.txt')
open(unit = 15, file = 't.bin', access = 'stream')!//stream是一个很霸道的二进制读写方式
CY: Do!//命名循环
!转存前面18行的内容
write(15) 0 !//先输出一个0,表示大小
Inquire( 15 , pos = locBegin ) !//查询块开始位置
doi = 1, lines
read(14, fmt = "(A66)",iostat = status) buffer
if(status /= 0) exit CY
write(15) trim(buffer) , crlf !//trim一下以便减小尺寸,每行输出换行符
end do
Inquire( 15 , pos = locEnd ) !//查询块结束位置
write(15,pos=locBegin-4) locEnd-locBegin !//在开始前4个字节写入大小
read(14,*,iostat=status) num !//获得行数
if(status /= 0) exit CY
write(15,pos=locEnd) num !//回到块结束,写入实数部分的大小
!转存实数部分的内容
doi = 1, num
read(14, *, iostat = status) a, b
if(status /= 0) exit CY
write(15) a, b
end do
End Do CY
close(12)
close(13)
end program jack01
楚香饭 发表于 2017-10-31 08:36
可以把文本的大小也写在二进制文件里。
以下代码在windows上运行。如果要在其他操作系统上运行,建议修改...
谢谢您,我拜读了一下您的代码,并且也跑了一下,成功了,但是任然有一些地方不是很明白 character(len = *) , parameter :: crlf = char(z'd') // char(z'a')!//换行符,不同操作系统不一样,这个是指从一个换行符到另外一个换行符的长度吗,但是这个换行符我在书上和网上一直没找到,还有就是 Write(14,'(a,\)') text里面的'(a,\)'我也不是很清楚,查了一些资料但是始终还是没太明白:-L 换行符的问题,可以百度搜索“crlf”
(a,\) 意思是,输出一个字符(a),并且不换行(\)。
页:
[1]
2