【问题标题】:How to export a text file in for each loop?如何为每个循环导出一个文本文件?
【发布时间】:2020-01-16 17:16:22
【问题描述】:

我写了一个程序来将文件导出到一个特定的目录,我觉得我写了一些不需要的逻辑。所以我想知道导出文件的简短和最佳方法。让我分享一下我的尝试

DEFINE VARIABLE cData AS CHARACTER NO-UNDO.
DEFINE VARIABLE i     AS INTEGER NO-UNDO.
DEFINE VARIABLE icount AS INTEGER NO-UNDO.
DEFINE VARIABLE cName AS CHARACTER NO-UNDO.
DEFINE VARIABLE cPath AS CHARACTER NO-UNDO.

DEFINE TEMP-TABLE ttdata
    FIELD GetName  AS CHARACTER 
    FIELD iValue   AS INTEGER.

ASSIGN
    icount = 2
    cPath  = "*******".

DO I = 1 TO icount:
    IF I = 1  THEN cName = "David".
    IF I = 2  THEN cName = "Macavo".


   CREATE ttdata.
   ASSIGN
        ttdata.GetName = cName
        ttdata.iValue  =  100.
END.

/** ttdata has two records now*/
FOR EACH ttdata.
    RUN CallProc.p (INPUT ttdata.GetName,
                    INPUT ttdata.iValue).
END.

PROCEDURE CallProc:

    DEFINE INPUT PARAMETER getName AS CHARACTER NO-UNDO.
    DEFINE INPUT PARAMETER iValue  AS INTEGER   NO-UNDO.

    OUTPUT TO cPath.
    PUT UNFORMATTED ttdata.GetName ttdata.GetName.
    OUTPUT CLOSE.
END PROCEDURE.

根据我的逻辑,它运行良好并按我的预期导出 2 个文件,但调用另一个程序是个坏主意。请帮助这个案例。

【问题讨论】:

  • 您再次标记了一些普通的“进步”。 “openedge”和“progress-4gl”更有帮助。
  • 对不起先生..我在多件事之间..我不会再这样做了

标签: openedge progress-4gl


【解决方案1】:

我将在我的示例中使用sports2000 db。每个人都有一份副本,因此运行示例很容易。

define stream outFile.  /* using a named stream rather than the default, unnamed, stream avoids unintended conflicts if someone else's code is lazily using the unnamed stream */

function mkTemp returns character ( input tmpid as character, input extension as character ):

  define variable fname as character no-undo.
  run adecomm/_tmpfile.p ( tmpid, extension, output fname ).

  /* create the temp file with no content
   */

  output stream outFile to value( fname ).
  output stream outFile close.

  return fname.

end.


procedure doStuff:

  define input parameter tmpfile as character no-undo.
  define input parameter custid  as integer   no-undo.

  output stream outFile to value( tmpFile ) append.  /* open the existing file in append mode */

  put stream outFile "customer:" custId skip.
  for each order no-lock where order.custNum = custId and orderStatus <> "shipped" and salesRep = "bbb":
    put stream outFile orderNum " " promised skip.
  end.

  output stream outFile close.

  return.

end.

define variable i       as integer no-undo.
define variable tmpName as character no-undo.

/* tmpName = mkTemp( "xyzzy", ".tmp" ). */  /* if you only need one temp file get the name here and comment it out below */

for each customer no-lock:

  tmpName = mkTemp( "xyzzy", ".tmp" ).  /* use this if every customer should get a distinct temp file */

  run doStuff ( tmpName, custNum ).

  /* if there is no good reason to be calling the doStuff() procedure then just remove it and do it inline like this: */

  /*
   *
  output stream outFile to value( tmpFile ) append.  /* open the existing file in append mode */

  put stream outFile "customer:" customer.custNum skip.
  for each order no-lock where order.custNum = customer.CustNum and orderStatus <> "shipped" and salesRep = "bbb":
    put stream outFile orderNum " " promised skip.
  end.

  output stream outFile close.

   */

  i = i + 1.
  if i >= 3 then leave.  /* just do 3 customers for the sample run... */

end.

