我已經在這個網站上閱讀了類似的已解決問題,但它們確實對我有幫助!所以,我很抱歉提出類似的問題。
我有以下名為“Asteroids_Numbered.txt”的 .txt 檔案(該檔案有很多行,即 607013,但為簡單起見,我放的少了很多):
Num Name Epoch a e i w Node M H G Ref
------ ----------------- ----- ---------- ---------- --------- --------- --------- ----------- ----- ----- ----------
1 Ceres 59600 2.7660431 0.07850100 10.58769 73.63704 80.26860 291.3755993 3.54 0.12 JPL 48
2 Pallas 59600 2.7711069 0.22999297 34.92530 310.69725 172.91657 272.4799259 4.22 0.11 JPL 49
3 Juno 59600 2.6687911 0.25688702 12.99186 247.94173 169.84780 261.2986327 5.28 0.32 JPL 123
4 Vesta 59600 2.3612665 0.08823418 7.14172 151.09094 103.80392 7.0315225 3.40 0.32 JPL 36
5 Astraea 59600 2.5751766 0.19009936 5.36762 358.74039 141.57036 160.9820880 6.99 0.15 JPL 125
6 Hebe 59600 2.4256657 0.20306151 14.73873 239.50547 138.64097 347.4991368 5.65 0.24 JPL 100
7 Iris 59600 2.3866161 0.22949924 5.51768 145.34355 259.52553 47.6423152 5.61 0.15 JPL 119
8 Flora 59600 2.2017319 0.15606719 5.88872 285.55022 110.87251 136.2585358 6.54 0.28 JPL 127
9 Metis 59600 2.3852921 0.12356142 5.57695 6.16423 68.89958 184.5626181 6.37 0.17 JPL 128
10 Hygiea 59600 3.1418676 0.11162598 3.83093 312.49331 283.18419 328.8968591 5.55 0.15 JPL 105
11 Parthenope 59600 2.4532814 0.09954681 4.63165 195.59824 125.52829 175.4211548 6.60 0.15 JPL 118
12 Victoria 59600 2.3337809 0.22074254 8.37333 69.66955 235.36878 49.7506630 7.31 0.22 JPL 131
13 Egeria 59600 2.5765835 0.08544364 16.53450 80.14708 43.20673 66.2442983 6.84 0.15 JPL 103
14 Irene 59600 2.5859176 0.16587880 9.12082 97.71349 86.11601 42.0351479 6.53 0.15 JPL 96
15 Eunomia 59600 2.6440754 0.18662534 11.75200 98.63169 292.92610 152.5002319 5.41 0.23 JPL 85
16 Psyche 59600 2.9244847 0.13392662 3.09684 229.21980 150.03218 125.1275316 6.06 0.20 JPL 90
17 Thetis 59600 2.4706187 0.13286003 5.59276 135.80674 125.54282 197.5734224 7.76 0.15 JPL 125
18 Melpomene 59600 2.2957889 0.21790920 10.13249 228.11923 150.36173 190.3739342 6.53 0.25 JPL 116
19 Fortuna 59600 2.4429040 0.15701789 1.57276 182.47214 211.04422 95.0887535 7.38 0.10 JPL 142
20 Massalia 59600 2.4088126 0.14306413 0.70880 257.55922 205.97388 20.5136762 6.56 0.25 JPL 118
21 Lutetia 59600 2.4351916 0.16354177 3.06364 250.15544 80.85386 243.3813245 7.52 0.11 JPL 118
22 Kalliope 59600 2.9102024 0.09838131 13.70049 357.60063 65.99349 33.4836574 6.51 0.21 JPL 111
如何創建一個讀取此檔案的程式,將資料存盤在一維陣列中(每種型別的資料一個,所以我想獲得 12 個陣列),然后根據一些標準過濾它們,例如傾斜值( i) 小于 2 度?最后,如何將過濾后的資料存盤在與原始檔案格式相同的新檔案中?
這是我的代碼(它只包含閱讀部分):
program Read_write_ephemerides_Main
implicit none
!Declarations
character*100 :: input_path,input_filename, output_path, output_filename
double precision, dimension(:,:), allocatable :: Epoch_TDB, a_AU, e, i_deg, w_deg, Node_deg, M_deg, H_mag, G
character*30, dimension(4) :: str_output
character, dimension (:,:), allocatable :: Name, Ref
integer :: i,iu, i_counter
integer, dimension (:,:), allocatable :: Number
logical :: bContinue
! Definition of constants, paths names and file names
iu = 10
input_path = 'D:\MSc_Aerospace_Eng\Thesis\Fortran_projects\Read_write_ephemerides\InputFiles\'
input_filename = 'Asteroids_Numbered.txt'
!output_path = 'D:\MSc_Aerospace_Eng\Thesis\Fortran_projects\Read_write_ephemerides\OutputFiles\'
!output_filename = 'prova_ast_num.txt'
! Reading of Asteroids_numbered file
open(unit = iu, file = trim(input_path) // trim(input_filename), status='old', &
access = 'sequential',form = 'formatted', action='read')
read(iu,'(//)') ! skip first 2 lines
read(iu,'(i10,a25,f10.0,6(f12.8),2(f5.4),f5.4)') Number, Name, Epoch_TDB, a_AU, e, i_deg, w_deg, Node_deg, M_deg, H_mag, G, Ref
close(unit = iu,status='keep')
! Creation of output file
!open(unit = iu, file = trim(output_path) // trim(output_filename1), status = 'unknown', action = 'write')
!write(iu,'(i10,a25,f10.0,6(f12.8),2(f5.4),f5.4)') Number, Name, Epoch_TDB, a_AU, e, i_deg, w_deg, Node_deg, M_deg, H_mag, G, Ref
!close(unit = iu,status='keep')
!
stop
end program Read_write_ephemerides_Main
EDIT: Code updated USEFUL NOTE: I use Intel Fortran compiler within Microsoft Visual Studio 2022
uj5u.com熱心網友回復:
在繼續下一部分之前,讓我們先解決一件事:如果這只是一個“過濾”任務,請將其視為過濾任務。
在 Fortran 2018 中,這可能很簡單
implicit none
character(1234) line
integer iostat, nchars
do
read (*,'(A)',iostat=iostat,size=nchars) line
if (iostat.lt.0) exit
if (KEEP_LINE) print *, line(:nchars) ! Implement conditional
end do
end program
(如果您的編譯器不是 Fortran 2018 編譯器,則需要將其復雜化。)該程式充當 Unix 意義上的過濾器:
./program < input_file > output_file
對于這個問題,過濾器類似于“通過前兩行;通過后面的行,其中第六列作為數字小于 2”。我將把確切的規范留作練習,注意我們可以用
awk 'NR<3||$6<2' < input_file > output_file
請注意,您可以簡單地提取第六列而不為每列創建變數 - 或者您可以注意到它是line(52:).
這就是過濾掉的方式。讓我們看看如何在 Fortran 程式中創建資料結構并對其進行處理。
正如高性能標記所評論的那樣,我們可以為這個“資料表”創建一個派生型別(如果所有列都是相同的資料型別,我們可能只使用 2 級內在型別,盡管即使在這種情況下)派生型別有幫助):
type asteroids_t
integer :: num
character(18) :: name
integer :: epoch
real :: a, e, i, w, node, m, h, g
character(10) :: ref
end type asteroids_t
(根據需要設定每個組件的種類引數,但可能是實數的雙精度)
我們有輸入和輸出的格式:
character(*), parameter :: FMT='(i6,a,i7,f10.7,f11.8,3f10.5,f12.7,2f6.2,a)'
(請注意,我們不能對輸入使用串列導向的格式,因為最后一列的字符中有一個空格。同樣,解決這個問題是一個練習。)
假設我們有一個大小合適的陣列(請參閱有關讀取行數未知的檔案的一般問題,或 hereveryreverie 的答案以了解詳細資訊),我們就可以開始了。為了清楚起見,我將使用明確的大小。
type(asteroids_t) asteroids(NUMBER_OF_ASTEROIDS)
integer, allocatable :: pass(:)
read FMT, asteroids
... ! Work, including setting pass for filter
print FMT, asteroids(pass)
將所有這些放在一起形成一個快速而骯臟的程式:
implicit none
type asteroids_t
integer :: num
character(18) :: name
integer :: epoch
real(KIND(0d0)) :: a, e, i, w, node, m, h, g
character(10) :: ref
end type asteroids_t
type(asteroids_t) :: asteroids(22)
character(118) :: header(2)
character(*), parameter :: FMT='(i6,a,i7,f10.7,f11.8,3f10.5,f12.7,2f6.2,a)'
integer :: i
read '(A)', header
print '(A)', header
read FMT, asteroids
print FMT, asteroids(PACK([(i,i=1,SIZE(asteroids))], asteroids%i<2))
end program
需要注意的關鍵點是,我們可以使用“普通”輸入/輸出來處理派生型別:專案asteroids被擴展為陣列元素,然后每個陣列元素都被擴展為組件。因為我們的派生型別沒有私有、指標或可分配的組件,我們可以使用這種簡單的處理形式。
作為更高級的材料,請注意此處示例中的“幻數”。我們已經知道如何洗掉魔法小行星計數(22)以及標題行的魔法數字和長度(2 和 118)。但也許我們擔心這些字符組件(18 和 10)的長度。
我們的資料結構與輸入資料檔案的形式緊密耦合,但是如果我們有兩個名稱長度不同的資料集怎么辦?重寫或復制我們的派生型別來處理這個問題確實很痛苦。讓我們解決這個問題:
type asteroids_t(len_name, len_ref)
integer, len :: len_name=18, len_ref=10
integer :: num
character(len_name) :: name
integer :: epoch
real(KIND(0d0)) :: a, e, i, w, node, m, h, g
character(len_ref) :: ref
end type asteroids_t
type(asteroids_t) asteroids_set_1(22)
type(asteroids(25,8)) asteroids_set_2(22)
! There's no magic character length in FMT
read FMT, asteroids_set_1
read FMT, asteroids_set_2
列寬甚至可以延遲到運行時決議(未顯示)。您可以在別處更詳細地了解這些引數化派生型別。
uj5u.com熱心網友回復:
要擴展@HighPerformanceMark 的評論,最好的辦法是定義一個Asteroid包含有關小行星的所有資訊的型別,然后創建一個Asteroids 陣列。
Asteroid型別_
該Asteroid型別最初應該只包含有關小行星的資料,
type :: Asteroid
integer :: num
character(:), allocatable :: name
integer :: epoch
real(dp) :: a
real(dp) :: e
real(dp) :: i
real(dp) :: w
real(dp) :: node
real(dp) :: m
real(dp) :: h
real(dp) :: g
character(:), allocatable :: ref_name
integer :: ref_number
end type
其中dp 定義了雙精度。
這允許您擁有一個 s 陣列Asteroid,例如
type(Asteroid) :: asteroids(22)
asteroids(1) = Asteroid(1, "Ceres", ..., "JPL", 48)
...
asteroids(22) = Asteroid(22, "Kalliope", ..., "JPL", 111)
write(*,*) asteroids(1)%name ! Writes "Ceres".
Asteroid閱讀和寫作
您希望能夠read與write小行星往返檔案,您可以使用用戶定義的輸入/輸出來做到這一點。為此,您需要一個子程式read,Asteroid例如
subroutine read_Asteroid(this, unit, iotype, v_list, iostat, iomsg)
class(Asteroid), intent(inout) :: this
integer, intent(in) :: unit
character(*), intent(in) :: iotype
integer, intent(in) :: v_list(:)
integer, intent(out) :: iostat
character(*), intent(inout) :: iomsg
character(100) :: name
character(100) :: ref_name
read(unit, *, iostat=iostat, iomsg=iomsg) &
& this%num, &
& name, &
& this%epoch, &
& this%a, &
& this%e, &
& this%i, &
& this%w, &
& this%node, &
& this%m, &
& this%h, &
& this%g, &
& ref_name, &
& this%ref_number
this%name = trim(name)
this%ref_name = trim(ref_name)
end subroutine
另一個到write一個Asteroid,例如
subroutine write_Asteroid(this, unit, iotype, v_list, iostat, iomsg)
class(Asteroid), intent(in) :: this
integer, intent(in) :: unit
character(*), intent(in) :: iotype
integer, intent(in) :: v_list(:)
integer, intent(out) :: iostat
character(*), intent(inout) :: iomsg
write(unit, *, iostat=iostat, iomsg=iomsg) &
& this%num, &
& this%name, &
& this%epoch, &
& this%a, &
& this%e, &
& this%i, &
& this%w, &
& this%node, &
& this%m, &
& this%h, &
& this%g, &
& this%ref_name, &
& this%ref_number
end subroutine
您還需要添加bindings到Asteroid型別,以便它知道使用read_Asteroid和write_Asteroid讀寫。這看起來像
type :: Asteroid
integer :: num
...
integer :: ref_number
contains
! `read` binding.
generic :: read(formatted) => read_Asteroid
procedure :: read_Asteroid
! `write` binding.
generic :: write(formatted) => write_Asteroid
procedure :: write_Asteroid
end type
注意,因為該Asteroid型別有allocatable組件(name和ref_name),它們不是由read陳述句分配的,所以在撰寫時必須小心read_Asteroid。這個方法可以用來讀allocatables;首先讀取一個過大的緩沖區,然后將資料復制到allocatable變數中。(感謝@francescalus 在這里指出我的代碼以前存在的問題)。
現在可以直接read和write小行星,例如
character(1000) :: line
type(Asteroid) :: Ceres
line = "1 Ceres 59600 2.766 0.07850 10.58 73.63 80.26 291.3 3.54 0.12 JPL 48"
read(line, *) Ceres
write(*, *) Ceres
示例代碼
把這一切放在一起,這是一個示例代碼,它讀取一個充滿小行星的檔案,然后將這些檔案寫入i < 2:
module asteroid_module
implicit none
! Define `dp`, which defines double precision.
integer, parameter :: dp = selected_real_kind(15, 307)
! Define the `Asteroid` type.
type :: Asteroid
integer :: num
character(:), allocatable :: name
integer :: epoch
real(dp) :: a
real(dp) :: e
real(dp) :: i
real(dp) :: w
real(dp) :: node
real(dp) :: m
real(dp) :: h
real(dp) :: g
character(:), allocatable :: ref_name
integer :: ref_number
contains
! `read` binding.
generic :: read(formatted) => read_Asteroid
procedure :: read_Asteroid
! `write` binding.
generic :: write(formatted) => write_Asteroid
procedure :: write_Asteroid
end type
contains
! Define how to `read` an `Asteroid`.
subroutine read_Asteroid(this, unit, iotype, v_list, iostat, iomsg)
class(Asteroid), intent(inout) :: this
integer, intent(in) :: unit
character(*), intent(in) :: iotype
integer, intent(in) :: v_list(:)
integer, intent(out) :: iostat
character(*), intent(inout) :: iomsg
character(100) :: name
character(100) :: ref_name
read(unit, *, iostat=iostat, iomsg=iomsg) &
& this%num, &
& name, &
& this%epoch, &
& this%a, &
& this%e, &
& this%i, &
& this%w, &
& this%node, &
& this%m, &
& this%h, &
& this%g, &
& ref_name, &
& this%ref_number
this%name = trim(name)
this%ref_name = trim(ref_name)
end subroutine
! Define how to `write` an `Asteroid`.
subroutine write_Asteroid(this, unit, iotype, v_list, iostat, iomsg)
class(Asteroid), intent(in) :: this
integer, intent(in) :: unit
character(*), intent(in) :: iotype
integer, intent(in) :: v_list(:)
integer, intent(out) :: iostat
character(*), intent(inout) :: iomsg
write(unit, *, iostat=iostat, iomsg=iomsg) &
& this%num, &
& this%name, &
& this%epoch, &
& this%a, &
& this%e, &
& this%i, &
& this%w, &
& this%node, &
& this%m, &
& this%h, &
& this%g, &
& this%ref_name, &
& this%ref_number
end subroutine
end module
program example
use asteroid_module
implicit none
character(1000) :: line
integer :: iostat
integer :: file_length
type(Asteroid), allocatable :: asteroids(:)
integer :: i
! Count the number of lines in the file.
file_length = 0
open(10, file="input.txt")
do
read(10, '(A)',iostat=iostat) line
if (iostat/=0) then
exit
endif
file_length = file_length 1
enddo
close(10)
! Allocate the array to hold the asteroids.
allocate(asteroids(file_length-2))
! Read the asteroids into the array.
open(10, file="input.txt")
read(10, '(A)') line
read(10, '(A)') line
do i=1,size(asteroids)
read(10, '(A)') line
read(line, *) asteroids(i)
enddo
close(10)
! Write the asteroids with `i` < 2 to a file.
open(10, file="output.txt")
do i=1,size(asteroids)
if (asteroids(i)%i < 2.0_dp) then
write(10,*) asteroids(i)
endif
enddo
close(10)
end program
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/412279.html
標籤:
上一篇:如何在R中壓縮帶有日期的資料集
