如何测试上载的Excel文件是否符合要求

时间:2017-08-09 09:53:44

标签: r shiny

背景

假设我有一个shiny应用,用户可以上传Excel文件。用户可以访问某个Excel模板,我想确保只上传此模板的副本。

我目前的做法

我目前的做法如下:

  1. 检查是否存在工作表名称​​ xyz - >如果没有抛出错误
  2. 从表 xyz 中读取数据,将列名与要求进行比较 - >如果缺少列会抛出错误
  3. 重复所有必要的工作表
  4. 当前方法存在问题

    这需要大量硬编码所需的工作表名称和所需的列名称,并且变得乏味。

    问题

    所以我的问题是:我如何确保用户提供有效的文件?您通常使用哪些策略来确保您的应用可以正确处理上传的文件?

    伪代码

    library(shiny)
    library(tidyverse)
    ui <- fluidPage(fileInput("file", "Upload Excel"))
    server <- function(input, output, session) {
        observe({
          req(input$file)
          sheet1 <- tryCatch(read_xlsx(input$file$datapath, sheet = "xyz"),
              error = function(e) {
                 ## do some sort of error handling, e.g. write to a reactiveValue list
              })
          if (!all(.REQUIRED_FIELDS_FOR_XYZ %in% names(sheet1))) {
              ## signal error
          }
        })
    }
    

1 个答案:

答案 0 :(得分:1)

如果您已经在使用Excel,为什么不使用宏来为您完成工作。考虑列出文件路径,检查格式类型,单元格地址,单元格值等。下面的宏将为您完成大部分繁重工作。

Sub GetFolder_Data_Collection()

    Dim colFiles As Collection, c As Range
    Dim strPath As String, f, sht As Worksheet
    Dim wbSrc As Workbook, wsSrc As Worksheet
    Dim rw As Range
    Dim sh As Worksheet, flg As Boolean

    Set sht = ActiveSheet

    strPath = ThisWorkbook.Path

    Set colFiles = GetFileMatches(strPath, "*.xlsx", True)

    With sht
        .Range("A:I").ClearContents
        .Range("A1").Resize(1, 5).Value = Array("Name", "Path", "Cell", "Value", "Numberformat")
        Set rw = .Rows(2)
    End With

    For Each f In colFiles
        Set wbSrc = Workbooks.Open(f)
        Set wsSrc = wbSrc.Sheets(1)
        For Each c In wsSrc.Range(wsSrc.Range("A1"), _
                                  wsSrc.Cells(1, Columns.Count).End(xlToLeft)).Cells


            rw.Cells(2).Value = wbSrc.Path
            sht.Hyperlinks.Add Anchor:=rw.Cells(1), Address:=wbSrc.Path, TextToDisplay:=wbSrc.Name
            rw.Cells(3).Value = c.Address(False, False)
            rw.Cells(4).Value = c.Value
            rw.Cells(5).Value = c.NumberFormat

            i = 6
            For Each sh In Worksheets
                If sh.Name Like "Sheet1*" Or sh.Name Like "*Sheet2*" Then rw.Cells(i).Value = sh.Name & " Exists"
                i = i + 1
            Next


            Set rw = rw.Offset(1, 0)
        Next c
        wbSrc.Close False
    Next f
End Sub


'Return a collection of file objects given a starting folder and a file pattern
'  e.g. "*.txt"
'Pass False for last parameter if don't want to check subfolders
Function GetFileMatches(startFolder As String, filePattern As String, _
                    Optional subFolders As Boolean = True) As Collection

    Dim fso, fldr, f, subFldr
    Dim colFiles As New Collection
    Dim colSub As New Collection

    Set fso = CreateObject("scripting.filesystemobject")
    colSub.Add startFolder

    Do While colSub.Count > 0
        Set fldr = fso.GetFolder(colSub(1))
        colSub.Remove 1

        For Each f In fldr.Files
            If UCase(f.Name) Like UCase(filePattern) Then colFiles.Add f
        Next f
        If subFolders Then
            For Each subFldr In fldr.subFolders
                colSub.Add subFldr.Path
            Next subFldr
        End If
    Loop
    Set GetFileMatches = colFiles
End Function

将此代码放在同一个文件夹中的XLSB或XLSM EXCEL文件中作为您的EXCEL文件。

使用Excel可能更容易做到这一点,我非常支持使用正确的工具。