COBOL .csv 文件 IO 到 Table 不工作
COBOL .csv File IO into Table Not Working
我正在尝试学习 Cobol,因为我听说过它,并且认为看一看会很有趣。我遇到了 MicroFocus Cobol,虽然我不太确定它是否与这个 post 相关,但由于我喜欢用 visual studio 写作,所以有足够的动力去尝试和学习它。
我已经阅读了很多相关内容并尝试遵循文档和示例。到目前为止,我已经让用户输入和输出到控制台正常工作,所以我决定尝试文件 IO。当我一次只阅读 'record' 时一切顺利,我意识到 'record' 可能是不正确的行话。虽然我已经编程了一段时间,但我对 cobol 是一个极端的菜鸟。
我有一个我之前编写的 c++ 程序,它只需要一个 .csv 文件并解析它,然后按用户想要的任何列对数据进行排序。我认为在 cobol 中做同样的事情并不难。好吧,显然我在这方面误判了。
我有一个文件,使用 notepad++ 在 windows 中编辑,名为 test.csv,其中包含:
4001942600,140,4
4001942700,141,3
4001944000,142,2
此数据来自美国人口普查,其中 header 列标题为:GEOID、SUMLEV、STATE。我删除了 header 行,因为当时我不知道如何读入它,然后再读入其他数据。任何人...
在 Visual Studio 2015 年,在 Windows 7 Pro 64 位上,使用 Micro Focus,并逐步调试我可以看到 in-record 包含第一行数据。 unstring 对于那个 运行 工作正常但是下一次程序 'loops' 我可以单步调试,查看 in-record 并看到它包含新数据但是当我展开手表时手表显示元素如下所示:
REC-COUNTER 002 PIC 9(3)
+ IN-RECORD {Length = 42} : "40019427004001942700 000 " GROUP
- GEOID {Length = 3} PIC 9(10)
GEOID(1) 4001942700 PIC 9(10)
GEOID(2) 4001942700 PIC 9(10)
GEOID(3) <Illegal data in numeric field> PIC 9(10)
- SUMLEV {Length = 3} PIC 9(3)
SUMLEV(1) <Illegal data in numeric field> PIC 9(3)
SUMLEV(2) 000 PIC 9(3)
SUMLEV(3) <Illegal data in numeric field> PIC 9(3)
- STATE {Length = 3} PIC X
STATE(1) PIC X
STATE(2) PIC X
STATE(3) PIC X
所以我不确定为什么在第二次 Unstring 操作之前我可以看到正确的数据,但是在 unstring 发生之后不正确的数据存储在 'table' 中。同样有趣的是,如果我第三次继续,正确的数据将存储在 'table' 中。
identification division.
program-id.endat.
environment division.
input-output section.
file-control.
select in-file assign to "C:/Users/Shittin Kitten/Google Drive/Embry-Riddle/Spring 2017/CS332/group_project/cobol1/cobol1/test.csv"
organization is line sequential.
data division.
file section.
fd in-file.
01 in-record.
05 record-table.
10 geoid occurs 3 times pic 9(10).
10 sumlev occurs 3 times pic 9(3).
10 state occurs 3 times pic X(1).
working-storage section.
01 switches.
05 eof-switch pic X value "N".
* declaring a local variable for counting
01 rec-counter pic 9(3).
* Defining constants for new line and carraige return. \n \r DNE in cobol!
78 NL value X"0A".
78 CR value X"0D".
78 TAB value X"09".
******** Start of Program ******
000-main.
open input in-file.
perform
perform 200-process-records
until eof-switch = "Y".
close in-file;
stop run.
*********** End of Program ************
******** Start of Paragraph 2 *********
200-process-records.
read in-file into in-record
at end move "Y" to eof-switch
not at end compute rec-counter = rec-counter + 1;
end-read.
Unstring in-record delimited by "," into
geoid in record-table(rec-counter),
sumlev in record-table(rec-counter),
state in record-table(rec-counter).
display "GEOID " & TAB &">> " & TAB & geoid of record-table(rec-counter).
display "SUMLEV >> " & TAB & sumlev of record-table(rec-counter).
display "STATE " & TAB &">> " & TAB & state of record-table(rec-counter) & NL.
************* End of Paragraph 2 **************
我很困惑为什么我在读取操作后实际上可以看到数据,但它没有存储在 table 中。我也尝试将 table 的声明更改为图片 9(一定长度),结果发生了变化,但我似乎无法确定我没有得到什么。
好吧,我想通了。再次进行单步调试,并将鼠标悬停在 record-table
上时,我注意到在最后一个数据字段之后出现了 26 个空格。现在今晚早些时候,我试图按原样更改 'fly' 上的数据,因为通常 visual studio 允许这样做。我试图进行更改,但没有验证它是否需要,通常我不需要,但显然它没有。现在我应该更清楚了,因为显示在 record-table
左侧的图标显示了一个关闭的小挂锁。
我通常使用 C、C++ 和 C# 进行编程,所以当我看到小挂锁时,它通常与作用域和可见性有关。由于不太了解 COBOL,我忽略了这个小细节。
现在我决定 unstring in-record delimited by spaces into temp-string.
在
之前
Unstring temp-string delimited by "," into
geoid in record-table(rec-counter),
sumlev in record-table(rec-counter),
state in record-table(rec-counter).
结果是格式正确的数据,至少据我所知,存储到 table 并打印到控制台屏幕。
现在我已经读到 unstring
'function' 可以利用多个 'operators' 这样我可能会尝试将这两个 unstring
操作合并为一个。
干杯!
**** 更新 ****
我已阅读下面伍德格先生的回复。如果我可以为此寻求更多帮助。我也读过这个post,它与我此时的水平相似但高于我的水平。 COBOL read/store in table
这几乎就是我想要做的,但我不明白 Woodger 先生试图解释的一些事情。下面是一些我作为评论提出的问题的更完善的代码。我非常希望在这方面得到一些帮助,或者如果我可以进行离线对话也可以。
`identification division.
* I do not know what 'endat' is
program-id.endat.
environment division.
input-output section.
file-control.
* assign a file path to in-file
select in-file assign to "C:/Users/Shittin Kitten/Google Drive/Embry-Riddle/Spring 2017/CS332/group_project/cobol1/cobol1/test.csv"
* Is line sequential what I need here? I think it is
organization is line sequential.
* Is the data devision similar to typedef in C?
data division.
* Does the file sectino belong to data division?
file section.
* Am I doing this correctly? Should this be below?
fd in-file.
* I believe I am defining a structure at this point
01 in-record.
05 record-table.
10 geoid occurs 3 times pic A(10).
10 sumlev occurs 3 times pic A(3).
10 state occurs 3 times pic A(1).
* To me the working-storage section is similar to ADA declarative section
* is this a correct analogy?
working-storage section.
* Is this where in-record should go? Is in-record a representative name?
01 eof-switch pic X value "N".
01 rec-counter pic 9(1).
* I don't know if I need these
78 NL value X"0A".
78 TAB value X"09".
01 sort-col pic 9(1).
********************************* Start of Program ****************************
*Now the procedure division, this is alot like ada to me
procedure division.
* Open the file
perform 100-initialize.
* Read data
perform 200-process-records
* loop until eof
until eof-switch = "Y".
* ask user to sort by a column
display "Would which column would you like to bubble sort? " & TAB.
* get user input
accept sort-col.
* close file
perform 300-terminate.
* End program
stop run.
********************************* End of Program ****************************
******************************** Start of Paragraph 1 ************************
100-initialize.
open input in-file.
* Performing a read, what is the difference in this read and the next one
* paragraph 200? Why do I do this here instead of just opening the file?
read in-file
at end
move "Y" to eof-switch
not at end
* Should I do this addition here? Also why a semicolon?
add 1 to rec-counter;
end-read.
* Should I not be unstringing here?
Unstring in-record delimited by "," into geoid of record-table,
sumlev of record-table, state of record-table.
******************************** End of Paragraph 1 ************************
********************************* Start of Paragraph 2 **********************
200-process-records.
read in-file into in-record
at end move "Y" to eof-switch
not at end add 1 to rec-counter;
end-read.
* Should in-record be something else? I think so but don't know how to
* declare and use it
Unstring in-record delimited by "," into
geoid in record-table(rec-counter),
sumlev in record-table(rec-counter),
state in record-table(rec-counter).
* These lines seem to give the printed format that I want
display "GEOID " & TAB &">> " & TAB & geoid of record-table(rec-counter).
display "SUMLEV >> " & TAB & sumlev of record-table(rec-counter).
display "STATE " & TAB &">> " & TAB & state of record-table(rec-counter) & NL.
********************************* End of Paragraph 2 ************************
********************************* Start of Paragraph 3 ************************
300-terminate.
display "number of records >>>> " rec-counter;
close in-file;
**************************** End of Paragraph 3 *****************************
`
我认为还有一些事情你还没有掌握,但你需要掌握。
在 DATA DIVISION
中,有许多 SECTION,每个 SECTION 都有特定的用途。
FILE SECTION
是您定义表示文件数据(输入、输出或输入-输出)的数据结构的地方。每个文件都有一个FD
,而从属于一个FD的会是一个或多个01级结构,可以很简单,也可以很复杂
一些确切的行为取决于编译器的特定实现,但是您应该这样对待事情,对于您自己的 "minimal surprise" 以及以后必须修改您的程序的任何人:对于输入文件,不要在 READ 后更改数据,除非您要更新记录(如果您正在使用键控 READ,也许)。您可以将 "input area" 视为数据文件中的 "window"。下一个 READ,window 指向不同的位置。或者,您可以将其视为 "the next record arrives, obliterating what was there previously"。您已将 UNSTRING 的 "result" 放入记录区。结果肯定会在下一次读取时消失。您也可以压缩 "following" 数据(如果 window 对于您的编译器是正确的,并且取决于它用于 IO 的机制)。
您的结果应该在工作存储器中,它不会被正在读取的新记录所干扰。
READ filname INTO data-description 是将数据从记录区域隐式移动到数据描述。如果如您所指定的那样,data-description 是record-area,则结果为"undefined"。如果您只需要记录区域中的数据,只需一个普通的 READ 文件名即可。
您的原始 UNSTRING 也有类似的问题。您有引用相同存储的源和目标字段。 "Undefined" 而不是你想要的结果。这就是为什么不必要的 UNSTRING "worked".
您有一个冗余的内联 PERFORM。您在文件结束后处理 "something"。你通过在 PROCEDURE DIVISION 中使用不必要的 "punctuation" 使事情变得更加复杂(你显然已经省略粘贴)。尝试在那里使用 ADD 而不是 COMPUTE。查看 FILE STATUS 和 88 级条件名称的使用。
DISPLAY
不需要 "new line",因为除非使用 NO ADVANCING
.
,否则您将免费获得一个
您不需要在 DISPLAY 中 "concatenate",因为您也可以免费获得它。
DISPLAY 及其堂兄 ACCEPT 是动词(只有内部函数是 COBOL 中的函数(除非您的编译器支持用户定义的函数)),它们在不同的编译器之间变化最大。如果您的编译器在 DATA DIVISION 中支持 SCREEN SECTION
,您可以在 "screens" 中格式化和处理用户输入。如果您要使用 IBM 的企业 COBOL,您将拥有非常基础的 DISPLAY/ACCEPT。
你"declare a local variable"。你?凭什么?本地程序。
通过查看过去几年的 COBOL 问题,您可以学到很多技巧。
我正在尝试学习 Cobol,因为我听说过它,并且认为看一看会很有趣。我遇到了 MicroFocus Cobol,虽然我不太确定它是否与这个 post 相关,但由于我喜欢用 visual studio 写作,所以有足够的动力去尝试和学习它。
我已经阅读了很多相关内容并尝试遵循文档和示例。到目前为止,我已经让用户输入和输出到控制台正常工作,所以我决定尝试文件 IO。当我一次只阅读 'record' 时一切顺利,我意识到 'record' 可能是不正确的行话。虽然我已经编程了一段时间,但我对 cobol 是一个极端的菜鸟。
我有一个我之前编写的 c++ 程序,它只需要一个 .csv 文件并解析它,然后按用户想要的任何列对数据进行排序。我认为在 cobol 中做同样的事情并不难。好吧,显然我在这方面误判了。
我有一个文件,使用 notepad++ 在 windows 中编辑,名为 test.csv,其中包含:
4001942600,140,4
4001942700,141,3
4001944000,142,2
此数据来自美国人口普查,其中 header 列标题为:GEOID、SUMLEV、STATE。我删除了 header 行,因为当时我不知道如何读入它,然后再读入其他数据。任何人...
在 Visual Studio 2015 年,在 Windows 7 Pro 64 位上,使用 Micro Focus,并逐步调试我可以看到 in-record 包含第一行数据。 unstring 对于那个 运行 工作正常但是下一次程序 'loops' 我可以单步调试,查看 in-record 并看到它包含新数据但是当我展开手表时手表显示元素如下所示:
REC-COUNTER 002 PIC 9(3)
+ IN-RECORD {Length = 42} : "40019427004001942700 000 " GROUP
- GEOID {Length = 3} PIC 9(10)
GEOID(1) 4001942700 PIC 9(10)
GEOID(2) 4001942700 PIC 9(10)
GEOID(3) <Illegal data in numeric field> PIC 9(10)
- SUMLEV {Length = 3} PIC 9(3)
SUMLEV(1) <Illegal data in numeric field> PIC 9(3)
SUMLEV(2) 000 PIC 9(3)
SUMLEV(3) <Illegal data in numeric field> PIC 9(3)
- STATE {Length = 3} PIC X
STATE(1) PIC X
STATE(2) PIC X
STATE(3) PIC X
所以我不确定为什么在第二次 Unstring 操作之前我可以看到正确的数据,但是在 unstring 发生之后不正确的数据存储在 'table' 中。同样有趣的是,如果我第三次继续,正确的数据将存储在 'table' 中。
identification division.
program-id.endat.
environment division.
input-output section.
file-control.
select in-file assign to "C:/Users/Shittin Kitten/Google Drive/Embry-Riddle/Spring 2017/CS332/group_project/cobol1/cobol1/test.csv"
organization is line sequential.
data division.
file section.
fd in-file.
01 in-record.
05 record-table.
10 geoid occurs 3 times pic 9(10).
10 sumlev occurs 3 times pic 9(3).
10 state occurs 3 times pic X(1).
working-storage section.
01 switches.
05 eof-switch pic X value "N".
* declaring a local variable for counting
01 rec-counter pic 9(3).
* Defining constants for new line and carraige return. \n \r DNE in cobol!
78 NL value X"0A".
78 CR value X"0D".
78 TAB value X"09".
******** Start of Program ******
000-main.
open input in-file.
perform
perform 200-process-records
until eof-switch = "Y".
close in-file;
stop run.
*********** End of Program ************
******** Start of Paragraph 2 *********
200-process-records.
read in-file into in-record
at end move "Y" to eof-switch
not at end compute rec-counter = rec-counter + 1;
end-read.
Unstring in-record delimited by "," into
geoid in record-table(rec-counter),
sumlev in record-table(rec-counter),
state in record-table(rec-counter).
display "GEOID " & TAB &">> " & TAB & geoid of record-table(rec-counter).
display "SUMLEV >> " & TAB & sumlev of record-table(rec-counter).
display "STATE " & TAB &">> " & TAB & state of record-table(rec-counter) & NL.
************* End of Paragraph 2 **************
我很困惑为什么我在读取操作后实际上可以看到数据,但它没有存储在 table 中。我也尝试将 table 的声明更改为图片 9(一定长度),结果发生了变化,但我似乎无法确定我没有得到什么。
好吧,我想通了。再次进行单步调试,并将鼠标悬停在 record-table
上时,我注意到在最后一个数据字段之后出现了 26 个空格。现在今晚早些时候,我试图按原样更改 'fly' 上的数据,因为通常 visual studio 允许这样做。我试图进行更改,但没有验证它是否需要,通常我不需要,但显然它没有。现在我应该更清楚了,因为显示在 record-table
左侧的图标显示了一个关闭的小挂锁。
我通常使用 C、C++ 和 C# 进行编程,所以当我看到小挂锁时,它通常与作用域和可见性有关。由于不太了解 COBOL,我忽略了这个小细节。
现在我决定 unstring in-record delimited by spaces into temp-string.
在
Unstring temp-string delimited by "," into
geoid in record-table(rec-counter),
sumlev in record-table(rec-counter),
state in record-table(rec-counter).
结果是格式正确的数据,至少据我所知,存储到 table 并打印到控制台屏幕。
现在我已经读到 unstring
'function' 可以利用多个 'operators' 这样我可能会尝试将这两个 unstring
操作合并为一个。
干杯!
**** 更新 ****
我已阅读下面伍德格先生的回复。如果我可以为此寻求更多帮助。我也读过这个post,它与我此时的水平相似但高于我的水平。 COBOL read/store in table
这几乎就是我想要做的,但我不明白 Woodger 先生试图解释的一些事情。下面是一些我作为评论提出的问题的更完善的代码。我非常希望在这方面得到一些帮助,或者如果我可以进行离线对话也可以。
`identification division.
* I do not know what 'endat' is
program-id.endat.
environment division.
input-output section.
file-control.
* assign a file path to in-file
select in-file assign to "C:/Users/Shittin Kitten/Google Drive/Embry-Riddle/Spring 2017/CS332/group_project/cobol1/cobol1/test.csv"
* Is line sequential what I need here? I think it is
organization is line sequential.
* Is the data devision similar to typedef in C?
data division.
* Does the file sectino belong to data division?
file section.
* Am I doing this correctly? Should this be below?
fd in-file.
* I believe I am defining a structure at this point
01 in-record.
05 record-table.
10 geoid occurs 3 times pic A(10).
10 sumlev occurs 3 times pic A(3).
10 state occurs 3 times pic A(1).
* To me the working-storage section is similar to ADA declarative section
* is this a correct analogy?
working-storage section.
* Is this where in-record should go? Is in-record a representative name?
01 eof-switch pic X value "N".
01 rec-counter pic 9(1).
* I don't know if I need these
78 NL value X"0A".
78 TAB value X"09".
01 sort-col pic 9(1).
********************************* Start of Program ****************************
*Now the procedure division, this is alot like ada to me
procedure division.
* Open the file
perform 100-initialize.
* Read data
perform 200-process-records
* loop until eof
until eof-switch = "Y".
* ask user to sort by a column
display "Would which column would you like to bubble sort? " & TAB.
* get user input
accept sort-col.
* close file
perform 300-terminate.
* End program
stop run.
********************************* End of Program ****************************
******************************** Start of Paragraph 1 ************************
100-initialize.
open input in-file.
* Performing a read, what is the difference in this read and the next one
* paragraph 200? Why do I do this here instead of just opening the file?
read in-file
at end
move "Y" to eof-switch
not at end
* Should I do this addition here? Also why a semicolon?
add 1 to rec-counter;
end-read.
* Should I not be unstringing here?
Unstring in-record delimited by "," into geoid of record-table,
sumlev of record-table, state of record-table.
******************************** End of Paragraph 1 ************************
********************************* Start of Paragraph 2 **********************
200-process-records.
read in-file into in-record
at end move "Y" to eof-switch
not at end add 1 to rec-counter;
end-read.
* Should in-record be something else? I think so but don't know how to
* declare and use it
Unstring in-record delimited by "," into
geoid in record-table(rec-counter),
sumlev in record-table(rec-counter),
state in record-table(rec-counter).
* These lines seem to give the printed format that I want
display "GEOID " & TAB &">> " & TAB & geoid of record-table(rec-counter).
display "SUMLEV >> " & TAB & sumlev of record-table(rec-counter).
display "STATE " & TAB &">> " & TAB & state of record-table(rec-counter) & NL.
********************************* End of Paragraph 2 ************************
********************************* Start of Paragraph 3 ************************
300-terminate.
display "number of records >>>> " rec-counter;
close in-file;
**************************** End of Paragraph 3 *****************************
`
我认为还有一些事情你还没有掌握,但你需要掌握。
在 DATA DIVISION
中,有许多 SECTION,每个 SECTION 都有特定的用途。
FILE SECTION
是您定义表示文件数据(输入、输出或输入-输出)的数据结构的地方。每个文件都有一个FD
,而从属于一个FD的会是一个或多个01级结构,可以很简单,也可以很复杂
一些确切的行为取决于编译器的特定实现,但是您应该这样对待事情,对于您自己的 "minimal surprise" 以及以后必须修改您的程序的任何人:对于输入文件,不要在 READ 后更改数据,除非您要更新记录(如果您正在使用键控 READ,也许)。您可以将 "input area" 视为数据文件中的 "window"。下一个 READ,window 指向不同的位置。或者,您可以将其视为 "the next record arrives, obliterating what was there previously"。您已将 UNSTRING 的 "result" 放入记录区。结果肯定会在下一次读取时消失。您也可以压缩 "following" 数据(如果 window 对于您的编译器是正确的,并且取决于它用于 IO 的机制)。
您的结果应该在工作存储器中,它不会被正在读取的新记录所干扰。
READ filname INTO data-description 是将数据从记录区域隐式移动到数据描述。如果如您所指定的那样,data-description 是record-area,则结果为"undefined"。如果您只需要记录区域中的数据,只需一个普通的 READ 文件名即可。
您的原始 UNSTRING 也有类似的问题。您有引用相同存储的源和目标字段。 "Undefined" 而不是你想要的结果。这就是为什么不必要的 UNSTRING "worked".
您有一个冗余的内联 PERFORM。您在文件结束后处理 "something"。你通过在 PROCEDURE DIVISION 中使用不必要的 "punctuation" 使事情变得更加复杂(你显然已经省略粘贴)。尝试在那里使用 ADD 而不是 COMPUTE。查看 FILE STATUS 和 88 级条件名称的使用。
DISPLAY
不需要 "new line",因为除非使用 NO ADVANCING
.
您不需要在 DISPLAY 中 "concatenate",因为您也可以免费获得它。
DISPLAY 及其堂兄 ACCEPT 是动词(只有内部函数是 COBOL 中的函数(除非您的编译器支持用户定义的函数)),它们在不同的编译器之间变化最大。如果您的编译器在 DATA DIVISION 中支持 SCREEN SECTION
,您可以在 "screens" 中格式化和处理用户输入。如果您要使用 IBM 的企业 COBOL,您将拥有非常基础的 DISPLAY/ACCEPT。
你"declare a local variable"。你?凭什么?本地程序。
通过查看过去几年的 COBOL 问题,您可以学到很多技巧。