在 foxpro 中复制到 excel Sheet

COPY TO excel Sheet in foxpro

是他们在 Foxpro 中将 DBF 转换为特定 excel sheet 的任何命令。 我有三个 DBF(dbf_1、dbf_2、dbf_3)。我当前的程序使用 copy 将文件转换为 "filename.xls",键入 fox2x,然后我将手动将所有 sheet 合并为一个 excel。对我来说,我使用的这种方法没问题,但如果它们是 20 个或更多 dbf,我将合并。是他们在 foxpro 中将 dbf 转换为一个 excel 文件的任何命令。我已经在使用 foxpro Automation,但速度很慢。

不,没有。

还有"copy to ... type fox2x"。虽然比很多其他的类型选择(比如csv和xls)更好的时候应该不会选择有更好的方法。

您说自动化很慢,但不知道您是否真的发现自动化很慢,或者您是否以不应该使用的方式尝试将数据传输到 Excel。下面的示例使用了我的 "vfp2excel" 函数和自动化的变体之一。它在我的机器上在 2.5 秒内传输样本客户、员工、订单、OrdItems 和产品数据。如果你真的认为它很慢那么就不要骰子,否则这里是示例:

 * These represent complex SQL as a sample
Select emp_id,First_Name,Last_Name,;
    Title,Notes ;
    from (_samples+'\data\employee') ;
    into Cursor crsEmployee ;
    readwrite
Replace All Notes With Chrtran(Notes,Chr(13)+Chr(10),Chr(10))

Select cust_id,company,contact,Title,country,postalcode ;
    from (_samples+'\data\customer') ;
    into Cursor crsCustomer ;
    nofilter

Select * ;
    from (_samples+'\data\orders') ;
    into Cursor crsOrders ;
    nofilter

Select * ;
    from (_samples+'\data\orditems') ;
    into Cursor crsOrderDetail ;
    nofilter

Select * ;
    from (_samples+'\data\products') ;
    into Cursor crsProducts ;
    nofilter

* Now we want to get these on 3 sheets
* Sheet1: Employees only
* Sheet2: Customers only
* Sheet3: Orders, ordItems, Products layed out horizontally

Local oExcel
oExcel = Createobject("Excel.Application")
With oExcel
    .DisplayAlerts = .F.
    .Workbooks.Add
    .Visible = .T.
    With .ActiveWorkBook
        For ix = 1 To 3 && We want 3 Sheets
            If .sheets.Count < m.ix
                .sheets.Add(,.sheets(.sheets.Count)) && Add new sheets
            Endif
        Endfor
        * Name the sheets
        .WorkSheets(1).Name = "Employees"
        .WorkSheets(2).Name = "Customers"
        .WorkSheets(3).Name = "Order, OrderDetail, Products" && max sheetname is 31 chars

        * Start sending data
        * First one has headers specified
        VFP2Excel('crsEmployee',    .WorkSheets(1).Range("A1"), ;
            "Id,First Name,Last Name,Employee Title,Comments about employee" ) && To sheet1, start at A1
        VFP2Excel('crsCustomer',    .WorkSheets(2).Range("A1") ) && To sheet2, start at A1
        VFP2Excel('crsOrders',      .WorkSheets(3).Range("A1") ) && To sheet3, start at A1
        * Need to know where to put next
        * Leave 2 columns empty - something like 'G1'
        lcRange = _GetChar(.WorkSheets(3).UsedRange.Columns.Count + 3) + '1'
        * To sheet3, start at next to previous
        VFP2Excel('crsOrderDetail', .WorkSheets(3).Range(m.lcRange) )

        lcRange = _GetChar(.WorkSheets(3).UsedRange.Columns.Count + 3) + '1'
        * To sheet3, start at next to previous
        VFP2Excel('crsProducts',    .WorkSheets(3).Range(m.lcRange) )

        #Define xlJustify                                         -4130
        #Define xlTop                                             -4160

        * I just happen to know notes in at column 5 from SQL
        * No need to query from excel to keep code simple
        * Lets format that column specially instead of leaving
        * at the mercy of Excel's autofitting
        .WorkSheets(1).UsedRange.VerticalAlignment = xlTop && set all to top
        With .WorkSheets(1).Columns(5)
            .ColumnWidth = 80 && 80 chars width
            .WrapText = .T.
            *      .HorizontalAlignment = xlJustify && doesn't work good always
        Endwith

        * Finally some cosmetic stuff
        For ix=1 To 3
            With .WorkSheets(m.ix)
                .Columns.AutoFit
                .Rows.AutoFit
            Endwith
        Endfor

        .WorkSheets(1).Activate
    Endwith
Endwith


