主题:一个有关输出的小问题
NMRD
[专家分:40] 发布于 2012-01-16 19:06:00
数据为单列:
1
1
1
13
13
13
15
15
15
17
17
17
23
23
23
25
25
25
...
我只需要读一下数,现在每一个都重复了三次,所以想重新输出成三列,然后只读第一列, 也就是
1
13
15
17
23
25
...
这样。
我写的源程序是:
program main
character(160) :: filename,tmp
integer m,n
integer i,line,a
filename='A_1_'
print*, 'Please enter the number of files:'
read*,n
do m=1,n
write(tmp,*)m
open(10,status='old', file=trim(filename)//trim(adjustl(tmp))
1//'.dat')
line=1000
do i = 1,line
read(10,111,iostat=ios) a
if (ios /=0) then
exit
endif
open(11,status='unknown',file=trim('B_1_')//trim(adjustl(tmp))
1//'.dat')
write(11,112) a
enddo
enddo
111 format (3I4)
112 format (I4,2x,2x)
close(10)
close(11)
end
这里的file=trim(filename)//trim(adjustl(tmp)),是说我有许多这一类数据,希望进行批处理。不知道format哪里不对,现在的问题是输出和原数据一样,也是单列然后每个重复三次。请问如何解决?
另外想问一下,输出的时候,能否在同一个文件输出很多列? 比如每个文件二十列(读二十个原文件,然后将结果输出到同一个dat文件里,像下面的举例那样)。这样读起来会更方便。请问这个想法是否可行,以及最多可以有多少列在同一个文件中?
eg:
1 1 ...
13 12 ...
15 13 ...
17 15 ...
23 16 ...
25 19 ...
... ... ...
回复列表 (共24个回复)
沙发
臭石头雪球 [专家分:23030] 发布于 2012-01-17 08:38:00
你的代码问题很多。
问题1,
Do
Open
End Do
Close
这样的结构是不合理的,因为会重复 Open,应该把 Open 和 Colose 都放在 Do 外面,或者都放在里面。
问题2,
file=trim(filename)//trim(adjustl(tmp))
如果你怀疑这个结果有问题,可以紧跟一句
write(*,*) trim(file)
这样看file是否合理。
或者用 Debug 模式下断点跟踪。
问题3,
如果你只是要把 20 个文件的列合并到一起,那很简单。根本不需要这样循环。
[quote]
[font=宋体][color=#FF0000]Integer [/color][color=#000000]a[/color][color=#000080]([/color][color=#800080]20[/color][color=#000080])
[/color][color=#FF0000]Open[/color][color=#000080]( [/color][color=#800080]101 [/color][color=#000080], [/color][color=#FF0000]file [/color][color=#000080]= [/color][color=#000000]第[/color][color=#800080]1[/color][color=#000000]个文件 [/color][color=#000080])
[/color][color=#FF0000]Open[/color][color=#000080]( [/color][color=#800080]102 [/color][color=#000080], [/color][color=#FF0000]file [/color][color=#000080]= [/color][color=#000000]第[/color][color=#800080]2[/color][color=#000000]个文件 [/color][color=#000080])
...
[/color][color=#FF0000]Open[/color][color=#000080]( [/color][color=#800080]120 [/color][color=#000080], [/color][color=#FF0000]file [/color][color=#000080]= [/color][color=#000000]第[/color][color=#800080]20[/color][color=#000000]个文件 [/color][color=#000080])
[/color][color=#FF0000]Open[/color][color=#000080]( [/color][color=#800080]11 [/color][color=#000080], [/color][color=#FF0000]file [/color][color=#000080]= [/color][color=#000000]输出结果 [/color][color=#000080])
[/color][color=#FF0000]Do [/color][color=#000000]h [/color][color=#000080]= [/color][color=#800080]1 [/color][color=#000080], [/color][color=#800080]1000 [/color][color=#008000]!//一千行
[/color][color=#FF0000]Do [/color][color=#000000]i [/color][color=#000080]= [/color][color=#800080]1 [/color][color=#000080], [/color][color=#800080]20 [/color][color=#008000]!// 20个文件
[/color][color=#FF0000]Read[/color][color=#000080]( [/color][color=#800080]100[/color][color=#000080]+[/color][color=#000000]i [/color][color=#000080], * ) [/color][color=#000000]a[/color][color=#000080]([/color][color=#000000]i[/color][color=#000080])
[/color][color=#FF0000]End Do
write[/color][color=#000080]( [/color][color=#800080]11 [/color][color=#000080], * ) [/color][color=#000000]a
[/color][color=#FF0000]End Do
Close[/color][color=#000080]() [/color][color=#008000]!//各种关闭[/color][/font][/quote]
板凳
NMRD [专家分:40] 发布于 2012-01-17 17:21:00
我尝试用dimension的方法写了一下,是这样的:
program main
character(160) :: filename,tmp
integer m1,n1
integer i,j,line,n,m
integer, dimension(75,3)::indata(75,3)
filename='A_1_'
print*, 'Please enter the number of files:'
read*,n1
do m1=1,n1
write(tmp,*)m1
open(10,status='old', file=trim(filename)//trim(adjustl(tmp))
1//'.dat')
n=75
do i = 1,n
m=3
read(10,*,iostat=ios) (indata(i,j), j=1,m)
if (ios /=0) then
exit
endif
open(11,status='unknown',file=trim('B_1_')//trim(adjustl(tmp))
1//'.dat')
write(11,111)(indata(i,j),j=1,1)
end do
close(10)
close(11)
enddo
111 format (I4,2X,I4,2X,I4)
end
在这里只输出第一列write(11,111)(indata(i,j),j=1,1)。发现这样也可以解决第一个问题。
最后一个问题,实际上我的想法是能够就数据进行比较。
比方说:
第一个文件里有数据
1
13
15
17
23
25
...(长度为不确定数)
这样。然后跟踪其中的一个,比方说数字1,比较第二个文件,比较第三个文件...一直到第二十个(假设总数是20)文件。如果它在前五个文件都有出现,就记录5,如果第六个文件中不含有数字1,就记录0然后重新开始计数。输出结果是
5
0
14 (假设剩余文件都包含数字1)
实际上,我希望能跟踪第一个文件里的全部数据,并像上面那样列印结果。我原本的打算是列成每个20列的DAT文件然后用Origin来做,但是实际做起来发现是很麻烦的操作。所以还是希望编程来解决。
你的解释每次都很详细和富有条理的,非常感谢! 并希望能得到继续的帮助!
3 楼
臭石头雪球 [专家分:23030] 发布于 2012-01-17 17:38:00
不是很明白你的意思。
先跟踪第一个文件的第一行,也就是 1,得到结果 5 0 14
然后在跟踪第一个文件的第二行,也就是 13,得到结果,比如是 7 0 12
然后再跟踪第三行,也就是 15 对吗?
跟踪第二行 13 的时候,也是判断第2个文件,第3个文件的第二行吗?
4 楼
NMRD [专家分:40] 发布于 2012-01-17 18:22:00
我中文不好,说得不是很清楚,抱歉!
我的想法是:
假设共有二十个文件。在第一个文件中含有
1
13
15
17
23
25
(每个文件的数据总数并不确定)
第二个文件可能是
1
12
13
第三个文件可能是
5
19
23
123
...
以此类推,20个文件包含的数字总数并不一样,其内容也不一定相同(不确定)。
然后以第一个文件为基础进行数据间的比较。以第一个文件中的第一个数据,数字1为例,它在第二个文件中含有,第三个文件中没有,所以希望另外打开一个文件(result.dat)来记录这件事。
因为出现两次,所以记录2, 在第三个文件中不存在,就记录0,同时‘计数器’重新开始计数。假设剩下的17个文件都包含1, 希望在result.dat中看到
2
0
17
这样的结果。
然后接下来,以上面的方式去比较第一个文件中的第二个数据(数字13),第三个数据(15)...
(对数字13)希望结果为
2
0
17 (假设余下的17个文件都包含数字13)
和 (对数字15)
1
0
0
17 (假设余下的17个文件都包含数字15)
问题就是这样的。
5 楼
NMRD [专家分:40] 发布于 2012-01-17 18:27:00
比较的时候,是以整个文件来比较,不是以特定的某行(比如第二行只能和下一个文件的第二行)。
也就是说,读指定的一个文件,选取其中的一个数据(比如数字1),view其他的文件看里面是否包含选到的数。如果有,就计数,如果没有,就output先前的记录,同时对于没有的项目记录一个0,计数器清零并重新开始计数。
希望得到的结果是
比如
result_1.dat (1是选取的数字)
里面的结果是:
2
0
17
再比如
result_13.dat (13是选取的数字)
里面的结果是:
2
0
17
6 楼
臭石头雪球 [专家分:23030] 发布于 2012-01-17 20:12:00
明白了。但是貌似这个没有直接的办法,可能比较麻烦。
还要确定两个问题:
1.你的数据都是整数吗?如果有小数点,可能不好判断是不是想等
2.你的数据量大不大?如果大量的数据,需要一边读,一边判断。如果数据量小,可以考虑全部读入内存判断,速度会快一些。
7 楼
NMRD [专家分:40] 发布于 2012-01-17 20:35:00
我刚刚做了一个统计。就是调用下面这个function
integer function GetFileN(iFileUnit)
implicit none
logical , parameter :: b = .True.
integer , intent( IN ) :: iFileUnit
character*(1) :: c
GetFileN = 0
rewind( iFileUnit )
do while (b)
read( iFileUnit , * ,end =999 ,Err = 999 )c
GetFileN = GetFileN + 1
end Do
999 rewind( iFileUnit )
return
end function GetFileN
每个文件最多包含四百个数据左右,最少的包含三十几个,其他的在这个范围之内。
数据全部为整数。最大的是四位数。
我希望每次能以一百个文件为单位进行比较。
8 楼
NMRD [专家分:40] 发布于 2012-01-17 20:38:00
如果不能够同时进行,至少希望能够每次运行时就单独一个选择的数字进行比较。比如第一个文件中的数字1,下次运行时再更换源程序里的选择数字(比如13)。
9 楼
臭石头雪球 [专家分:23030] 发布于 2012-01-18 08:18:00
那就放入内存里,不需要频繁的读取文件,方便一些。
代码我没有经过测试,因为我也没有那么多符合你要求的文件。
只是提供给你一个思路。也许你直接用可能会有 BUG,具体逻辑我没有分析是不是合理。
[quote]
Program Main
Implicit None
Type :: ST_OneFileData
Integer , allocatable :: rData(:)
End Type
Type ( ST_OneFileData ) , allocatable :: stAllData(:)
Integer iNumOfFile , i , iNumOfLine , j , iCount , iCompare , GetFileN
!// 输入文件数目
write( * , * ) '一共多少文件?'
read ( * , * ) iNumOfFile
Allocate( stAllData( iNumOfFile ) )
!// 读取全部数据
Do i = 1 , iNumOfFile
Open( 12 , File = 'File' ) !//此处按照你的文件方式修改
iNumOfLine = GetFileN( 12 )
Allocate( stAllData(i)%rData( iNumOfLine ) )
Do j = 1 , iNumOfLine
Read( 12 , * ) stAllData(i)%rData( j )
End Do
Close( 12 )
End Do
!// 逐个比较
Open( 12 , File = '原始文件' ) !//此处按照你的文件方式修改
Open( 13 , File = '结果文件' )
iNumOfLine = GetFileN( 12 )
Do i = 1 , iNumOfLine
iCount = 0
Read( 12 , * ) iCompare
write( 13 , * ) '现在查找第',i,'个数据:',iCompare
Do j = 1 , iNumOfFile
If ( any( stAllData(j)%rData(:) == iCompare ) ) then
iCount = iCount + 1
Else
write( 13 , * ) iCount
iCount = 0
End If
End Do
If ( iCount /= 0 ) write( 13 , * ) iCount
End Do
Close(13)
Close(12)
!// 结束
Deallocate( stAllData )
End Program[/quote]
10 楼
NMRD [专家分:40] 发布于 2012-01-18 18:44:00
我的编译器比较老版本,所以Integer , pointer:: rData(:)这里改成pointer。用allocatable就会提示Error: This attribute specification is not valid for a component definition statement. [ALLOCATABLE]。(实际上我不晓得这个原理,是在网上找来类似问题参考而改写的)
然后提示出现test2.obj : error LNK2001: unresolved external symbol _GETFILEN@4,就胡乱加了integer function GetFileN(iFileUnit)的部分,然后问题消失。
最后改成这样:
Program Main
Implicit None
Type :: ST_OneFileData
Integer , pointer:: rData(:)
End Type
Type ( ST_OneFileData ) , allocatable :: stAllData(:)
Integer iNumOfFile ,i ,iNumOfLine ,j ,iCount ,iCompare ,GetFileN
character(160) :: tmp
write( * , * ) 'How many files you want to run?' (我的电脑没有中文字体,所以此类部分全部用英文替换)
read ( * , * ) iNumOfFile
Allocate( stAllData( iNumOfFile ) )
Do i = 1 , iNumOfFile
write(tmp,*)i
open(1,file=trim('A_1_')//trim(adjustl(tmp))
1//'.dat',status='old' )
(这里师兄给的原程序不是很明白,为什么和后面一起open (12,...), 我想了一下,认为是在这里打开需要比较的全部文件。测试时用了10个。1// 前的1是换行用,有的编译器可能是用&符号替代。)
iNumOfLine = GetFileN( 1 )
Allocate( stAllData(i)%rData( iNumOfLine ) )
Do j = 1 , iNumOfLine
Read( 1 , * ) stAllData(i)%rData( j )
End Do
Close( 1 )
End Do
Open( 12 , File = 'Sample.dat' )
(就是这个地方。我决定在这里打开用来做‘模板’的那个文件。就是说,其他文件和这里的数据进行比较。)
Open( 13 , File = 'Result.dat' )
(然后这个是结果。)
iNumOfLine = GetFileN( 12 )
Do i = 1 , iNumOfLine
iCount = 0
Read( 12 , * ) iCompare
write( 13 , 111 ) 'No:',i,'Read:',iCompare
Do j = 1 , iNumOfFile
If ( any( stAllData(j)%rData(:) == iCompare ) ) then
iCount = iCount + 1
Else
write( 13 , * ) iCount
iCount = 0
End If
End Do
If ( iCount /= 0 ) write( 13 , * ) iCount
111 format (a4,i5,a8,i4)
(输出的时候format了一下,发现结果好看一点。)
End Do
Close(13)
Close(12)
Deallocate( stAllData )
End Program
integer function GetFileN(iFileUnit)
implicit none
logical , parameter :: b = .True.
integer , intent( IN ) :: iFileUnit
character*(1) :: c
GetFileN = 0
rewind( iFileUnit )
do while (b)
read( iFileUnit , * ,end =999 ,Err = 999 )c
GetFileN = GetFileN + 1
end Do
999 rewind( iFileUnit )
return
end function GetFileN
我来回复