# 安裝 GFortran 使用 Fortran 程式讀取、寫入 csv 檔
> 作者:王一哲
> 日期:2021/7/31
<br />
## 前言
我之前幾乎沒有寫過 Fortran,這次為了幫某人擺脫需要花錢購買的 [Visual Fortran](https://software.intel.com/content/www/us/en/develop/articles/intel-visual-fortran-compiler-190-for-windows-release-notes-for-intel-parallel-studio-xe-2019.html),我只好從零開始學 Fortran,並且試試看是否能用 [GFortran](https://gcc.gnu.org/wiki/GFortran) 編譯他們實驗室需要的程式碼,由 csv 檔讀取資料經過一些運算後再儲存成另一個 csv 檔,以下是我測試的筆記。
<br />
## 於 Ubuntu 安裝 GFortran
我使用的作業系統是 Ubuntu 20.04.2 LTS,只要在文字界面中執行以下指令即可安裝 GFortran。
```shell
sudo apt install gfortran-10
```
<br />
安裝完畢之後可以用以下指令查詢安裝的版本,我安裝的版本是 10.3.0。
```shell
gfortran-10 --version
```
<br />
建立一個測試用的資料夾,於資料夾中用文字編輯器將以下內容儲存成 hello.f95。
```fortran
program hello
write(*, *) 'Hello World!'
write(*, *) '哈囉世界!'
stop
end program hello
```
<br />
用以下指令將 hello.f95 編譯成執行檔再執行檔案。
```shell
gfortran-10 -o hello hello.f95
./hello
```
<br />
如果螢幕輸出以下文字就成功了。
```shell
Hello World!
哈囉世界!
```
<br />
## 於 Windows 10 安裝 GFortran
我使用的作業系統是 Windows 10 家用版。安裝步驟主要是參考這篇文章 [Installation of GFortran in Windows 10](https://masuday.github.io/fortran_tutorial/install_gfortran_windows.html)。先安裝 [mingw-w64](http://mingw-w64.org/doku.php),目前最新的版本是 msys2-x86_64-20210725.exe,[下載連結在此](https://github.com/msys2/msys2-installer/releases/download/2021-07-25/msys2-x86_64-20210725.exe)。安裝完成之後開啟 MSYS2 MinGW 64-bit。
<img height="40%" width="40%" src="https://i.imgur.com/xIlG034.png" style="display: block; margin-left: auto; margin-right: auto;"/>
<div style="text-align:center">MSYS2</div>
<br /><br />
輸入以下指令更新軟體列表、安裝 GFortran。
```shell
pacman -Syu
pacman -Su gcc-fortran
```
<br />
輸入以下指令查詢安裝好的 GFortran 版本。
```shell
gfortran.exe --version
```
<br />
我安裝的是 10.2.0 版。用 pwd 查詢路徑,看起來是在 /home/[UserName] 底下,實際上的路徑是
```shell
C:\msys64\home\[UserName]
```
<br />
接著用 Hello World! 測試一下。
<img height="60%" width="60%" src="https://i.imgur.com/oMB3I1f.png" style="display: block; margin-left: auto; margin-right: auto;"/>
<div style="text-align:center">於 Windows 10 測試 GFortran</div>
<br /><br />
## 使用 Fortran 程式讀取、寫入 csv 檔
這次的目標是要在執行程式時於後方加上輸入、輸出檔名,由輸入的 csv 檔讀取資料,再將資料寫到輸出的 csv 檔,主要是參考這兩個網頁的內容:[Passing command line arguments](https://riptutorial.com/fortran/example/26615/passing-command-line-arguments)、[TEK-TIPS.COM: Help with .csv](https://www.tek-tips.com/viewthread.cfm?qid=1710427)。假設輸入檔名為 input.csv,內容如下,第一行開頭的 ! 是為了在讀取資料時忽略此行而加上的記號。
```
!h(m),t(s),errt(s)
2,0.65,0.01
4,0.89,0.01
6,1.11,0.01
8,1.27,0.01
10,1.42,0.01
12,1.57,0.01
14,1.71,0.01
16,1.79,0.01
18,1.92,0.01
20,2.03,0.01
```
<br />
以下是我測試成功的程式碼。
```fortran=
program fileIO
implicit none ! 不使用預設變數名稱及種類對應關係
character(20) :: inputfile ! 輸入檔名用的變數
character(20) :: outputfile ! 輸出檔名用的變數
integer :: flag1, flag2, line_num ! 檔案狀態1、2, 行號
character(80) :: line ! 讀取的整行資料
real :: h, t, t2, errt ! 儲存資料的變數
! 檢查輸入的參數是否為2個
if(command_argument_count().NE.2) then
write(*,*) 'Error! Please enter the input and output file names.'
stop
end if
! 由輸入的參數取得輸入、輸出檔名
call get_command_argument(1, inputfile)
call get_command_argument(2, outputfile)
write(*,*) 'The input file name is: ', inputfile
write(*,*) 'The output file name is: ', outputfile
! 由 inputfile 讀取資料, 準備寫入資料至 outputfile
open(3, file=inputfile, status='old', action='read', iostat=flag1)
open(4, file=outputfile, action='write', iostat=flag2)
! 檢查是否能開啟檔案
if(flag1 .NE. 0) then
write(*, *) 'Cannot open input file!'
go to 99
end if
if(flag2 .NE. 0) then
write(*, *) 'Cannot open output file!'
go to 99
end if
! 於 outputfile 寫入欄位標題
write(4, *) '!h(m),t(s),t2(s2),errt(s)'
line_num = 0
do
! 讀取整行資料並存入 line
read(3, '(A)', end=99, iostat=flag1) line
! 若 flag1 不等於 0 則跳到 99 continue
if(flag1 .NE. 0) then
write(*, *) 'Cannot read data!'
go to 99
end if
! 若 line 的開頭為 '!' 則不做任何事
if(adjustl(trim(line(1:1))) .EQ. '!') then
cycle
end if
! 將 line 的資料分別存入 h, t, errt, 計算 t^2, 存入 outputfile
read(line, *) h, t, errt
t2 = t**2
write(*, *) 'line ', line_num, ': ', h, t, t2, errt
line_num = line_num + 1
write(4, *) h, ',', t, ',', t2, ',', errt
end do
99 continue
close(3)
close(4)
stop
end program fileIO
```
<br />
假設檔名是 fileIO.f95,在 Ubuntu 可以使用以下指令編譯程式。
```fortran
gfortran-10 -o fileIO fileIO.f95
```
<br />
在 Windows 10 可以使用以下指令編譯程式。
```fortran
gfortran.exe -o fileIO fileIO.f95
```
<br />
使用以下指令執行程式。
```shell
./fileIO input.csv output.csv
```
<br />
於文字界面輸出以下的內容。
```shell
The input file name is: input.csv
The output file name is: output.csv
line 0 : 2.00000000 0.649999976 0.422499955 9.99999978E-03
line 1 : 4.00000000 0.889999986 0.792099953 9.99999978E-03
line 2 : 6.00000000 1.11000001 1.23210001 9.99999978E-03
line 3 : 8.00000000 1.26999998 1.61289990 9.99999978E-03
line 4 : 10.0000000 1.41999996 2.01639986 9.99999978E-03
line 5 : 12.0000000 1.57000005 2.46490026 9.99999978E-03
line 6 : 14.0000000 1.71000004 2.92410016 9.99999978E-03
line 7 : 16.0000000 1.78999996 3.20409989 9.99999978E-03
line 8 : 18.0000000 1.91999996 3.68639994 9.99999978E-03
line 9 : 20.0000000 2.02999997 4.12089968 9.99999978E-03
```
<br />
<img height="100%" width="100%" src="https://i.imgur.com/CBjWRKC.png" style="display: block; margin-left: auto; margin-right: auto;"/>
<div style="text-align:center">於 Windows 10 測試 fileIO 程式碼</div>
<br /><br />
輸出的 csv 檔如下,看來應該有達到我要的效果。
```shell
!h(m),t(s),t2(s2),errt(s)
2.00000000 , 0.649999976 , 0.422499955 , 9.99999978E-03
4.00000000 , 0.889999986 , 0.792099953 , 9.99999978E-03
6.00000000 , 1.11000001 , 1.23210001 , 9.99999978E-03
8.00000000 , 1.26999998 , 1.61289990 , 9.99999978E-03
10.0000000 , 1.41999996 , 2.01639986 , 9.99999978E-03
12.0000000 , 1.57000005 , 2.46490026 , 9.99999978E-03
14.0000000 , 1.71000004 , 2.92410016 , 9.99999978E-03
16.0000000 , 1.78999996 , 3.20409989 , 9.99999978E-03
18.0000000 , 1.91999996 , 3.68639994 , 9.99999978E-03
20.0000000 , 2.02999997 , 4.12089968 , 9.99999978E-03
```
<br />
## 結語
由於 Fortran 的語法與 Python、C、C++ 差異很大,寫起來感覺相當奇怪。接下來還要再修改他們實驗室以前的程式碼,其中一部分還是採用 Fortran 77 的語法撰寫,要修改成新版 GFotrtan 可以接受的語法才行,好像還有不少的麻煩要解決。
<br />
## 參考資料
1. [gfortran — the GNU Fortran compiler, part of GCC](https://gcc.gnu.org/wiki/GFortran)
2. [Installation of GFortran in Windows 10](https://masuday.github.io/fortran_tutorial/install_gfortran_windows.html)
3. [mingw-w64](http://mingw-w64.org/doku.php)
4. [Passing command line arguments](https://riptutorial.com/fortran/example/26615/passing-command-line-arguments)
5. [TEK-TIPS.COM: Help with .csv](https://www.tek-tips.com/viewthread.cfm?qid=1710427)
<br />
---
###### tags:`Computer`、`Fortran`