* Author: Cetin Basoz
* This is based on earlier VFP2Excel function codes
* that has been published on the internet, at various sites
* since 2001. Not to be messed with others' code who named the same but has
* nothing to do with the approaches taken here (unless copy & pasted and claimed
* to be their own work, < s > that happens).
Procedure VFP2Excel(tcCursorName, toRange, tcHeaders, tnPrefferredWidthForMemo)
    * tcCursorName
    * toRange
    * tcHeaders: Optional. Defaults to field headers
    * tnPrefferredWidthForMemo: Optional. Default 80
    * Function VFP2Excel
    tcCursorName = Evl(m.tcCursorName,Alias())
    tnPrefferredWidthForMemo = Evl(m.tnPrefferredWidthForMemo,80)
    Local loConn As AdoDB.Connection, loRS As AdoDB.Recordset,;
        lcTemp,lcTempDb, oExcel,ix, lcFieldName, lcHeaders

    lnSelect = Select()
    lcTemp   = Forcepath(Sys(2015)+'.dbf',Sys(2023))
    lcTempDb = Forcepath(Sys(2015)+'.dbc',Sys(2023))

    Create Database (m.lcTempDb)
    Select * From (m.tcCursorName) Into Table (m.lcTemp) Database (m.lcTempDb)

    Local Array aMemo[1]
    Local nMemoCount
    nMemoCount = 0
    lcHeaders = ''
    For ix = 1 To Fcount()
        lcFieldName = Field(m.ix)
        If Type(Field(m.ix))='M'
            nMemoCount = m.nMemoCount + 1
            Dimension aMemo[m.nMemoCount]
            aMemo[m.nMemoCount] = m.ix
            Replace All &lcFieldName With Chrtran(&lcFieldName,Chr(13)+Chr(10),Chr(10))
        Endif
        lcHeaders = m.lcHeaders + Iif(Empty(m.lcHeaders),'',',')+Proper(m.lcFieldName)
    Endfor
    tcHeaders = Evl(m.tcHeaders,m.lcHeaders)

    Use In (Juststem(m.lcTemp))
    Close Databases
    Set Database To

    loStream = Createobject('AdoDb.Stream')
    loConn = Createobject('ADODB.Connection')
    loRS = Createobject("ADODB.Recordset")
    loConn.ConnectionString = "Provider=VFPOLEDB;Data Source="+m.lcTempDb
    loConn.Open()
    loRS = loConn.Execute("select * from "+m.lcTemp)
    loRS.Save( loStream )
    loRS.Close
    loConn.Close
    Erase (m.lcTemp)

    * Use first row for headers
    Local Array aHeader[1]

    loRS.Open( loStream )
    toRange.Offset(1,0).CopyFromRecordSet( loRS )  && Copy data starting from headerrow + 1

    Set Safety Off
    Delete Database (m.lcTempDb) Deletetables

    Select (m.lnSelect)

    For ix=1 To Iif( !Empty(m.tcHeaders), ;
            ALINES(aHeader, m.tcHeaders,1,','), ;
            loRS.Fields.Count )
        toRange.Offset(0,m.ix-1).Value = ;
            Iif( !Empty(m.tcHeaders), ;
            aHeader[m.ix], ;
            Proper(loRS.Fields(m.ix-1).Name) )
        toRange.Offset(0,m.ix-1).Font.Bold = .T.
    Endfor

    #Define xlJustify                                         -4130
    #Define xlTop                                             -4160
    * This part is cosmetic
    toRange.WorkSheet.Activate
    With toRange.WorkSheet.UsedRange
        .VerticalAlignment = xlTop && set all to top
        For ix=1 To m.nMemoCount
            With .Columns(aMemo[m.ix])
                .ColumnWidth = m.tnPrefferredWidthForMemo && 80 chars width
                .WrapText = .T.
            Endwith
        Endfor
        .Columns.AutoFit
        .Rows.AutoFit
    Endwith
Endproc

* Return A, AA, BC etc noation for nth column
Function _GetChar
    Lparameters tnColumn && Convert tnvalue to Excel alpha notation
    If m.tnColumn = 0
        Return ""
    Endif
    If m.tnColumn <= 26
        Return Chr(Asc("A")-1+m.tnColumn)
    Else
        Return  _GetChar(Int(Iif(m.tnColumn % 26 = 0,m.tnColumn - 1, m.tnColumn) / 26)) + ;
            _GetChar((m.tnColumn-1)%26+1)
    Endif
Endfunc

这就是我一直在寻找的:-)我正在尝试使用 Excel AutomationVisual FoxPro[=21] 中编程的知识=] 但总是出错。我的任务是从一个大游标创建 "n" 表,我想从游标中解析关于客户 select 属性名称的离子,以获取 "n" 表。此示例适用于 3 个游标和 3 个工作表,它是通用的。但是我需要这个 "n" 游标 一个属性 客户 select 不同 在一个 Excel 文件 中得到 "n" 张 。所以现在我有了 dynamic 过程。我定制了这段代码并解决了我试图结束大约 4 天的问题。再次感谢您提供此代码,当然我不会修改 VFP2Excel 程序并在其他地方写下我的名字。感谢您的帮助!

没有 native VFP 函数可以做到这一点,但是,有一个很棒的开源项目,它有一个 class 可以使这非常容易:

VFPx 工作簿 Xlsx - 在 Github 上查看:XLSX Workbook for FoxPro

它有 3 个神奇的功能,可以完全满足您的要求:

  • 创建工作簿()
  • AddSheet()
  • SaveTableToWorkbook()

(为每个要创建的 DBF/Sheet 重复上面的命令 2 和 3)

它有一个 54 页的 PDF 和代码示例,解释了您需要知道的一切。