回 帖 发 新 帖 刷新版面

主题:一个有关输出的小问题

数据为单列:
   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个回复)

沙发

你的代码问题很多。

问题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]

板凳

我尝试用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 楼

不是很明白你的意思。

先跟踪第一个文件的第一行,也就是 1,得到结果 5 0 14
然后在跟踪第一个文件的第二行,也就是 13,得到结果,比如是 7 0 12
然后再跟踪第三行,也就是 15 对吗?

跟踪第二行 13 的时候,也是判断第2个文件,第3个文件的第二行吗?

4 楼

我中文不好,说得不是很清楚,抱歉!

我的想法是:

假设共有二十个文件。在第一个文件中含有

   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 楼

比较的时候,是以整个文件来比较,不是以特定的某行(比如第二行只能和下一个文件的第二行)。

也就是说,读指定的一个文件,选取其中的一个数据(比如数字1),view其他的文件看里面是否包含选到的数。如果有,就计数,如果没有,就output先前的记录,同时对于没有的项目记录一个0,计数器清零并重新开始计数。

希望得到的结果是

比如

result_1.dat  (1是选取的数字)

里面的结果是:
2
0
17

再比如

result_13.dat (13是选取的数字)

里面的结果是:
2
0
17


6 楼

明白了。但是貌似这个没有直接的办法,可能比较麻烦。

还要确定两个问题:

1.你的数据都是整数吗?如果有小数点,可能不好判断是不是想等
2.你的数据量大不大?如果大量的数据,需要一边读,一边判断。如果数据量小,可以考虑全部读入内存判断,速度会快一些。

7 楼

我刚刚做了一个统计。就是调用下面这个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 楼

如果不能够同时进行,至少希望能够每次运行时就单独一个选择的数字进行比较。比如第一个文件中的数字1,下次运行时再更换源程序里的选择数字(比如13)。

9 楼

那就放入内存里,不需要频繁的读取文件,方便一些。

代码我没有经过测试,因为我也没有那么多符合你要求的文件。

只是提供给你一个思路。也许你直接用可能会有 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 楼

我的编译器比较老版本,所以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

我来回复

您尚未登录,请登录后再回复。点此登录或注册