【讨论】:

    【解决方案2】:

    这个程序乍一看还不错,但有几个问题。

    DEFINE TEMP-TABLE 可以使用 NO-UNDO。

    您可能应该使用“FOR EACH ttdata:”而不是“FOR EACH ttdata”。这是旧风格。

    您正在运行 CallProc.p,它是一个外部程序,而不是您的示例中包含的内部程序。如果您的代码实际运行,您必须向我们展示 CallProc.p 中的代码。

    假设代码来自 CallProc,您打开的文件名为 cPath。 (我不明白为什么要写两个文件。)如果你想把文件命名为“*******”,你必须写 value(cPath) 而不是 cPath,但是“**** ***" 在 Windows 中无论如何都是无效的名称。

    为每一行运行一个过程并没有太大的伤害。更大的问题是您每次都打开和关闭文件。在 for each 之前打开文件,然后将其关闭。如果你使用的是当前的 OpenEdge 版本,你应该在 finally 块中关闭它。

    此外,您在没有 APPEND 的情况下打开文件,这意味着您每次都在覆盖它,因此只写入最后一条记录。

    至于不使用过程,这应该很简单,尤其是因为您不使用传递给过程的参数。您当前正在输出 ttdata.GetName 两次,这可能是一个错误。此外,由于 UNFORMATTED 不添加任何空格,因此您在 put 语句的末尾缺少一个 SKIP 和一个空格。我想你应该写 PUT UNFORMATTED getName " " iValue skip.

    我想这是某种家庭作业?

    【讨论】:

    • 显然这不是家庭作业。概念是相同的,但程序在我们这边非常大,所以我不想显示所有代码并浪费您宝贵的时间,所以我只写了一些示例查询。是的,我正在将其运行到内部程序,我很抱歉。并且 ttdata 总是有 2 条记录,并且需要导出每条记录,您能否通过对每个循环使用单个来帮助这种情况,并且不传递参数并调用另一个过程。
    • 让您寻求帮助的人更轻松的一种方法是让您的样本针对sports2000 数据库运行。每个人都有一份副本,这使得运行您的示例或尝试建议的解决方案变得非常容易。我知道使用sports2000 创建一个示例并不总是容易——但它经常是这样,当你设法这样做时,我认为你会发现它很有成效。
    • 全世界都可以访问sports2000 数据库 - 在abldojo.services.progress.com创建您的样本
    【解决方案3】:

    如果您需要两个(或更多)单独的导出文件,您需要为它们指定唯一的名称。我在这里通过重用您的“I”变量并每次重新分配 cPath 来做到这一点。尽管我不同意调用单独的过程来编写文件是一个坏主意,但我已将其合并到单个 FOR-EACH 循环中。我还修正了 idspispopd 提出的一些观点。

    DEFINE VARIABLE i     AS INTEGER NO-UNDO.
    DEFINE VARIABLE icount AS INTEGER NO-UNDO.
    DEFINE VARIABLE cName AS CHARACTER NO-UNDO.
    DEFINE VARIABLE cPath AS CHARACTER NO-UNDO.
    
    DEFINE TEMP-TABLE ttdata NO-UNDO
        FIELD GetName  AS CHARACTER 
        FIELD iValue   AS INTEGER.
    
    ASSIGN
        icount = 2.
    
    DO I = 1 TO icount:
        /* Using a CASE statement makes it easier to add in other values in the future */
        CASE I:
            WHEN 1 THEN cName = "David".
            WHEN 2 THEN cName = "Macavo".
        END CASE.
    
        CREATE ttdata.
        ASSIGN
            ttdata.GetName = cName
            ttdata.iValue  =  100.
    END.
    
    /** ttdata has two records now*/
    I = 1.
    FOR EACH ttdata NO-LOCK:
    
        cPath = ".\" + STRING(I) + ".txt".
    
        OUTPUT TO VALUE(cPath).
        PUT UNFORMATTED ttdata.GetName ttdata.iValue SKIP.
        OUTPUT CLOSE.
    
        I = I + 1.
    END.
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-06-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-22
      相关资源
      最近更新 更多